Annotation of src/usr.bin/aucat/file.c, Revision 1.7
1.7 ! ratchov 1: /* $OpenBSD: file.c,v 1.6 2008/11/16 17:08:32 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:
35: #include "conf.h"
36: #include "file.h"
37: #include "aproc.h"
38: #include "abuf.h"
39:
40: #define MAXFDS 100
41:
1.4 ratchov 42: extern struct fileops listen_ops, pipe_ops;
1.1 ratchov 43: struct filelist file_list;
44:
1.3 ratchov 45: void
46: file_dprint(int n, struct file *f)
47: {
1.6 ratchov 48: #ifdef DEBUG
1.4 ratchov 49: if (debug_level < n)
50: return;
51: fprintf(stderr, "%s:%s <", f->ops->name, f->name);
52: if (f->state & FILE_ROK)
53: fprintf(stderr, "ROK");
54: if (f->state & FILE_WOK)
55: fprintf(stderr, "WOK");
56: if (f->state & FILE_EOF)
57: fprintf(stderr, "EOF");
58: if (f->state & FILE_HUP)
59: fprintf(stderr, "HUP");
60: fprintf(stderr, ">");
1.6 ratchov 61: #endif
1.3 ratchov 62: }
63:
1.1 ratchov 64: struct file *
1.4 ratchov 65: file_new(struct fileops *ops, char *name, unsigned nfds)
1.1 ratchov 66: {
67: struct file *f;
68:
69: LIST_FOREACH(f, &file_list, entry)
1.4 ratchov 70: nfds += f->ops->nfds(f);
71: if (nfds > MAXFDS)
1.1 ratchov 72: err(1, "%s: too many polled files", name);
73:
1.4 ratchov 74: f = malloc(ops->size);
1.1 ratchov 75: if (f == NULL)
1.4 ratchov 76: err(1, "file_new: %s", ops->name);
77: f->ops = ops;
1.1 ratchov 78: f->name = name;
79: f->state = 0;
80: f->rproc = NULL;
81: f->wproc = NULL;
1.4 ratchov 82: f->refs = 0;
1.1 ratchov 83: LIST_INSERT_HEAD(&file_list, f, entry);
1.4 ratchov 84: DPRINTF("file_new: %s:%s\n", ops->name, f->name);
1.1 ratchov 85: return f;
86: }
87:
88: void
89: file_del(struct file *f)
90: {
1.3 ratchov 91: DPRINTF("file_del: ");
92: file_dprint(1, f);
1.4 ratchov 93: if (f->refs > 0) {
94: DPRINTF(": delayed\n");
95: f->state |= FILE_ZOMB;
96: return;
97: } else {
98: DPRINTF(": immediate\n");
99: LIST_REMOVE(f, entry);
100: f->ops->close(f);
101: free(f);
102: }
1.1 ratchov 103: }
104:
105: int
106: file_poll(void)
107: {
1.4 ratchov 108: nfds_t nfds, n;
109: short events, revents;
1.1 ratchov 110: struct pollfd pfds[MAXFDS];
111: struct file *f, *fnext;
1.2 ratchov 112: struct aproc *p;
1.5 ratchov 113: #ifdef DEBUG
114: unsigned nused;
115: #endif
1.1 ratchov 116:
1.4 ratchov 117: /*
118: * fill the pfds[] array with files that are blocked on reading
119: * and/or writing, skipping those that're just waiting
120: */
121: DPRINTFN(4, "file_poll:");
1.1 ratchov 122: nfds = 0;
1.5 ratchov 123: #ifdef DEBUG
124: nused = 0;
125: #endif
1.1 ratchov 126: LIST_FOREACH(f, &file_list, entry) {
1.4 ratchov 127: events = 0;
128: if (f->rproc && !(f->state & FILE_ROK))
129: events |= POLLIN;
130: if (f->wproc && !(f->state & FILE_WOK))
131: events |= POLLOUT;
1.5 ratchov 132: #ifdef DEBUG
133: if (events)
134: nused++;
135: #endif
1.4 ratchov 136: DPRINTFN(4, " %s(%x)", f->name, events);
137: n = f->ops->pollfd(f, pfds + nfds, events);
138: if (n == 0) {
1.1 ratchov 139: f->pfd = NULL;
140: continue;
141: }
1.4 ratchov 142: f->pfd = pfds + nfds;
143: nfds += n;
1.1 ratchov 144: }
1.4 ratchov 145: DPRINTFN(4, "\n");
1.1 ratchov 146:
147: #ifdef DEBUG
1.5 ratchov 148: if (nused == 0 && !LIST_EMPTY(&file_list)) {
1.1 ratchov 149: fprintf(stderr, "file_poll: deadlock\n");
150: abort();
151: }
152: #endif
153: if (LIST_EMPTY(&file_list)) {
154: DPRINTF("file_poll: nothing to do...\n");
155: return 0;
156: }
1.4 ratchov 157: if (poll(pfds, nfds, -1) < 0) {
158: if (errno == EINTR)
159: return 1;
160: err(1, "file_poll: poll failed");
1.1 ratchov 161: }
1.4 ratchov 162: f = LIST_FIRST(&file_list);
163: while (f != LIST_END(&file_list)) {
164: if (f->pfd == NULL) {
165: f = LIST_NEXT(f, entry);
1.1 ratchov 166: continue;
1.4 ratchov 167: }
168: f->refs++;
169: revents = f->ops->revents(f, f->pfd);
170: if (!(f->state & FILE_ZOMB) && (revents & POLLIN)) {
171: revents &= ~POLLIN;
1.1 ratchov 172: f->state |= FILE_ROK;
173: DPRINTFN(3, "file_poll: %s rok\n", f->name);
1.4 ratchov 174: for (;;) {
1.2 ratchov 175: p = f->rproc;
176: if (!p || !p->ops->in(p, NULL))
1.1 ratchov 177: break;
178: }
179: }
1.4 ratchov 180: if (!(f->state & FILE_ZOMB) && (revents & POLLOUT)) {
181: revents &= ~POLLOUT;
1.1 ratchov 182: f->state |= FILE_WOK;
183: DPRINTFN(3, "file_poll: %s wok\n", f->name);
1.4 ratchov 184: for (;;) {
1.2 ratchov 185: p = f->wproc;
186: if (!p || !p->ops->out(p, NULL))
1.1 ratchov 187: break;
188: }
1.7 ! ratchov 189: }
! 190: if (!(f->state & FILE_ZOMB) && (revents & POLLHUP)) {
! 191: DPRINTFN(2, "file_poll: %s: disconnected\n", f->name);
! 192: f->state |= (FILE_EOF | FILE_HUP);
1.1 ratchov 193: }
1.4 ratchov 194: if (!(f->state & FILE_ZOMB) && (f->state & FILE_EOF)) {
1.1 ratchov 195: DPRINTFN(2, "file_poll: %s: eof\n", f->name);
1.2 ratchov 196: p = f->rproc;
197: if (p)
198: p->ops->eof(p, NULL);
1.1 ratchov 199: f->state &= ~FILE_EOF;
200: }
1.4 ratchov 201: if (!(f->state & FILE_ZOMB) && (f->state & FILE_HUP)) {
1.1 ratchov 202: DPRINTFN(2, "file_poll: %s hup\n", f->name);
1.2 ratchov 203: p = f->wproc;
204: if (p)
205: p->ops->hup(p, NULL);
1.1 ratchov 206: f->state &= ~FILE_HUP;
207: }
1.4 ratchov 208: f->refs--;
1.1 ratchov 209: fnext = LIST_NEXT(f, entry);
1.4 ratchov 210: if (f->state & FILE_ZOMB)
1.3 ratchov 211: file_del(f);
1.4 ratchov 212: f = fnext;
1.1 ratchov 213: }
214: if (LIST_EMPTY(&file_list)) {
215: DPRINTFN(2, "file_poll: terminated\n");
216: return 0;
217: }
218: return 1;
219: }
220:
221: void
1.4 ratchov 222: filelist_init(void)
1.1 ratchov 223: {
224: sigset_t set;
225:
226: sigemptyset(&set);
227: (void)sigaddset(&set, SIGPIPE);
228: if (sigprocmask(SIG_BLOCK, &set, NULL))
229: err(1, "sigprocmask");
230:
231: LIST_INIT(&file_list);
232: }
233:
234: void
1.4 ratchov 235: filelist_done(void)
1.1 ratchov 236: {
237: struct file *f;
238:
239: if (!LIST_EMPTY(&file_list)) {
1.4 ratchov 240: fprintf(stderr, "filelist_done: list not empty:\n");
1.1 ratchov 241: LIST_FOREACH(f, &file_list, entry) {
1.4 ratchov 242: fprintf(stderr, "\t");
243: file_dprint(0, f);
244: fprintf(stderr, "\n");
1.1 ratchov 245: }
1.4 ratchov 246: abort();
1.1 ratchov 247: }
248: }
249:
1.4 ratchov 250: /*
251: * close all listening sockets
252: *
253: * XXX: remove this
254: */
255: void
256: filelist_unlisten(void)
1.1 ratchov 257: {
1.4 ratchov 258: struct file *f, *fnext;
1.1 ratchov 259:
1.4 ratchov 260: for (f = LIST_FIRST(&file_list); f != NULL; f = fnext) {
261: fnext = LIST_NEXT(f, entry);
262: if (f->ops == &listen_ops)
263: file_del(f);
1.1 ratchov 264: }
265: }
266:
1.4 ratchov 267: unsigned
268: file_read(struct file *file, unsigned char *data, unsigned count)
269: {
270: return file->ops->read(file, data, count);
271: }
1.1 ratchov 272:
273: unsigned
274: file_write(struct file *file, unsigned char *data, unsigned count)
275: {
1.4 ratchov 276: return file->ops->write(file, data, count);
1.1 ratchov 277: }
278:
279: void
280: file_eof(struct file *f)
281: {
1.4 ratchov 282: struct aproc *p;
283:
284: if (f->refs == 0) {
285: DPRINTFN(2, "file_eof: %s: immediate\n", f->name);
286: f->refs++;
287: p = f->rproc;
288: if (p)
289: p->ops->eof(p, NULL);
290: f->refs--;
291: if (f->state & FILE_ZOMB)
292: file_del(f);
293: } else {
294: DPRINTFN(2, "file_eof: %s: delayed\n", f->name);
295: f->state &= ~FILE_ROK;
296: f->state |= FILE_EOF;
297: }
1.1 ratchov 298: }
299:
300: void
301: file_hup(struct file *f)
302: {
1.4 ratchov 303: struct aproc *p;
304:
305: if (f->refs == 0) {
306: DPRINTFN(2, "file_hup: %s immediate\n", f->name);
307: f->refs++;
308: p = f->wproc;
309: if (p)
310: p->ops->hup(p, NULL);
311: f->refs--;
312: if (f->state & FILE_ZOMB)
313: file_del(f);
314: } else {
315: DPRINTFN(2, "file_hup: %s: delayed\n", f->name);
316: f->state &= ~FILE_WOK;
317: f->state |= FILE_HUP;
318: }
1.1 ratchov 319: }