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