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

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