blob.c: Fix stale comment of stdin_command().
[paraslash.git] / stdout.c
1 /* Copyright (C) 2006 Andre Noll <maan@tuebingen.mpg.de>, see file COPYING. */
2
3 /** \file stdout.c Functions that deal with writing to stdout. */
4
5 #include "para.h"
6 #include "list.h"
7 #include "sched.h"
8 #include "fd.h"
9 #include "error.h"
10 #include "stdout.h"
11 #include "buffer_tree.h"
12
13 /* Add STDOUT_FILENO to the write fd set if there is input data available. */
14 static void stdout_pre_select(struct sched *s, void *context)
15 {
16 struct stdout_task *sot = context;
17 int ret;
18
19 ret = btr_node_status(sot->btrn, 0, BTR_NT_LEAF);
20 if (ret > 0)
21 para_fd_set(STDOUT_FILENO, &s->wfds, &s->max_fileno);
22 else if (ret < 0)
23 sched_min_delay(s);
24 }
25
26 /*
27 * This function writes input data from the buffer tree to stdout if
28 * STDOUT_FILENO is writable.
29 */
30 static int stdout_post_select(struct sched *s, void *context)
31 {
32 struct stdout_task *sot = context;
33 struct btr_node *btrn = sot->btrn;
34 int ret;
35 char *buf;
36 size_t sz;
37
38 ret = btr_node_status(btrn, 0, BTR_NT_LEAF);
39 if (ret < 0)
40 goto out;
41 if (ret == 0)
42 return 0;
43 if (!FD_ISSET(STDOUT_FILENO, &s->wfds))
44 return 0;
45
46 if (sot->must_set_nonblock_flag) {
47 ret = mark_fd_nonblocking(STDOUT_FILENO);
48 if (ret < 0)
49 goto out;
50 sot->must_set_nonblock_flag = false;
51 }
52 for (;;) {
53 sz = btr_next_buffer(btrn, &buf);
54 if (sz == 0)
55 break;
56 ret = xwrite(STDOUT_FILENO, buf, sz);
57 if (ret <= 0)
58 break;
59 btr_consume(btrn, ret);
60 }
61 out:
62 if (ret < 0) {
63 btr_remove_node(&sot->btrn);
64 /* Revert to blocking mode if necessary. */
65 fcntl(STDOUT_FILENO, F_SETFL, sot->fd_flags);
66 }
67 return ret;
68 }
69
70 /**
71 * Register a stdout task structure.
72 *
73 * \param sot The stdout task structure to register.
74 * \param s The task will be added to this scheduler's task list.
75 *
76 * This sets up \a sot and registers a task with \a sot as context pointer.
77 */
78 void stdout_task_register(struct stdout_task *sot, struct sched *s)
79 {
80 int ret;
81 struct task_info ti = {
82 .pre_select = stdout_pre_select,
83 .post_select = stdout_post_select,
84 .context = sot,
85 .name = "stdout",
86 };
87
88 /* See \ref stdin.c for details. */
89 ret = fcntl(STDOUT_FILENO, F_GETFL);
90 if (ret < 0) {
91 PARA_EMERG_LOG("F_GETFL: %s\n", strerror(errno));
92 exit(EXIT_FAILURE);
93 }
94 sot->fd_flags = ret;
95 sot->must_set_nonblock_flag = (sot->fd_flags & O_NONBLOCK) == 0
96 && !isatty(STDOUT_FILENO);
97 sot->task = task_register(&ti, s);
98 }