Annotation of src/usr.bin/aucat/file.c, Revision 1.2
1.2 ! ratchov 1: /* $OpenBSD: file.c,v 1.1 2008/05/23 07:15:46 ratchov Exp $ */
1.1 ratchov 2: /*
3: * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
8: *
9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16: */
17: /*
18: * non-blocking file i/o module: each file can be read or written (or
19: * both). To achieve non-blocking io, we simply use the poll() syscall
20: * in an event loop. If a read() or write() syscall return EAGAIN
21: * (operation will block), then the file is marked as "for polling", else
22: * the file is not polled again.
23: *
24: */
25: #include <sys/types.h>
26:
27: #include <err.h>
28: #include <errno.h>
29: #include <fcntl.h>
30: #include <poll.h>
31: #include <signal.h>
32: #include <stdio.h>
33: #include <stdlib.h>
34: #include <unistd.h>
35:
36: #include "conf.h"
37: #include "file.h"
38: #include "aproc.h"
39: #include "abuf.h"
40:
41: #define MAXFDS 100
42:
43: struct filelist file_list;
44:
45: struct file *
46: file_new(int fd, char *name)
47: {
48: unsigned i;
49: struct file *f;
50:
51: i = 0;
52: LIST_FOREACH(f, &file_list, entry)
53: i++;
54: if (i >= MAXFDS)
55: err(1, "%s: too many polled files", name);
56:
57: f = malloc(sizeof(struct file));
58: if (f == NULL)
59: err(1, "%s", name);
60:
61: f->fd = fd;
62: f->events = 0;
63: f->rbytes = -1;
64: f->wbytes = -1;
65: f->name = name;
66: f->state = 0;
67: f->rproc = NULL;
68: f->wproc = NULL;
69: LIST_INSERT_HEAD(&file_list, f, entry);
70: DPRINTF("file_new: %s\n", f->name);
71: return f;
72: }
73:
74: void
75: file_del(struct file *f)
76: {
77: DPRINTF("file_del: %s|%x\n", f->name, f->state);
78: }
79:
80: int
81: file_poll(void)
82: {
83: #ifdef DEBUG
84: int ndead;
85: #endif
86: nfds_t nfds;
87: struct pollfd pfds[MAXFDS];
88: struct pollfd *pfd;
89: struct file *f, *fnext;
1.2 ! ratchov 90: struct aproc *p;
1.1 ratchov 91:
92: nfds = 0;
93: #ifdef DEBUG
94: ndead = 0;
95: #endif
96: LIST_FOREACH(f, &file_list, entry) {
97: if (!f->events) {
98: #ifdef DEBUG
99: if (f->state & (FILE_EOF | FILE_HUP))
100: ndead++;
101: #endif
102: f->pfd = NULL;
103: continue;
104: }
105: pfd = &pfds[nfds++];
106: f->pfd = pfd;
107: pfd->fd = f->fd;
108: pfd->events = f->events;
109: }
110:
111: #ifdef DEBUG
112: if (debug_level >= 4) {
113: fprintf(stderr, "file_poll:");
114: LIST_FOREACH(f, &file_list, entry) {
115: fprintf(stderr, " %s(%x)", f->name, f->events);
116: }
117: fprintf(stderr, "\n");
118: }
119: if (nfds == 0 && ndead == 0 && !LIST_EMPTY(&file_list)) {
120: fprintf(stderr, "file_poll: deadlock\n");
121: abort();
122: }
123: #endif
124: if (LIST_EMPTY(&file_list)) {
125: DPRINTF("file_poll: nothing to do...\n");
126: return 0;
127: }
128: if (nfds) {
129: while (poll(pfds, nfds, -1) < 0) {
130: if (errno != EINTR)
131: err(1, "file_poll: poll failed");
132: }
133: }
134: LIST_FOREACH(f, &file_list, entry) {
135: pfd = f->pfd;
136: if (pfd == NULL)
137: continue;
138: if ((f->events & POLLIN) && (pfd->revents & POLLIN)) {
139: f->events &= ~POLLIN;
140: f->state |= FILE_ROK;
141: DPRINTFN(3, "file_poll: %s rok\n", f->name);
142: while (f->state & FILE_ROK) {
1.2 ! ratchov 143: p = f->rproc;
! 144: if (!p || !p->ops->in(p, NULL))
1.1 ratchov 145: break;
146: }
147: }
148: if ((f->events & POLLOUT) && (pfd->revents & POLLOUT)) {
149: f->events &= ~POLLOUT;
150: f->state |= FILE_WOK;
151: DPRINTFN(3, "file_poll: %s wok\n", f->name);
152: while (f->state & FILE_WOK) {
1.2 ! ratchov 153: p = f->wproc;
! 154: if (!p || !p->ops->out(p, NULL))
1.1 ratchov 155: break;
156: }
157: }
158: }
159: LIST_FOREACH(f, &file_list, entry) {
160: if (f->state & FILE_EOF) {
161: DPRINTFN(2, "file_poll: %s: eof\n", f->name);
1.2 ! ratchov 162: p = f->rproc;
! 163: if (p)
! 164: p->ops->eof(p, NULL);
1.1 ratchov 165: f->state &= ~FILE_EOF;
166: }
167: if (f->state & FILE_HUP) {
168: DPRINTFN(2, "file_poll: %s hup\n", f->name);
1.2 ! ratchov 169: p = f->wproc;
! 170: if (p)
! 171: p->ops->hup(p, NULL);
1.1 ratchov 172: f->state &= ~FILE_HUP;
173: }
174: }
175: for (f = LIST_FIRST(&file_list); f != NULL; f = fnext) {
176: fnext = LIST_NEXT(f, entry);
177: if (f->rproc == NULL && f->wproc == NULL) {
178: LIST_REMOVE(f, entry);
179: DPRINTF("file_poll: %s: deleted\n", f->name);
180: free(f);
181: }
182: }
183: if (LIST_EMPTY(&file_list)) {
184: DPRINTFN(2, "file_poll: terminated\n");
185: return 0;
186: }
187: return 1;
188: }
189:
190: void
191: file_start(void)
192: {
193: sigset_t set;
194:
195: sigemptyset(&set);
196: (void)sigaddset(&set, SIGPIPE);
197: if (sigprocmask(SIG_BLOCK, &set, NULL))
198: err(1, "sigprocmask");
199:
200: LIST_INIT(&file_list);
201: }
202:
203: void
204: file_stop(void)
205: {
206: struct file *f;
207:
208: if (!LIST_EMPTY(&file_list)) {
209: fprintf(stderr, "file_stop:");
210: LIST_FOREACH(f, &file_list, entry) {
211: fprintf(stderr, " %s(%x)", f->name, f->events);
212: }
213: fprintf(stderr, "\nfile_stop: list not empty\n");
214: exit(1);
215: }
216: }
217:
218: unsigned
219: file_read(struct file *file, unsigned char *data, unsigned count)
220: {
221: int n;
222:
223: if (file->rbytes >= 0 && count > file->rbytes) {
224: count = file->rbytes; /* file->rbytes fits in count */
225: if (count == 0) {
226: DPRINTFN(2, "file_read: %s: complete\n", file->name);
227: file->state &= ~FILE_ROK;
228: file->state |= FILE_EOF;
229: return 0;
230: }
231: }
232: while ((n = read(file->fd, data, count)) < 0) {
233: if (errno == EINTR)
234: continue;
235: file->state &= ~FILE_ROK;
236: if (errno == EAGAIN) {
237: DPRINTFN(3, "file_read: %s: blocking...\n",
238: file->name);
239: file->events |= POLLIN;
240: } else {
241: warn("%s", file->name);
242: file->state |= FILE_EOF;
243: }
244: return 0;
245: }
246: if (n == 0) {
247: DPRINTFN(2, "file_read: %s: eof\n", file->name);
248: file->state &= ~FILE_ROK;
249: file->state |= FILE_EOF;
250: return 0;
251: }
252: if (file->rbytes >= 0)
253: file->rbytes -= n;
254: DPRINTFN(4, "file_read: %s: got %d bytes\n", file->name, n);
255: return n;
256: }
257:
258:
259: unsigned
260: file_write(struct file *file, unsigned char *data, unsigned count)
261: {
262: int n;
263:
264: if (file->wbytes >= 0 && count > file->wbytes) {
265: count = file->wbytes; /* file->wbytes fits in count */
266: if (count == 0) {
267: DPRINTFN(2, "file_write: %s: complete\n", file->name);
268: file->state &= ~FILE_WOK;
269: file->state |= FILE_HUP;
270: return 0;
271: }
272: }
273: while ((n = write(file->fd, data, count)) < 0) {
274: if (errno == EINTR)
275: continue;
276: file->state &= ~FILE_WOK;
277: if (errno == EAGAIN) {
278: DPRINTFN(3, "file_write: %s: blocking...\n",
279: file->name);
280: file->events |= POLLOUT;
281: } else {
282: warn("%s", file->name);
283: file->state |= FILE_HUP;
284: }
285: return 0;
286: }
287: if (file->wbytes >= 0)
288: file->wbytes -= n;
289: DPRINTFN(4, "file_write: %s: wrote %d bytes\n", file->name, n);
290: return n;
291: }
292:
293: void
294: file_eof(struct file *f)
295: {
296: DPRINTFN(2, "file_eof: %s: scheduled for eof\n", f->name);
297: f->events &= ~POLLIN;
298: f->state &= ~FILE_ROK;
299: f->state |= FILE_EOF;
300: }
301:
302: void
303: file_hup(struct file *f)
304: {
305: DPRINTFN(2, "file_hup: %s: scheduled for hup\n", f->name);
306: f->events &= ~POLLOUT;
307: f->state &= ~FILE_WOK;
308: f->state |= FILE_HUP;
309: }