version 1.14, 2009/09/27 11:51:20 |
version 1.15, 2010/01/10 21:47:41 |
|
|
#include "aproc.h" |
#include "aproc.h" |
#include "conf.h" |
#include "conf.h" |
#include "file.h" |
#include "file.h" |
|
#ifdef DEBUG |
|
#include "dbg.h" |
|
#endif |
|
|
#define MAXFDS 100 |
#define MAXFDS 100 |
|
|
|
|
unsigned val; |
unsigned val; |
int diff; |
int diff; |
|
|
|
#ifdef DEBUG |
|
if (o->set) { |
|
dbg_puts("timo_set: already set\n"); |
|
dbg_panic(); |
|
} |
|
if (delta == 0) { |
|
dbg_puts("timo_set: zero timeout is evil\n"); |
|
dbg_panic(); |
|
} |
|
#endif |
val = timo_abstime + delta; |
val = timo_abstime + delta; |
for (i = &timo_queue; *i != NULL; i = &(*i)->next) { |
for (i = &timo_queue; *i != NULL; i = &(*i)->next) { |
diff = (*i)->val - val; |
diff = (*i)->val - val; |
|
|
return; |
return; |
} |
} |
} |
} |
|
#ifdef DEBUG |
|
if (debug_level >= 4) |
|
dbg_puts("timo_del: not found\n"); |
|
#endif |
} |
} |
|
|
/* |
/* |
|
|
void |
void |
timo_done(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; |
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 * |
struct file * |
file_new(struct fileops *ops, char *name, unsigned nfds) |
file_new(struct fileops *ops, char *name, unsigned nfds) |
|
|
LIST_FOREACH(f, &file_list, entry) |
LIST_FOREACH(f, &file_list, entry) |
nfds += f->ops->nfds(f); |
nfds += f->ops->nfds(f); |
if (nfds > MAXFDS) { |
if (nfds > MAXFDS) { |
|
#ifdef DEBUG |
|
if (debug_level >= 1) { |
|
dbg_puts(name); |
|
dbg_puts(": too many polled files\n"); |
|
} |
|
#endif |
return NULL; |
return NULL; |
} |
} |
f = malloc(ops->size); |
f = malloc(ops->size); |
|
|
f->rproc = NULL; |
f->rproc = NULL; |
f->wproc = NULL; |
f->wproc = NULL; |
LIST_INSERT_HEAD(&file_list, f, entry); |
LIST_INSERT_HEAD(&file_list, f, entry); |
|
#ifdef DEBUG |
|
if (debug_level >= 3) { |
|
file_dbg(f); |
|
dbg_puts(": created\n"); |
|
} |
|
#endif |
return f; |
return f; |
} |
} |
|
|
void |
void |
file_del(struct file *f) |
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)) { |
if (f->state & (FILE_RINUSE | FILE_WINUSE)) { |
f->state |= FILE_ZOMB; |
f->state |= FILE_ZOMB; |
} else { |
} else { |
LIST_REMOVE(f, entry); |
LIST_REMOVE(f, entry); |
|
#ifdef DEBUG |
|
if (debug_level >= 3) { |
|
file_dbg(f); |
|
dbg_puts(": destroyed\n"); |
|
} |
|
#endif |
f->ops->close(f); |
f->ops->close(f); |
free(f); |
free(f); |
} |
} |
|
|
* Fill the pfds[] array with files that are blocked on reading |
* Fill the pfds[] array with files that are blocked on reading |
* and/or writing, skipping those that are just waiting. |
* and/or writing, skipping those that are just waiting. |
*/ |
*/ |
|
#ifdef DEBUG |
|
dbg_flush(); |
|
if (debug_level >= 4) |
|
dbg_puts("poll:"); |
|
#endif |
nfds = 0; |
nfds = 0; |
LIST_FOREACH(f, &file_list, entry) { |
LIST_FOREACH(f, &file_list, entry) { |
events = 0; |
events = 0; |
|
|
events |= POLLIN; |
events |= POLLIN; |
if (f->wproc && !(f->state & FILE_WOK)) |
if (f->wproc && !(f->state & FILE_WOK)) |
events |= POLLOUT; |
events |= POLLOUT; |
|
#ifdef DEBUG |
|
if (debug_level >= 4) { |
|
dbg_puts(" "); |
|
file_dbg(f); |
|
} |
|
#endif |
n = f->ops->pollfd(f, pfds + nfds, events); |
n = f->ops->pollfd(f, pfds + nfds, events); |
if (n == 0) { |
if (n == 0) { |
f->pfd = NULL; |
f->pfd = NULL; |
|
|
f->pfd = pfds + nfds; |
f->pfd = pfds + nfds; |
nfds += n; |
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 |
if (LIST_EMPTY(&file_list)) { |
if (LIST_EMPTY(&file_list)) { |
|
#ifdef DEBUG |
|
if (debug_level >= 3) |
|
dbg_puts("nothing to do...\n"); |
|
#endif |
return 0; |
return 0; |
} |
} |
if (nfds > 0) { |
if (nfds > 0) { |
|
|
revents = f->ops->revents(f, f->pfd); |
revents = f->ops->revents(f, f->pfd); |
if (!(f->state & FILE_ZOMB) && (revents & POLLIN)) { |
if (!(f->state & FILE_ZOMB) && (revents & POLLIN)) { |
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_ROK; |
f->state |= FILE_RINUSE; |
f->state |= FILE_RINUSE; |
for (;;) { |
for (;;) { |
p = f->rproc; |
p = f->rproc; |
if (!p) |
if (!p) |
break; |
break; |
|
#ifdef DEBUG |
|
if (debug_level >= 4) { |
|
aproc_dbg(p); |
|
dbg_puts(": in\n"); |
|
} |
|
#endif |
if (!p->ops->in(p, NULL)) |
if (!p->ops->in(p, NULL)) |
break; |
break; |
} |
} |
|
|
} |
} |
if (!(f->state & FILE_ZOMB) && (revents & POLLOUT)) { |
if (!(f->state & FILE_ZOMB) && (revents & POLLOUT)) { |
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_WOK; |
f->state |= FILE_WINUSE; |
f->state |= FILE_WINUSE; |
for (;;) { |
for (;;) { |
p = f->wproc; |
p = f->wproc; |
if (!p) |
if (!p) |
break; |
break; |
|
#ifdef DEBUG |
|
if (debug_level >= 4) { |
|
aproc_dbg(p); |
|
dbg_puts(": out\n"); |
|
} |
|
#endif |
if (!p->ops->out(p, NULL)) |
if (!p->ops->out(p, NULL)) |
break; |
break; |
} |
} |
f->state &= ~FILE_WINUSE; |
f->state &= ~FILE_WINUSE; |
} |
} |
if (!(f->state & FILE_ZOMB) && (revents & POLLHUP)) { |
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); |
f->state |= (FILE_EOF | FILE_HUP); |
} |
} |
if (!(f->state & FILE_ZOMB) && (f->state & FILE_EOF)) { |
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; |
p = f->rproc; |
if (p) { |
if (p) { |
f->state |= FILE_RINUSE; |
f->state |= FILE_RINUSE; |
|
#ifdef DEBUG |
|
if (debug_level >= 3) { |
|
aproc_dbg(p); |
|
dbg_puts(": eof\n"); |
|
} |
|
#endif |
p->ops->eof(p, NULL); |
p->ops->eof(p, NULL); |
f->state &= ~FILE_RINUSE; |
f->state &= ~FILE_RINUSE; |
} |
} |
f->state &= ~FILE_EOF; |
f->state &= ~FILE_EOF; |
} |
} |
if (!(f->state & FILE_ZOMB) && (f->state & FILE_HUP)) { |
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; |
p = f->wproc; |
if (p) { |
if (p) { |
f->state |= FILE_WINUSE; |
f->state |= FILE_WINUSE; |
|
#ifdef DEBUG |
|
if (debug_level >= 3) { |
|
aproc_dbg(p); |
|
dbg_puts(": hup\n"); |
|
} |
|
#endif |
p->ops->hup(p, NULL); |
p->ops->hup(p, NULL); |
f->state &= ~FILE_WINUSE; |
f->state &= ~FILE_WINUSE; |
} |
} |
|
|
f = fnext; |
f = fnext; |
} |
} |
if (LIST_EMPTY(&file_list)) { |
if (LIST_EMPTY(&file_list)) { |
|
#ifdef DEBUG |
|
if (debug_level >= 3) |
|
dbg_puts("no files anymore...\n"); |
|
#endif |
return 0; |
return 0; |
} |
} |
return 1; |
return 1; |
|
|
LIST_INIT(&file_list); |
LIST_INIT(&file_list); |
timo_init(); |
timo_init(); |
gettimeofday(&file_tv, NULL); |
gettimeofday(&file_tv, NULL); |
|
#ifdef DEBUG |
|
dbg_sync = 0; |
|
#endif |
} |
} |
|
|
void |
void |
filelist_done(void) |
filelist_done(void) |
{ |
{ |
|
#ifdef DEBUG |
|
struct file *f; |
|
|
|
if (!LIST_EMPTY(&file_list)) { |
|
LIST_FOREACH(f, &file_list, entry) { |
|
dbg_puts("\t"); |
|
file_dbg(f); |
|
dbg_puts("\n"); |
|
} |
|
dbg_panic(); |
|
} |
|
dbg_sync = 1; |
|
dbg_flush(); |
|
#endif |
timo_done(); |
timo_done(); |
} |
} |
|
|
|
|
file_read(struct file *f, unsigned char *data, unsigned count) |
file_read(struct file *f, unsigned char *data, unsigned count) |
{ |
{ |
unsigned n; |
unsigned n; |
|
#ifdef DEBUG |
|
struct timeval tv0, tv1, dtv; |
|
unsigned us; |
|
|
|
gettimeofday(&tv0, NULL); |
|
if (!(f->state & FILE_ROK)) { |
|
file_dbg(f); |
|
dbg_puts(": read: bad state\n"); |
|
dbg_panic(); |
|
} |
|
#endif |
n = f->ops->read(f, data, count); |
n = f->ops->read(f, data, count); |
|
#ifdef DEBUG |
|
gettimeofday(&tv1, NULL); |
|
timersub(&tv1, &tv0, &dtv); |
|
us = dtv.tv_sec * 1000000 + dtv.tv_usec; |
|
if (debug_level >= 4 || (debug_level >= 1 && 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; |
return n; |
} |
} |
|
|
|
|
file_write(struct file *f, unsigned char *data, unsigned count) |
file_write(struct file *f, unsigned char *data, unsigned count) |
{ |
{ |
unsigned n; |
unsigned n; |
|
#ifdef DEBUG |
|
struct timeval tv0, tv1, dtv; |
|
unsigned us; |
|
|
|
if (!(f->state & FILE_WOK)) { |
|
file_dbg(f); |
|
dbg_puts(": write: bad state\n"); |
|
dbg_panic(); |
|
} |
|
gettimeofday(&tv0, NULL); |
|
#endif |
n = f->ops->write(f, data, count); |
n = f->ops->write(f, data, count); |
|
#ifdef DEBUG |
|
gettimeofday(&tv1, NULL); |
|
timersub(&tv1, &tv0, &dtv); |
|
us = dtv.tv_sec * 1000000 + dtv.tv_usec; |
|
if (debug_level >= 4 || (debug_level >= 1 && 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; |
return n; |
} |
} |
|
|
|
|
{ |
{ |
struct aproc *p; |
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))) { |
if (!(f->state & (FILE_RINUSE | FILE_WINUSE))) { |
p = f->rproc; |
p = f->rproc; |
if (p) { |
if (p) { |
f->state |= FILE_RINUSE; |
f->state |= FILE_RINUSE; |
|
#ifdef DEBUG |
|
if (debug_level >= 3) { |
|
aproc_dbg(p); |
|
dbg_puts(": eof\n"); |
|
} |
|
#endif |
p->ops->eof(p, NULL); |
p->ops->eof(p, NULL); |
f->state &= ~FILE_RINUSE; |
f->state &= ~FILE_RINUSE; |
} |
} |
|
|
{ |
{ |
struct aproc *p; |
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))) { |
if (!(f->state & (FILE_RINUSE | FILE_WINUSE))) { |
p = f->wproc; |
p = f->wproc; |
if (p) { |
if (p) { |
f->state |= FILE_WINUSE; |
f->state |= FILE_WINUSE; |
|
#ifdef DEBUG |
|
if (debug_level >= 3) { |
|
aproc_dbg(p); |
|
dbg_puts(": hup\n"); |
|
} |
|
#endif |
p->ops->hup(p, NULL); |
p->ops->hup(p, NULL); |
f->state &= ~FILE_WINUSE; |
f->state &= ~FILE_WINUSE; |
} |
} |
|
|
{ |
{ |
struct aproc *p; |
struct aproc *p; |
|
|
|
#ifdef DEBUG |
|
if (debug_level >= 3) { |
|
file_dbg(f); |
|
dbg_puts(": closing\n"); |
|
} |
|
#endif |
if (!(f->state & (FILE_RINUSE | FILE_WINUSE))) { |
if (!(f->state & (FILE_RINUSE | FILE_WINUSE))) { |
p = f->rproc; |
p = f->rproc; |
if (p) { |
if (p) { |
f->state |= FILE_RINUSE; |
f->state |= FILE_RINUSE; |
|
#ifdef DEBUG |
|
if (debug_level >= 3) { |
|
aproc_dbg(p); |
|
dbg_puts(": eof\n"); |
|
} |
|
#endif |
p->ops->eof(p, NULL); |
p->ops->eof(p, NULL); |
f->state &= ~FILE_RINUSE; |
f->state &= ~FILE_RINUSE; |
} |
} |
p = f->wproc; |
p = f->wproc; |
if (p) { |
if (p) { |
f->state |= FILE_WINUSE; |
f->state |= FILE_WINUSE; |
|
#ifdef DEBUG |
|
if (debug_level >= 3) { |
|
aproc_dbg(p); |
|
dbg_puts(": hup\n"); |
|
} |
|
#endif |
p->ops->hup(p, NULL); |
p->ops->hup(p, NULL); |
f->state &= ~FILE_WINUSE; |
f->state &= ~FILE_WINUSE; |
} |
} |