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