[btr] Add the node type parameter to btr_node_status().
[paraslash.git] / stdout.c
1 /*
2  * Copyright (C) 2006-2009 Andre Noll <maan@systemlinux.org>
3  *
4  * Licensed under the GPL v2. For licencing details see COPYING.
5  */
6
7 /** \file stdout.c Functions that deal with writing to stdout. */
8
9 #include <dirent.h> /* readdir() */
10 #include <assert.h>
11 #include <stdbool.h>
12
13 #include "para.h"
14 #include "list.h"
15 #include "sched.h"
16 #include "fd.h"
17 #include "error.h"
18 #include "stdout.h"
19 #include "buffer_tree.h"
20
21 /**
22  * The pre_select function of the stdout task.
23  *
24  * \param s The scheduler this task was registered to.
25  * \param t The task structure of the stdout task.
26  *
27  * This function is always successful. If there is data available in the input
28  * buffer, it adds \p STDOUT_FILENO to the write fd set of \a s.
29  */
30 static void stdout_pre_select(struct sched *s, struct task *t)
31 {
32         struct stdout_task *sot = container_of(t, struct stdout_task, task);
33
34         t->error = 0;
35         sot->check_fd = 0;
36         if (!*sot->loaded) {
37                 if (*sot->input_error < 0) {
38                         t->error = *sot->input_error;
39                         s->timeout.tv_sec = 0;
40                         s->timeout.tv_usec = 1;
41                 }
42                 return;
43         }
44         sot->check_fd = 1;
45         para_fd_set(STDOUT_FILENO, &s->wfds, &s->max_fileno);
46 }
47
48 static void stdout_pre_select_btr(struct sched *s, struct task *t)
49 {
50         struct stdout_task *sot = container_of(t, struct stdout_task, task);
51         int ret;
52
53         t->error = 0;
54         sot->check_fd = 0;
55         ret = btr_node_status(sot->btrn, 0, BTR_NT_LEAF);
56         if (ret > 0)
57                 para_fd_set(STDOUT_FILENO, &s->wfds, &s->max_fileno);
58         else if (ret < 0) {
59                 s->timeout.tv_sec = 0;
60                 s->timeout.tv_usec = 1;
61         }
62 }
63
64 /**
65  * The post select function of the stdout task.
66  *
67  * \param s The scheduler this task was registered to.
68  * \param t The task structure of the stdout task.
69  *
70  * This function checks if \p STDOUT_FILENO was included by in the write fd set
71  * of \a s during the previous pre_select call.  If yes, and \p STDOUT_FILENO
72  * appeears to be writable, the data loaded in the input buffer is written to
73  * stdout.
74  */
75 static void stdout_post_select(struct sched *s, struct task *t)
76 {
77         struct stdout_task *sot = container_of(t, struct stdout_task, task);
78         ssize_t ret;
79
80         t->error = 0;
81         if (!sot->check_fd) {
82                 if (!*sot->loaded && *sot->input_error < 0)
83                         t->error = *sot->input_error;
84                 return;
85         }
86         if (!FD_ISSET(STDOUT_FILENO, &s->wfds))
87                 return;
88         ret = write(STDOUT_FILENO, *sot->bufp, *sot->loaded);
89         if (ret < 0) {
90                 t->error = -ERRNO_TO_PARA_ERROR(errno);
91                 return;
92         }
93         *sot->loaded -= ret;
94         if (*sot->loaded)
95                 memmove(*sot->bufp, *sot->bufp + ret, *sot->loaded);
96 }
97
98 static void stdout_post_select_btr(struct sched *s, struct task *t)
99 {
100         struct stdout_task *sot = container_of(t, struct stdout_task, task);
101         struct btr_node *btrn = sot->btrn;
102         int ret;
103         char *buf;
104         size_t sz;
105
106         t->error = 0;
107         ret = btr_node_status(btrn, 0, BTR_NT_LEAF);
108         if (ret < 0)
109                 goto err;
110         if (ret == 0)
111                 return;
112         if (!FD_ISSET(STDOUT_FILENO, &s->wfds))
113                 return;
114         sz = btr_next_buffer(btrn, &buf);
115         assert(sz > 0);
116         ret = write_nonblock(STDOUT_FILENO, buf, sz, 0);
117         if (ret < 0)
118                 goto err;
119         btr_consume(btrn, ret);
120         return;
121 err:
122         btr_remove_node(btrn);
123         t->error = ret;
124 }
125 /**
126  * Initialize a stdout task structure with default values.
127  *
128  * \param sot The stdout task structure.
129  *
130  * This fills in the pre/post select function poinzters of the task structure
131  * given by \a sot.
132  */
133 void stdout_set_defaults(struct stdout_task *sot)
134 {
135         int ret;
136
137         if (sot->btrn) {
138                 sot->task.pre_select = stdout_pre_select_btr;
139                 sot->task.post_select = stdout_post_select_btr;
140         } else {
141                 sot->task.pre_select = stdout_pre_select;
142                 sot->task.post_select = stdout_post_select;
143         }
144         sprintf(sot->task.status, "stdout writer");
145         ret = mark_fd_nonblocking(STDOUT_FILENO);
146         if (ret >= 0)
147                 return;
148         PARA_EMERG_LOG("%s\n", para_strerror(-ret));
149         exit(EXIT_FAILURE);
150 }