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