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

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