summaryrefslogtreecommitdiff
path: root/usr.bin/aucat/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/aucat/file.c')
-rw-r--r--usr.bin/aucat/file.c775
1 files changed, 0 insertions, 775 deletions
diff --git a/usr.bin/aucat/file.c b/usr.bin/aucat/file.c
deleted file mode 100644
index b2e6a7f1121..00000000000
--- a/usr.bin/aucat/file.c
+++ /dev/null
@@ -1,775 +0,0 @@
-/* $OpenBSD: file.c,v 1.31 2013/11/18 17:37:45 ratchov Exp $ */
-/*
- * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-/*
- * non-blocking file i/o module: each file can be read or written (or
- * both). To achieve non-blocking io, we simply use the poll() syscall
- * in an event loop. If a read() or write() syscall return EAGAIN
- * (operation will block), then the file is marked as "for polling", else
- * the file is not polled again.
- *
- * the module also provides trivial timeout implementation,
- * derived from:
- *
- * anoncvs@moule.caoua.org:/midish
- *
- * midish/timo.c rev 1.18
- * midish/mdep.c rev 1.71
- *
- * A timeout is used to schedule the call of a routine (the callback)
- * there is a global list of timeouts that is processed inside the
- * event loop. Timeouts work as follows:
- *
- * first the timo structure must be initialized with timo_set()
- *
- * then the timeout is scheduled (only once) with timo_add()
- *
- * if the timeout expires, the call-back is called; then it can
- * be scheduled again if needed. It's OK to reschedule it again
- * from the callback
- *
- * the timeout can be aborted with timo_del(), it is OK to try to
- * abort a timout that has expired
- *
- */
-
-#include <sys/time.h>
-#include <sys/types.h>
-
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <poll.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <time.h>
-
-#include "abuf.h"
-#include "aproc.h"
-#include "conf.h"
-#include "file.h"
-#ifdef DEBUG
-#include "dbg.h"
-#endif
-
-#define MAXFDS 100
-#define TIMER_USEC 10000
-
-void timo_update(unsigned int);
-void timo_init(void);
-void timo_done(void);
-void file_sigalrm(int);
-
-struct timespec file_ts;
-struct filelist file_list;
-struct timo *timo_queue;
-unsigned int timo_abstime;
-int file_slowaccept = 0;
-#ifdef DEBUG
-long long file_wtime, file_utime;
-#endif
-
-/*
- * initialise a timeout structure, arguments are callback and argument
- * that will be passed to the callback
- */
-void
-timo_set(struct timo *o, void (*cb)(void *), void *arg)
-{
- o->cb = cb;
- o->arg = arg;
- o->set = 0;
-}
-
-/*
- * schedule the callback in 'delta' 24-th of microseconds. The timeout
- * must not be already scheduled
- */
-void
-timo_add(struct timo *o, unsigned int delta)
-{
- struct timo **i;
- unsigned int val;
- int diff;
-
-#ifdef DEBUG
- if (o->set) {
- dbg_puts("timo_add: already set\n");
- dbg_panic();
- }
- if (delta == 0) {
- dbg_puts("timo_add: zero timeout is evil\n");
- dbg_panic();
- }
-#endif
- val = timo_abstime + delta;
- for (i = &timo_queue; *i != NULL; i = &(*i)->next) {
- diff = (*i)->val - val;
- if (diff > 0) {
- break;
- }
- }
- o->set = 1;
- o->val = val;
- o->next = *i;
- *i = o;
-}
-
-/*
- * abort a scheduled timeout
- */
-void
-timo_del(struct timo *o)
-{
- struct timo **i;
-
- for (i = &timo_queue; *i != NULL; i = &(*i)->next) {
- if (*i == o) {
- *i = o->next;
- o->set = 0;
- return;
- }
- }
-#ifdef DEBUG
- if (debug_level >= 4)
- dbg_puts("timo_del: not found\n");
-#endif
-}
-
-/*
- * routine to be called by the timer when 'delta' 24-th of microsecond
- * elapsed. This routine updates time referece used by timeouts and
- * calls expired timeouts
- */
-void
-timo_update(unsigned int delta)
-{
- struct timo *to;
- int diff;
-
- /*
- * update time reference
- */
- timo_abstime += delta;
-
- /*
- * remove from the queue and run expired timeouts
- */
- while (timo_queue != NULL) {
- /*
- * there is no overflow here because + and - are
- * modulo 2^32, they are the same for both signed and
- * unsigned integers
- */
- diff = timo_queue->val - timo_abstime;
- if (diff > 0)
- break;
- to = timo_queue;
- timo_queue = to->next;
- to->set = 0;
- to->cb(to->arg);
- }
-}
-
-/*
- * initialize timeout queue
- */
-void
-timo_init(void)
-{
- timo_queue = NULL;
- timo_abstime = 0;
-}
-
-/*
- * destroy timeout queue
- */
-void
-timo_done(void)
-{
-#ifdef DEBUG
- if (timo_queue != NULL) {
- dbg_puts("timo_done: timo_queue not empty!\n");
- dbg_panic();
- }
-#endif
- timo_queue = (struct timo *)0xdeadbeef;
-}
-
-#ifdef DEBUG
-void
-file_dbg(struct file *f)
-{
- dbg_puts(f->ops->name);
- dbg_puts("(");
- dbg_puts(f->name);
- dbg_puts("|");
- if (f->state & FILE_ROK)
- dbg_puts("r");
- if (f->state & FILE_RINUSE)
- dbg_puts("R");
- if (f->state & FILE_WOK)
- dbg_puts("w");
- if (f->state & FILE_WINUSE)
- dbg_puts("W");
- if (f->state & FILE_EOF)
- dbg_puts("e");
- if (f->state & FILE_HUP)
- dbg_puts("h");
- if (f->state & FILE_ZOMB)
- dbg_puts("Z");
- dbg_puts(")");
-}
-#endif
-
-struct file *
-file_new(struct fileops *ops, char *name, unsigned int nfds)
-{
- struct file *f;
-
- LIST_FOREACH(f, &file_list, entry)
- nfds += f->ops->nfds(f);
- if (nfds > MAXFDS) {
-#ifdef DEBUG
- if (debug_level >= 1) {
- dbg_puts(name);
- dbg_puts(": too many polled files\n");
- }
-#endif
- return NULL;
- }
- f = malloc(ops->size);
- if (f == NULL)
- err(1, "file_new: %s", ops->name);
- f->ops = ops;
- f->name = name;
- f->state = 0;
-#ifdef DEBUG
- f->cycles = 0;
-#endif
- f->rproc = NULL;
- f->wproc = NULL;
- LIST_INSERT_HEAD(&file_list, f, entry);
-#ifdef DEBUG
- if (debug_level >= 3) {
- file_dbg(f);
- dbg_puts(": created\n");
- }
-#endif
- return f;
-}
-
-void
-file_del(struct file *f)
-{
-#ifdef DEBUG
- if (debug_level >= 3) {
- file_dbg(f);
- dbg_puts(": terminating...\n");
- }
-#endif
- if (f->state & (FILE_RINUSE | FILE_WINUSE)) {
- f->state |= FILE_ZOMB;
- } else {
- LIST_REMOVE(f, entry);
-#ifdef DEBUG
- if (debug_level >= 3) {
- file_dbg(f);
- dbg_puts(": destroyed\n");
- }
-#endif
- f->ops->close(f);
- free(f);
- }
-}
-
-int
-file_poll(void)
-{
- nfds_t nfds, n;
- short events, revents;
- struct pollfd pfds[MAXFDS];
- struct file *f, *fnext;
- struct aproc *p;
- struct timespec ts;
-#ifdef DEBUG
- struct timespec sleepts;
-#endif
- long long delta_nsec;
- int res;
-
- if (LIST_EMPTY(&file_list) && timo_queue == NULL) {
-#ifdef DEBUG
- if (debug_level >= 3)
- dbg_puts("nothing to do...\n");
-#endif
- return 0;
- }
- /*
- * Fill the pfds[] array with files that are blocked on reading
- * and/or writing, skipping those that are just waiting.
- */
-#ifdef DEBUG
- dbg_flush();
- if (debug_level >= 4)
- dbg_puts("poll:");
-#endif
- nfds = 0;
- LIST_FOREACH(f, &file_list, entry) {
- events = 0;
- if (f->rproc && !(f->state & FILE_ROK))
- events |= POLLIN;
- if (f->wproc && !(f->state & FILE_WOK))
- events |= POLLOUT;
-#ifdef DEBUG
- if (debug_level >= 4) {
- dbg_puts(" ");
- file_dbg(f);
- }
-#endif
- n = f->ops->pollfd(f, pfds + nfds, events);
- if (n == 0) {
- f->pfd = NULL;
- continue;
- }
- f->pfd = pfds + nfds;
- nfds += n;
- }
-#ifdef DEBUG
- if (debug_level >= 4) {
- dbg_puts("\npfds[] =");
- for (n = 0; n < nfds; n++) {
- dbg_puts(" ");
- dbg_putx(pfds[n].events);
- }
- dbg_puts("\n");
- }
-#endif
-#ifdef DEBUG
- clock_gettime(CLOCK_MONOTONIC, &sleepts);
- file_utime += 1000000000LL * (sleepts.tv_sec - file_ts.tv_sec);
- file_utime += sleepts.tv_nsec - file_ts.tv_nsec;
-#endif
- res = poll(pfds, nfds, -1);
- if (res < 0 && errno != EINTR)
- err(1, "poll");
- clock_gettime(CLOCK_MONOTONIC, &ts);
-#ifdef DEBUG
- file_wtime += 1000000000LL * (ts.tv_sec - sleepts.tv_sec);
- file_wtime += ts.tv_nsec - sleepts.tv_nsec;
-#endif
- delta_nsec = 1000000000LL * (ts.tv_sec - file_ts.tv_sec);
- delta_nsec += ts.tv_nsec - file_ts.tv_nsec;
-#ifdef DEBUG
- if (delta_nsec < 0)
- dbg_puts("file_poll: negative time interval\n");
-#endif
- file_ts = ts;
- if (delta_nsec >= 0 && delta_nsec < 1000000000LL)
- timo_update(delta_nsec / 1000);
- else {
-#ifdef DEBUG
- if (debug_level >= 1)
- dbg_puts("ignored huge clock delta\n");
-#endif
- }
- if (res <= 0)
- return 1;
-
- f = LIST_FIRST(&file_list);
- while (f != NULL) {
- if (f->pfd == NULL) {
- f = LIST_NEXT(f, entry);
- continue;
- }
- revents = f->ops->revents(f, f->pfd);
-#ifdef DEBUG
- if (revents) {
- f->cycles++;
- if (f->cycles > FILE_MAXCYCLES) {
- file_dbg(f);
- dbg_puts(": busy loop, disconnecting\n");
- revents = POLLHUP;
- }
- }
-#endif
- if (!(f->state & FILE_ZOMB) && (revents & POLLIN)) {
- revents &= ~POLLIN;
-#ifdef DEBUG
- if (debug_level >= 4) {
- file_dbg(f);
- dbg_puts(": rok\n");
- }
-#endif
- f->state |= FILE_ROK;
- f->state |= FILE_RINUSE;
- for (;;) {
- p = f->rproc;
- if (!p)
- break;
-#ifdef DEBUG
- if (debug_level >= 4) {
- aproc_dbg(p);
- dbg_puts(": in\n");
- }
-#endif
- if (!p->ops->in(p, NULL))
- break;
- }
- f->state &= ~FILE_RINUSE;
- }
- if (!(f->state & FILE_ZOMB) && (revents & POLLOUT)) {
- revents &= ~POLLOUT;
-#ifdef DEBUG
- if (debug_level >= 4) {
- file_dbg(f);
- dbg_puts(": wok\n");
- }
-#endif
- f->state |= FILE_WOK;
- f->state |= FILE_WINUSE;
- for (;;) {
- p = f->wproc;
- if (!p)
- break;
-#ifdef DEBUG
- if (debug_level >= 4) {
- aproc_dbg(p);
- dbg_puts(": out\n");
- }
-#endif
- if (!p->ops->out(p, NULL))
- break;
- }
- f->state &= ~FILE_WINUSE;
- }
- if (!(f->state & FILE_ZOMB) && (revents & POLLHUP)) {
-#ifdef DEBUG
- if (debug_level >= 3) {
- file_dbg(f);
- dbg_puts(": disconnected\n");
- }
-#endif
- f->state |= (FILE_EOF | FILE_HUP);
- }
- if (!(f->state & FILE_ZOMB) && (f->state & FILE_EOF)) {
-#ifdef DEBUG
- if (debug_level >= 3) {
- file_dbg(f);
- dbg_puts(": eof\n");
- }
-#endif
- p = f->rproc;
- if (p) {
- f->state |= FILE_RINUSE;
-#ifdef DEBUG
- if (debug_level >= 3) {
- aproc_dbg(p);
- dbg_puts(": eof\n");
- }
-#endif
- p->ops->eof(p, NULL);
- f->state &= ~FILE_RINUSE;
- }
- f->state &= ~FILE_EOF;
- }
- if (!(f->state & FILE_ZOMB) && (f->state & FILE_HUP)) {
-#ifdef DEBUG
- if (debug_level >= 3) {
- file_dbg(f);
- dbg_puts(": hup\n");
- }
-#endif
- p = f->wproc;
- if (p) {
- f->state |= FILE_WINUSE;
-#ifdef DEBUG
- if (debug_level >= 3) {
- aproc_dbg(p);
- dbg_puts(": hup\n");
- }
-#endif
- p->ops->hup(p, NULL);
- f->state &= ~FILE_WINUSE;
- }
- f->state &= ~FILE_HUP;
- }
- fnext = LIST_NEXT(f, entry);
- if (f->state & FILE_ZOMB)
- file_del(f);
- f = fnext;
- }
- if (LIST_EMPTY(&file_list) && timo_queue == NULL) {
-#ifdef DEBUG
- if (debug_level >= 3)
- dbg_puts("no files anymore...\n");
-#endif
- return 0;
- }
- return 1;
-}
-
-/*
- * handler for SIGALRM, invoked periodically
- */
-void
-file_sigalrm(int i)
-{
- /* nothing to do, we only want poll() to return EINTR */
-}
-
-
-void
-filelist_init(void)
-{
- static struct sigaction sa;
- struct itimerval it;
- sigset_t set;
-
- sigemptyset(&set);
- (void)sigaddset(&set, SIGPIPE);
- if (sigprocmask(SIG_BLOCK, &set, NULL))
- err(1, "sigprocmask");
- LIST_INIT(&file_list);
- if (clock_gettime(CLOCK_MONOTONIC, &file_ts) < 0) {
- perror("clock_gettime");
- exit(1);
- }
- sa.sa_flags = SA_RESTART;
- sa.sa_handler = file_sigalrm;
- sigfillset(&sa.sa_mask);
- if (sigaction(SIGALRM, &sa, NULL) < 0) {
- perror("sigaction");
- exit(1);
- }
- it.it_interval.tv_sec = 0;
- it.it_interval.tv_usec = TIMER_USEC;
- it.it_value.tv_sec = 0;
- it.it_value.tv_usec = TIMER_USEC;
- if (setitimer(ITIMER_REAL, &it, NULL) < 0) {
- perror("setitimer");
- exit(1);
- }
- timo_init();
-#ifdef DEBUG
- dbg_sync = 0;
-#endif
-}
-
-void
-filelist_done(void)
-{
- struct itimerval it;
-#ifdef DEBUG
- struct file *f;
-
- if (!LIST_EMPTY(&file_list)) {
- LIST_FOREACH(f, &file_list, entry) {
- file_dbg(f);
- dbg_puts(" not closed\n");
- }
- dbg_panic();
- }
- dbg_sync = 1;
- dbg_flush();
-#endif
- timerclear(&it.it_value);
- timerclear(&it.it_interval);
- if (setitimer(ITIMER_REAL, &it, NULL) < 0) {
- perror("setitimer");
- exit(1);
- }
- timo_done();
-}
-
-unsigned int
-file_read(struct file *f, unsigned char *data, unsigned int count)
-{
- unsigned int n;
-#ifdef DEBUG
- struct timespec ts0, ts1;
- long us;
-
- if (!(f->state & FILE_ROK)) {
- file_dbg(f);
- dbg_puts(": read: bad state\n");
- dbg_panic();
- }
- clock_gettime(CLOCK_MONOTONIC, &ts0);
-#endif
- n = f->ops->read(f, data, count);
-#ifdef DEBUG
- if (n > 0)
- f->cycles = 0;
- clock_gettime(CLOCK_MONOTONIC, &ts1);
- us = 1000000L * (ts1.tv_sec - ts0.tv_sec);
- us += (ts1.tv_nsec - ts0.tv_nsec) / 1000;
- if (debug_level >= 4 || (debug_level >= 2 && us >= 5000)) {
- dbg_puts(f->name);
- dbg_puts(": read ");
- dbg_putu(n);
- dbg_puts(" bytes in ");
- dbg_putu(us);
- dbg_puts("us\n");
- }
-#endif
- return n;
-}
-
-unsigned int
-file_write(struct file *f, unsigned char *data, unsigned int count)
-{
- unsigned int n;
-#ifdef DEBUG
- struct timespec ts0, ts1;
- long us;
-
- if (!(f->state & FILE_WOK)) {
- file_dbg(f);
- dbg_puts(": write: bad state\n");
- dbg_panic();
- }
- clock_gettime(CLOCK_MONOTONIC, &ts0);
-#endif
- n = f->ops->write(f, data, count);
-#ifdef DEBUG
- if (n > 0)
- f->cycles = 0;
- clock_gettime(CLOCK_MONOTONIC, &ts1);
- us = 1000000L * (ts1.tv_sec - ts0.tv_sec);
- us += (ts1.tv_nsec - ts0.tv_nsec) / 1000;
- if (debug_level >= 4 || (debug_level >= 2 && us >= 5000)) {
- dbg_puts(f->name);
- dbg_puts(": wrote ");
- dbg_putu(n);
- dbg_puts(" bytes in ");
- dbg_putu(us);
- dbg_puts("us\n");
- }
-#endif
- return n;
-}
-
-void
-file_eof(struct file *f)
-{
- struct aproc *p;
-
-#ifdef DEBUG
- if (debug_level >= 3) {
- file_dbg(f);
- dbg_puts(": eof requested\n");
- }
-#endif
- if (!(f->state & (FILE_RINUSE | FILE_WINUSE))) {
- p = f->rproc;
- if (p) {
- f->state |= FILE_RINUSE;
-#ifdef DEBUG
- if (debug_level >= 3) {
- aproc_dbg(p);
- dbg_puts(": eof\n");
- }
-#endif
- p->ops->eof(p, NULL);
- f->state &= ~FILE_RINUSE;
- }
- if (f->state & FILE_ZOMB)
- file_del(f);
- } else {
- f->state &= ~FILE_ROK;
- f->state |= FILE_EOF;
- }
-}
-
-void
-file_hup(struct file *f)
-{
- struct aproc *p;
-
-#ifdef DEBUG
- if (debug_level >= 3) {
- file_dbg(f);
- dbg_puts(": hup requested\n");
- }
-#endif
- if (!(f->state & (FILE_RINUSE | FILE_WINUSE))) {
- p = f->wproc;
- if (p) {
- f->state |= FILE_WINUSE;
-#ifdef DEBUG
- if (debug_level >= 3) {
- aproc_dbg(p);
- dbg_puts(": hup\n");
- }
-#endif
- p->ops->hup(p, NULL);
- f->state &= ~FILE_WINUSE;
- }
- if (f->state & FILE_ZOMB)
- file_del(f);
- } else {
- f->state &= ~FILE_WOK;
- f->state |= FILE_HUP;
- }
-}
-
-void
-file_close(struct file *f)
-{
- struct aproc *p;
-
-#ifdef DEBUG
- if (debug_level >= 3) {
- file_dbg(f);
- dbg_puts(": closing\n");
- }
-#endif
- if (f->wproc == NULL && f->rproc == NULL)
- f->state |= FILE_ZOMB;
- if (!(f->state & (FILE_RINUSE | FILE_WINUSE))) {
- p = f->rproc;
- if (p) {
- f->state |= FILE_RINUSE;
-#ifdef DEBUG
- if (debug_level >= 3) {
- aproc_dbg(p);
- dbg_puts(": eof\n");
- }
-#endif
- p->ops->eof(p, NULL);
- f->state &= ~FILE_RINUSE;
- }
- p = f->wproc;
- if (p) {
- f->state |= FILE_WINUSE;
-#ifdef DEBUG
- if (debug_level >= 3) {
- aproc_dbg(p);
- dbg_puts(": hup\n");
- }
-#endif
- p->ops->hup(p, NULL);
- f->state &= ~FILE_WINUSE;
- }
- if (f->state & FILE_ZOMB)
- file_del(f);
- } else {
- f->state &= ~(FILE_ROK | FILE_WOK);
- f->state |= (FILE_EOF | FILE_HUP);
- }
-}