[BACK]Return to file.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / aucat

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: }