]> git.pond.sub.org Git - empserver/blob - src/lib/empthread/io.c
Generation numbers didn't catch all potential yields on output
[empserver] / src / lib / empthread / io.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2010, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                           Ken Stevens, Steve McClure
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  *  ---
21  *
22  *  See files README, COPYING and CREDITS in the root of the source
23  *  tree for related information and legal notices.  It is expected
24  *  that future projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  io.c: Arrange for input and output on a file descriptor to be queued.
29  *
30  *  Known contributors to this file:
31  *      Doug Hay, 1998
32  *      Steve McClure, 1998
33  *      Ron Koenderink, 2009
34  */
35
36 /*
37  * Arrange for input and output on a file descriptor
38  * to be queued.  Provide main loop -- a mechanism for
39  * blocking across all registered file descriptors, and
40  * reading or writing when appropriate.
41  */
42
43 #include <config.h>
44
45 #include <errno.h>
46 #include <fcntl.h>
47 #include <stdlib.h>
48 #include <sys/socket.h>
49 #include <sys/types.h>
50 #include <sys/uio.h>
51 #include <unistd.h>
52 #include "empio.h"
53 #include "empthread.h"
54 #include "file.h"
55 #include "ioqueue.h"
56 #include "misc.h"
57 #include "queue.h"
58
59 struct iop {
60     int fd;
61     struct ioqueue *input;
62     struct ioqueue *output;
63     int flags;
64     int bufsize;
65     int last_out;
66     struct timeval input_timeout;
67 };
68
69 void
70 io_init(void)
71 {
72 }
73
74 struct iop *
75 io_open(int fd, int flags, int bufsize, struct timeval timeout)
76 {
77     int fdfl;
78     struct iop *iop;
79
80     flags = flags & (IO_READ | IO_WRITE);
81     if ((flags & (IO_READ | IO_WRITE)) == 0)
82         return NULL;
83
84     fdfl = fcntl(fd, F_GETFL, 0);
85     if (fdfl < 0)
86         return NULL;
87     fdfl |= O_NONBLOCK;
88     if (fcntl(fd, F_SETFL, fdfl) < 0)
89         return NULL;
90
91     iop = malloc(sizeof(struct iop));
92     if (!iop)
93         return NULL;
94     iop->fd = fd;
95     iop->input = NULL;
96     iop->output = NULL;
97     iop->flags = flags;
98     iop->last_out = 0;
99     iop->bufsize = bufsize;
100     iop->input_timeout = timeout;
101     if (flags & IO_READ)
102         iop->input = ioq_create(bufsize);
103     if (flags & IO_WRITE)
104         iop->output = ioq_create(bufsize);
105     return iop;
106 }
107
108 void
109 io_close(struct iop *iop)
110 {
111
112     if (iop->input)
113         ioq_destroy(iop->input);
114     if (iop->output)
115         ioq_destroy(iop->output);
116     (void)close(iop->fd);
117     free(iop);
118 }
119
120 /*
121  * Return number of bytes read on success, zero on timeout, early
122  * wakeup or EOF, -1 on error, with errno set appropriately.  In
123  * particular, return -1 with errno set to EAGAIN or EWOULDBLOCK when
124  * no data is available for non-blocking input (WAITFORINPUT false).
125  * Use io_eof() to distinguish timeout and early wakeup from EOF.
126  */
127 int
128 io_input(struct iop *iop, int waitforinput)
129 {
130     char buf[IO_BUFSIZE];
131     int cc;
132     int res;
133
134     /* Not a read IOP */
135     if ((iop->flags & IO_READ) == 0) {
136         errno = EBADF;
137         return -1;
138     }
139     /* IOP is markes as in error. */
140     if (iop->flags & IO_ERROR) {
141         errno = EBADF;
142         return -1;
143     }
144     /* Wait for the file to have input. */
145     if (waitforinput) {
146         res = empth_select(iop->fd, EMPTH_FD_READ, &iop->input_timeout);
147         if (res < 0) {
148             iop->flags |= IO_ERROR;
149             return -1;
150         } else if (res == 0)
151             return 0;
152     }
153
154     /* Do the actual read. */
155     cc = read(iop->fd, buf, sizeof(buf));
156     if (cc < 0) {
157         if (errno != EAGAIN && errno != EWOULDBLOCK)
158             /* Some form of file error occurred... */
159             iop->flags |= IO_ERROR;
160         return -1;
161     }
162
163     /* We eof'd */
164     if (cc == 0) {
165         iop->flags |= IO_EOF;
166         return 0;
167     }
168
169     /* Append the input to the IOQ. */
170     ioq_append(iop->input, buf, cc);
171     return cc;
172 }
173
174 int
175 io_inputwaiting(struct iop *iop)
176 {
177     return ioq_qsize(iop->input);
178 }
179
180 int
181 io_outputwaiting(struct iop *iop)
182 {
183     return ioq_qsize(iop->output);
184 }
185
186 /*
187  * Write output queued in IOP.
188  * If WAIT, writing may put the thread to sleep.
189  * Return number of bytes written on success, -1 on error.
190  * In particular, return zero when nothing was written because the
191  * queue was empty, or because the write slept and got woken up (only
192  * if WAIT), or because the write refused to sleep (only if !WAIT).
193  */
194 int
195 io_output(struct iop *iop, int wait)
196 {
197     struct iovec iov[16];
198     int n, res, cc;
199
200     if (wait)
201         ef_make_stale();
202
203     if (!ioq_qsize(iop->output))
204         return 0;
205
206     if ((iop->flags & IO_WRITE) == 0)
207         return -1;
208
209     if (iop->flags & IO_ERROR)
210         return -1;
211
212     n = ioq_makeiov(iop->output, iov, IO_BUFSIZE);
213
214     if (wait) {
215         res = empth_select(iop->fd, EMPTH_FD_WRITE, NULL);
216         if (res == 0)
217             return 0;
218         if (res < 0) {
219             iop->flags |= IO_ERROR;
220             return -1;
221         }
222     }
223
224     cc = writev(iop->fd, iov, n);
225     if (cc < 0) {
226         if (errno == EAGAIN || errno == EWOULDBLOCK)
227             return 0;
228         iop->flags |= IO_ERROR;
229         return -1;
230     }
231
232     ioq_dequeue(iop->output, cc);
233     iop->last_out = ioq_qsize(iop->output);
234     return cc;
235 }
236
237 /*
238  * Write output queued in IOP if enough have been enqueued.
239  * Write if at least one buffer has been filled since the last write.
240  * If WAIT, writing may put the thread to sleep.
241  * Return number of bytes written on success, -1 on error.
242  * In particular, return zero when nothing was written because the
243  * queue was not long, or the write slept and got woken up (only if
244  * WAIT), or the write refused to sleep (only if !WAIT).
245  */
246 int
247 io_output_if_queue_long(struct iop *iop, int wait)
248 {
249     int len = ioq_qsize(iop->output);
250
251     if (CANT_HAPPEN(iop->last_out > len))
252         iop->last_out = 0;
253     if (len - iop->last_out < iop->bufsize) {
254         if (wait)
255             ef_make_stale();
256         return 0;
257     }
258     return io_output(iop, wait);
259 }
260
261
262 int
263 io_peek(struct iop *iop, char *buf, int nbytes)
264 {
265     if ((iop->flags & IO_READ) == 0)
266         return -1;
267     return ioq_peek(iop->input, buf, nbytes);
268 }
269
270 int
271 io_read(struct iop *iop, char *buf, int nbytes)
272 {
273     int cc;
274
275     if ((iop->flags & IO_READ) == 0)
276         return -1;
277     cc = ioq_peek(iop->input, buf, nbytes);
278     if (cc > 0)
279         ioq_dequeue(iop->input, cc);
280     return cc;
281 }
282
283 int
284 io_write(struct iop *iop, char *buf, int nbytes)
285 {
286     if ((iop->flags & IO_WRITE) == 0)
287         return -1;
288     ioq_append(iop->output, buf, nbytes);
289     return nbytes;
290 }
291
292 int
293 io_gets(struct iop *iop, char *buf, int nbytes)
294 {
295     if ((iop->flags & IO_READ) == 0)
296         return -1;
297     return ioq_gets(iop->input, buf, nbytes);
298 }
299
300 int
301 io_puts(struct iop *iop, char *buf)
302 {
303     if ((iop->flags & IO_WRITE) == 0)
304         return -1;
305     return ioq_puts(iop->output, buf);
306 }
307
308 int
309 io_shutdown(struct iop *iop, int flags)
310 {
311     flags &= (IO_READ | IO_WRITE);
312     if ((iop->flags & flags) != flags)
313         return -1;
314     if (flags & IO_READ) {
315         shutdown(iop->fd, 0);
316         ioq_drain(iop->input);
317     }
318     if (flags & IO_WRITE) {
319         shutdown(iop->fd, 1);
320         ioq_drain(iop->output);
321         iop->last_out = 0;
322     }
323     return 0;
324 }
325
326 int
327 io_error(struct iop *iop)
328 {
329     return iop->flags & IO_ERROR;
330 }
331
332 int
333 io_eof(struct iop *iop)
334 {
335     return iop->flags & IO_EOF;
336 }
337
338 int
339 io_fileno(struct iop *iop)
340 {
341     return iop->fd;
342 }