[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.18

1.18    ! ratchov     1: /*     $OpenBSD: file.c,v 1.17 2010/04/03 17:59:17 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:  *
1.12      ratchov    24:  * the module also provides trivial timeout implementation,
                     25:  * derived from:
                     26:  *
                     27:  *     anoncvs@moule.caoua.org:/cvs/midish/timo.c rev 1.16
                     28:  *
                     29:  * A timeout is used to schedule the call of a routine (the callback)
                     30:  * there is a global list of timeouts that is processed inside the
                     31:  * event loop. Timeouts work as follows:
                     32:  *
                     33:  *     first the timo structure must be initialized with timo_set()
                     34:  *
                     35:  *     then the timeout is scheduled (only once) with timo_add()
                     36:  *
                     37:  *     if the timeout expires, the call-back is called; then it can
                     38:  *     be scheduled again if needed. It's OK to reschedule it again
                     39:  *     from the callback
                     40:  *
                     41:  *     the timeout can be aborted with timo_del(), it is OK to try to
                     42:  *     abort a timout that has expired
                     43:  *
1.1       ratchov    44:  */
1.12      ratchov    45:
1.1       ratchov    46: #include <sys/types.h>
                     47:
                     48: #include <err.h>
                     49: #include <errno.h>
                     50: #include <fcntl.h>
                     51: #include <poll.h>
                     52: #include <signal.h>
                     53: #include <stdio.h>
                     54: #include <stdlib.h>
                     55:
1.13      ratchov    56: #include "abuf.h"
                     57: #include "aproc.h"
1.1       ratchov    58: #include "conf.h"
                     59: #include "file.h"
1.15      ratchov    60: #ifdef DEBUG
                     61: #include "dbg.h"
                     62: #endif
1.1       ratchov    63:
                     64: #define MAXFDS 100
                     65:
1.12      ratchov    66: struct timeval file_tv;
1.1       ratchov    67: struct filelist file_list;
1.12      ratchov    68: struct timo *timo_queue;
                     69: unsigned timo_abstime;
                     70:
                     71: /*
                     72:  * initialise a timeout structure, arguments are callback and argument
                     73:  * that will be passed to the callback
                     74:  */
                     75: void
                     76: timo_set(struct timo *o, void (*cb)(void *), void *arg)
                     77: {
                     78:        o->cb = cb;
                     79:        o->arg = arg;
                     80:        o->set = 0;
                     81: }
                     82:
                     83: /*
                     84:  * schedule the callback in 'delta' 24-th of microseconds. The timeout
                     85:  * must not be already scheduled
                     86:  */
                     87: void
                     88: timo_add(struct timo *o, unsigned delta)
                     89: {
                     90:        struct timo **i;
                     91:        unsigned val;
                     92:        int diff;
                     93:
1.15      ratchov    94: #ifdef DEBUG
                     95:        if (o->set) {
                     96:                dbg_puts("timo_set: already set\n");
                     97:                dbg_panic();
                     98:        }
                     99:        if (delta == 0) {
                    100:                dbg_puts("timo_set: zero timeout is evil\n");
                    101:                dbg_panic();
                    102:        }
                    103: #endif
1.12      ratchov   104:        val = timo_abstime + delta;
                    105:        for (i = &timo_queue; *i != NULL; i = &(*i)->next) {
                    106:                diff = (*i)->val - val;
                    107:                if (diff > 0) {
                    108:                        break;
                    109:                }
                    110:        }
                    111:        o->set = 1;
                    112:        o->val = val;
                    113:        o->next = *i;
                    114:        *i = o;
                    115: }
                    116:
                    117: /*
                    118:  * abort a scheduled timeout
                    119:  */
                    120: void
                    121: timo_del(struct timo *o)
                    122: {
                    123:        struct timo **i;
                    124:
                    125:        for (i = &timo_queue; *i != NULL; i = &(*i)->next) {
                    126:                if (*i == o) {
                    127:                        *i = o->next;
                    128:                        o->set = 0;
                    129:                        return;
                    130:                }
                    131:        }
1.15      ratchov   132: #ifdef DEBUG
                    133:        if (debug_level >= 4)
                    134:                dbg_puts("timo_del: not found\n");
                    135: #endif
1.12      ratchov   136: }
                    137:
                    138: /*
                    139:  * routine to be called by the timer when 'delta' 24-th of microsecond
                    140:  * elapsed. This routine updates time referece used by timeouts and
                    141:  * calls expired timeouts
                    142:  */
                    143: void
                    144: timo_update(unsigned delta)
                    145: {
                    146:        struct timo *to;
                    147:        int diff;
                    148:
                    149:        /*
                    150:         * update time reference
                    151:         */
                    152:        timo_abstime += delta;
                    153:
                    154:        /*
                    155:         * remove from the queue and run expired timeouts
                    156:         */
                    157:        while (timo_queue != NULL) {
                    158:                /*
                    159:                 * there is no overflow here because + and - are
                    160:                 * modulo 2^32, they are the same for both signed and
                    161:                 * unsigned integers
                    162:                 */
                    163:                diff = timo_queue->val - timo_abstime;
                    164:                if (diff > 0)
                    165:                        break;
                    166:                to = timo_queue;
                    167:                timo_queue = to->next;
                    168:                to->set = 0;
                    169:                to->cb(to->arg);
                    170:        }
                    171: }
                    172:
                    173: /*
                    174:  * initialize timeout queue
                    175:  */
                    176: void
                    177: timo_init(void)
                    178: {
                    179:        timo_queue = NULL;
                    180:        timo_abstime = 0;
                    181: }
                    182:
                    183: /*
                    184:  * destroy timeout queue
                    185:  */
                    186: void
                    187: timo_done(void)
                    188: {
1.15      ratchov   189: #ifdef DEBUG
                    190:        if (timo_queue != NULL) {
                    191:                dbg_puts("timo_done: timo_queue not empty!\n");
                    192:                dbg_panic();
                    193:        }
                    194: #endif
1.12      ratchov   195:        timo_queue = (struct timo *)0xdeadbeef;
                    196: }
1.1       ratchov   197:
1.15      ratchov   198: #ifdef DEBUG
                    199: void
                    200: file_dbg(struct file *f)
                    201: {
                    202:        dbg_puts(f->ops->name);
                    203:        dbg_puts("(");
                    204:        dbg_puts(f->name);
                    205:        dbg_puts("|");
                    206:        if (f->state & FILE_ROK)
                    207:                dbg_puts("r");
                    208:        if (f->state & FILE_RINUSE)
                    209:                dbg_puts("R");
                    210:        if (f->state & FILE_WOK)
                    211:                dbg_puts("w");
                    212:        if (f->state & FILE_WINUSE)
                    213:                dbg_puts("W");
                    214:        if (f->state & FILE_EOF)
                    215:                dbg_puts("e");
                    216:        if (f->state & FILE_HUP)
                    217:                dbg_puts("h");
                    218:        if (f->state & FILE_ZOMB)
                    219:                dbg_puts("Z");
                    220:        dbg_puts(")");
                    221: }
                    222: #endif
1.3       ratchov   223:
1.1       ratchov   224: struct file *
1.4       ratchov   225: file_new(struct fileops *ops, char *name, unsigned nfds)
1.1       ratchov   226: {
                    227:        struct file *f;
                    228:
                    229:        LIST_FOREACH(f, &file_list, entry)
1.4       ratchov   230:                nfds += f->ops->nfds(f);
1.11      ratchov   231:        if (nfds > MAXFDS) {
1.15      ratchov   232: #ifdef DEBUG
                    233:                if (debug_level >= 1) {
                    234:                        dbg_puts(name);
                    235:                        dbg_puts(": too many polled files\n");
                    236:                }
                    237: #endif
1.11      ratchov   238:                return NULL;
                    239:        }
1.4       ratchov   240:        f = malloc(ops->size);
1.1       ratchov   241:        if (f == NULL)
1.4       ratchov   242:                err(1, "file_new: %s", ops->name);
                    243:        f->ops = ops;
1.1       ratchov   244:        f->name = name;
                    245:        f->state = 0;
                    246:        f->rproc = NULL;
                    247:        f->wproc = NULL;
                    248:        LIST_INSERT_HEAD(&file_list, f, entry);
1.15      ratchov   249: #ifdef DEBUG
                    250:        if (debug_level >= 3) {
                    251:                file_dbg(f);
                    252:                dbg_puts(": created\n");
                    253:        }
                    254: #endif
1.1       ratchov   255:        return f;
                    256: }
                    257:
                    258: void
                    259: file_del(struct file *f)
                    260: {
1.15      ratchov   261: #ifdef DEBUG
                    262:        if (debug_level >= 3) {
                    263:                file_dbg(f);
                    264:                dbg_puts(": terminating...\n");
                    265:        }
                    266: #endif
1.12      ratchov   267:        if (f->state & (FILE_RINUSE | FILE_WINUSE)) {
1.4       ratchov   268:                f->state |= FILE_ZOMB;
                    269:        } else {
                    270:                LIST_REMOVE(f, entry);
1.15      ratchov   271: #ifdef DEBUG
                    272:                if (debug_level >= 3) {
                    273:                        file_dbg(f);
                    274:                        dbg_puts(": destroyed\n");
                    275:                }
                    276: #endif
1.4       ratchov   277:                f->ops->close(f);
                    278:                free(f);
                    279:        }
1.1       ratchov   280: }
                    281:
                    282: int
                    283: file_poll(void)
                    284: {
1.4       ratchov   285:        nfds_t nfds, n;
                    286:        short events, revents;
1.1       ratchov   287:        struct pollfd pfds[MAXFDS];
                    288:        struct file *f, *fnext;
1.2       ratchov   289:        struct aproc *p;
1.12      ratchov   290:        struct timeval tv;
                    291:        long delta_usec;
                    292:        int timo;
1.1       ratchov   293:
1.4       ratchov   294:        /*
1.13      ratchov   295:         * Fill the pfds[] array with files that are blocked on reading
                    296:         * and/or writing, skipping those that are just waiting.
1.4       ratchov   297:         */
1.15      ratchov   298: #ifdef DEBUG
                    299:        dbg_flush();
                    300:        if (debug_level >= 4)
                    301:                dbg_puts("poll:");
                    302: #endif
1.1       ratchov   303:        nfds = 0;
                    304:        LIST_FOREACH(f, &file_list, entry) {
1.4       ratchov   305:                events = 0;
                    306:                if (f->rproc && !(f->state & FILE_ROK))
                    307:                        events |= POLLIN;
                    308:                if (f->wproc && !(f->state & FILE_WOK))
                    309:                        events |= POLLOUT;
1.15      ratchov   310: #ifdef DEBUG
                    311:                if (debug_level >= 4) {
                    312:                        dbg_puts(" ");
                    313:                        file_dbg(f);
                    314:                }
                    315: #endif
1.4       ratchov   316:                n = f->ops->pollfd(f, pfds + nfds, events);
                    317:                if (n == 0) {
1.1       ratchov   318:                        f->pfd = NULL;
                    319:                        continue;
                    320:                }
1.4       ratchov   321:                f->pfd = pfds + nfds;
                    322:                nfds += n;
1.1       ratchov   323:        }
1.15      ratchov   324: #ifdef DEBUG
                    325:        if (debug_level >= 4) {
                    326:                dbg_puts("\npfds[] =");
                    327:                for (n = 0; n < nfds; n++) {
                    328:                        dbg_puts(" ");
                    329:                        dbg_putx(pfds[n].events);
                    330:                }
                    331:                dbg_puts("\n");
                    332:        }
                    333: #endif
1.1       ratchov   334:        if (LIST_EMPTY(&file_list)) {
1.15      ratchov   335: #ifdef DEBUG
                    336:                if (debug_level >= 3)
                    337:                        dbg_puts("nothing to do...\n");
                    338: #endif
1.1       ratchov   339:                return 0;
                    340:        }
1.9       ratchov   341:        if (nfds > 0) {
1.12      ratchov   342:                if (timo_queue) {
                    343:                        timo = (timo_queue->val - timo_abstime) / (2 * 1000);
                    344:                        if (timo == 0)
                    345:                                timo = 1;
                    346:                } else
                    347:                        timo = -1;
                    348:                if (poll(pfds, nfds, timo) < 0) {
1.9       ratchov   349:                        if (errno == EINTR)
                    350:                                return 1;
                    351:                        err(1, "file_poll: poll failed");
                    352:                }
1.12      ratchov   353:                gettimeofday(&tv, NULL);
                    354:                delta_usec = 1000000L * (tv.tv_sec - file_tv.tv_sec);
                    355:                delta_usec += tv.tv_usec - file_tv.tv_usec;
                    356:                if (delta_usec > 0) {
                    357:                        file_tv = tv;
                    358:                        timo_update(delta_usec);
                    359:                }
1.1       ratchov   360:        }
1.4       ratchov   361:        f = LIST_FIRST(&file_list);
                    362:        while (f != LIST_END(&file_list)) {
                    363:                if (f->pfd == NULL) {
                    364:                        f = LIST_NEXT(f, entry);
1.1       ratchov   365:                        continue;
1.4       ratchov   366:                }
                    367:                revents = f->ops->revents(f, f->pfd);
                    368:                if (!(f->state & FILE_ZOMB) && (revents & POLLIN)) {
                    369:                        revents &= ~POLLIN;
1.15      ratchov   370: #ifdef DEBUG
                    371:                        if (debug_level >= 4) {
                    372:                                file_dbg(f);
                    373:                                dbg_puts(": rok\n");
                    374:                        }
                    375: #endif
1.1       ratchov   376:                        f->state |= FILE_ROK;
1.12      ratchov   377:                        f->state |= FILE_RINUSE;
1.4       ratchov   378:                        for (;;) {
1.2       ratchov   379:                                p = f->rproc;
1.14      ratchov   380:                                if (!p)
                    381:                                        break;
1.15      ratchov   382: #ifdef DEBUG
                    383:                                if (debug_level >= 4) {
                    384:                                        aproc_dbg(p);
                    385:                                        dbg_puts(": in\n");
                    386:                                }
                    387: #endif
1.14      ratchov   388:                                if (!p->ops->in(p, NULL))
1.1       ratchov   389:                                        break;
                    390:                        }
1.12      ratchov   391:                        f->state &= ~FILE_RINUSE;
1.1       ratchov   392:                }
1.4       ratchov   393:                if (!(f->state & FILE_ZOMB) && (revents & POLLOUT)) {
                    394:                        revents &= ~POLLOUT;
1.15      ratchov   395: #ifdef DEBUG
                    396:                        if (debug_level >= 4) {
                    397:                                file_dbg(f);
                    398:                                dbg_puts(": wok\n");
                    399:                        }
                    400: #endif
1.1       ratchov   401:                        f->state |= FILE_WOK;
1.12      ratchov   402:                        f->state |= FILE_WINUSE;
1.4       ratchov   403:                        for (;;) {
1.2       ratchov   404:                                p = f->wproc;
1.14      ratchov   405:                                if (!p)
                    406:                                        break;
1.15      ratchov   407: #ifdef DEBUG
                    408:                                if (debug_level >= 4) {
                    409:                                        aproc_dbg(p);
                    410:                                        dbg_puts(": out\n");
                    411:                                }
                    412: #endif
1.14      ratchov   413:                                if (!p->ops->out(p, NULL))
1.1       ratchov   414:                                        break;
                    415:                        }
1.12      ratchov   416:                        f->state &= ~FILE_WINUSE;
1.7       ratchov   417:                }
                    418:                if (!(f->state & FILE_ZOMB) && (revents & POLLHUP)) {
1.15      ratchov   419: #ifdef DEBUG
                    420:                        if (debug_level >= 3) {
                    421:                                file_dbg(f);
                    422:                                dbg_puts(": disconnected\n");
                    423:                        }
                    424: #endif
1.7       ratchov   425:                        f->state |= (FILE_EOF | FILE_HUP);
1.1       ratchov   426:                }
1.4       ratchov   427:                if (!(f->state & FILE_ZOMB) && (f->state & FILE_EOF)) {
1.15      ratchov   428: #ifdef DEBUG
                    429:                        if (debug_level >= 3) {
                    430:                                file_dbg(f);
                    431:                                dbg_puts(": eof\n");
                    432:                        }
                    433: #endif
1.2       ratchov   434:                        p = f->rproc;
1.12      ratchov   435:                        if (p) {
                    436:                                f->state |= FILE_RINUSE;
1.15      ratchov   437: #ifdef DEBUG
                    438:                                if (debug_level >= 3) {
                    439:                                        aproc_dbg(p);
                    440:                                        dbg_puts(": eof\n");
                    441:                                }
                    442: #endif
1.2       ratchov   443:                                p->ops->eof(p, NULL);
1.12      ratchov   444:                                f->state &= ~FILE_RINUSE;
                    445:                        }
1.1       ratchov   446:                        f->state &= ~FILE_EOF;
                    447:                }
1.4       ratchov   448:                if (!(f->state & FILE_ZOMB) && (f->state & FILE_HUP)) {
1.15      ratchov   449: #ifdef DEBUG
                    450:                        if (debug_level >= 3) {
                    451:                                file_dbg(f);
                    452:                                dbg_puts(": hup\n");
                    453:                        }
                    454: #endif
1.2       ratchov   455:                        p = f->wproc;
1.12      ratchov   456:                        if (p) {
                    457:                                f->state |= FILE_WINUSE;
1.15      ratchov   458: #ifdef DEBUG
                    459:                                if (debug_level >= 3) {
                    460:                                        aproc_dbg(p);
                    461:                                        dbg_puts(": hup\n");
                    462:                                }
                    463: #endif
1.2       ratchov   464:                                p->ops->hup(p, NULL);
1.12      ratchov   465:                                f->state &= ~FILE_WINUSE;
                    466:                        }
1.1       ratchov   467:                        f->state &= ~FILE_HUP;
                    468:                }
                    469:                fnext = LIST_NEXT(f, entry);
1.4       ratchov   470:                if (f->state & FILE_ZOMB)
1.3       ratchov   471:                        file_del(f);
1.4       ratchov   472:                f = fnext;
1.1       ratchov   473:        }
                    474:        if (LIST_EMPTY(&file_list)) {
1.15      ratchov   475: #ifdef DEBUG
                    476:                if (debug_level >= 3)
                    477:                        dbg_puts("no files anymore...\n");
                    478: #endif
1.1       ratchov   479:                return 0;
                    480:        }
                    481:        return 1;
                    482: }
                    483:
                    484: void
1.4       ratchov   485: filelist_init(void)
1.1       ratchov   486: {
                    487:        sigset_t set;
                    488:
                    489:        sigemptyset(&set);
                    490:        (void)sigaddset(&set, SIGPIPE);
                    491:        if (sigprocmask(SIG_BLOCK, &set, NULL))
                    492:                err(1, "sigprocmask");
                    493:        LIST_INIT(&file_list);
1.12      ratchov   494:        timo_init();
                    495:        gettimeofday(&file_tv, NULL);
1.15      ratchov   496: #ifdef DEBUG
                    497:        dbg_sync = 0;
                    498: #endif
1.1       ratchov   499: }
                    500:
                    501: void
1.4       ratchov   502: filelist_done(void)
1.1       ratchov   503: {
1.15      ratchov   504: #ifdef DEBUG
                    505:        struct file *f;
                    506:
                    507:        if (!LIST_EMPTY(&file_list)) {
                    508:                LIST_FOREACH(f, &file_list, entry) {
                    509:                        dbg_puts("\t");
                    510:                        file_dbg(f);
                    511:                        dbg_puts("\n");
                    512:                }
                    513:                dbg_panic();
                    514:        }
                    515:        dbg_sync = 1;
                    516:        dbg_flush();
                    517: #endif
1.12      ratchov   518:        timo_done();
1.1       ratchov   519: }
                    520:
1.4       ratchov   521: unsigned
1.14      ratchov   522: file_read(struct file *f, unsigned char *data, unsigned count)
1.4       ratchov   523: {
1.14      ratchov   524:        unsigned n;
1.15      ratchov   525: #ifdef DEBUG
                    526:        struct timeval tv0, tv1, dtv;
                    527:        unsigned us;
                    528:
                    529:        gettimeofday(&tv0, NULL);
                    530:        if (!(f->state & FILE_ROK)) {
                    531:                file_dbg(f);
                    532:                dbg_puts(": read: bad state\n");
                    533:                dbg_panic();
                    534:        }
                    535: #endif
1.14      ratchov   536:        n = f->ops->read(f, data, count);
1.15      ratchov   537: #ifdef DEBUG
                    538:        gettimeofday(&tv1, NULL);
                    539:        timersub(&tv1, &tv0, &dtv);
                    540:        us = dtv.tv_sec * 1000000 + dtv.tv_usec;
                    541:        if (debug_level >= 4 || (debug_level >= 1 && us >= 5000)) {
                    542:                dbg_puts(f->name);
                    543:                dbg_puts(": read ");
                    544:                dbg_putu(n);
                    545:                dbg_puts(" bytes in ");
                    546:                dbg_putu(us);
                    547:                dbg_puts("us\n");
                    548:        }
                    549: #endif
1.14      ratchov   550:        return n;
1.4       ratchov   551: }
1.1       ratchov   552:
                    553: unsigned
1.14      ratchov   554: file_write(struct file *f, unsigned char *data, unsigned count)
1.1       ratchov   555: {
1.14      ratchov   556:        unsigned n;
1.15      ratchov   557: #ifdef DEBUG
                    558:        struct timeval tv0, tv1, dtv;
                    559:        unsigned us;
                    560:
                    561:        if (!(f->state & FILE_WOK)) {
                    562:                file_dbg(f);
                    563:                dbg_puts(": write: bad state\n");
                    564:                dbg_panic();
                    565:        }
                    566:        gettimeofday(&tv0, NULL);
                    567: #endif
1.14      ratchov   568:        n = f->ops->write(f, data, count);
1.15      ratchov   569: #ifdef DEBUG
                    570:        gettimeofday(&tv1, NULL);
                    571:        timersub(&tv1, &tv0, &dtv);
                    572:        us = dtv.tv_sec * 1000000 + dtv.tv_usec;
                    573:        if (debug_level >= 4 || (debug_level >= 1 && us >= 5000)) {
                    574:                dbg_puts(f->name);
                    575:                dbg_puts(": wrote ");
                    576:                dbg_putu(n);
                    577:                dbg_puts(" bytes in ");
                    578:                dbg_putu(us);
                    579:                dbg_puts("us\n");
                    580:        }
                    581: #endif
1.14      ratchov   582:        return n;
1.1       ratchov   583: }
                    584:
                    585: void
                    586: file_eof(struct file *f)
                    587: {
1.4       ratchov   588:        struct aproc *p;
                    589:
1.15      ratchov   590: #ifdef DEBUG
                    591:        if (debug_level >= 3) {
                    592:                file_dbg(f);
                    593:                dbg_puts(": eof requested\n");
                    594:        }
                    595: #endif
1.12      ratchov   596:        if (!(f->state & (FILE_RINUSE | FILE_WINUSE))) {
1.4       ratchov   597:                p = f->rproc;
1.12      ratchov   598:                if (p) {
                    599:                        f->state |= FILE_RINUSE;
1.15      ratchov   600: #ifdef DEBUG
                    601:                        if (debug_level >= 3) {
                    602:                                aproc_dbg(p);
                    603:                                dbg_puts(": eof\n");
                    604:                        }
                    605: #endif
1.4       ratchov   606:                        p->ops->eof(p, NULL);
1.12      ratchov   607:                        f->state &= ~FILE_RINUSE;
                    608:                }
1.4       ratchov   609:                if (f->state & FILE_ZOMB)
                    610:                        file_del(f);
                    611:        } else {
                    612:                f->state &= ~FILE_ROK;
                    613:                f->state |= FILE_EOF;
                    614:        }
1.1       ratchov   615: }
                    616:
                    617: void
                    618: file_hup(struct file *f)
                    619: {
1.4       ratchov   620:        struct aproc *p;
                    621:
1.15      ratchov   622: #ifdef DEBUG
                    623:        if (debug_level >= 3) {
                    624:                file_dbg(f);
                    625:                dbg_puts(": hup requested\n");
                    626:        }
                    627: #endif
1.12      ratchov   628:        if (!(f->state & (FILE_RINUSE | FILE_WINUSE))) {
1.4       ratchov   629:                p = f->wproc;
1.12      ratchov   630:                if (p) {
                    631:                        f->state |= FILE_WINUSE;
1.15      ratchov   632: #ifdef DEBUG
                    633:                        if (debug_level >= 3) {
                    634:                                aproc_dbg(p);
                    635:                                dbg_puts(": hup\n");
                    636:                        }
                    637: #endif
1.4       ratchov   638:                        p->ops->hup(p, NULL);
1.12      ratchov   639:                        f->state &= ~FILE_WINUSE;
                    640:                }
1.4       ratchov   641:                if (f->state & FILE_ZOMB)
                    642:                        file_del(f);
                    643:        } else {
                    644:                f->state &= ~FILE_WOK;
                    645:                f->state |= FILE_HUP;
1.9       ratchov   646:        }
                    647: }
                    648:
                    649: void
                    650: file_close(struct file *f)
                    651: {
                    652:        struct aproc *p;
                    653:
1.15      ratchov   654: #ifdef DEBUG
                    655:        if (debug_level >= 3) {
                    656:                file_dbg(f);
                    657:                dbg_puts(": closing\n");
                    658:        }
                    659: #endif
1.18    ! ratchov   660:        if (f->wproc == NULL && f->rproc == NULL)
        !           661:                f->state |= FILE_ZOMB;
1.12      ratchov   662:        if (!(f->state & (FILE_RINUSE | FILE_WINUSE))) {
1.9       ratchov   663:                p = f->rproc;
1.12      ratchov   664:                if (p) {
                    665:                        f->state |= FILE_RINUSE;
1.15      ratchov   666: #ifdef DEBUG
                    667:                        if (debug_level >= 3) {
                    668:                                aproc_dbg(p);
                    669:                                dbg_puts(": eof\n");
                    670:                        }
                    671: #endif
1.9       ratchov   672:                        p->ops->eof(p, NULL);
1.12      ratchov   673:                        f->state &= ~FILE_RINUSE;
                    674:                }
1.9       ratchov   675:                p = f->wproc;
1.12      ratchov   676:                if (p) {
                    677:                        f->state |= FILE_WINUSE;
1.15      ratchov   678: #ifdef DEBUG
                    679:                        if (debug_level >= 3) {
                    680:                                aproc_dbg(p);
                    681:                                dbg_puts(": hup\n");
                    682:                        }
                    683: #endif
1.9       ratchov   684:                        p->ops->hup(p, NULL);
1.12      ratchov   685:                        f->state &= ~FILE_WINUSE;
                    686:                }
1.9       ratchov   687:                if (f->state & FILE_ZOMB)
                    688:                        file_del(f);
                    689:        } else {
                    690:                f->state &= ~(FILE_ROK | FILE_WOK);
                    691:                f->state |= (FILE_EOF | FILE_HUP);
1.4       ratchov   692:        }
1.1       ratchov   693: }