X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/mLib/blobdiff_plain/1226c514d496f4552b43682c8ca3dde7d87f952a..0ae5e7b3fd62e0251d21f3abbc187f4c7585f85f:/sel.c diff --git a/sel.c b/sel.c index de8cdef..04d9ed5 100644 --- a/sel.c +++ b/sel.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: sel.c,v 1.4 1999/08/19 18:30:26 mdw Exp $ + * $Id: sel.c,v 1.8 2000/03/23 20:42:08 mdw Exp $ * * I/O multiplexing support * @@ -30,6 +30,18 @@ /*----- Revision history --------------------------------------------------* * * $Log: sel.c,v $ + * Revision 1.8 2000/03/23 20:42:08 mdw + * Rearrange timeout handling to avoid list corruptions. + * + * Revision 1.7 1999/12/11 11:12:17 mdw + * Fix comment formatting error. + * + * Revision 1.6 1999/09/26 14:28:11 mdw + * (sel_select): Almost pointless efficiency tweak. + * + * Revision 1.5 1999/08/31 17:42:22 mdw + * New function `sel_force' to force a descriptor to be `selected'. + * * Revision 1.4 1999/08/19 18:30:26 mdw * Implement hooks for foreign select-using systems (currently not well * tested). @@ -71,12 +83,15 @@ void sel_init(sel_state *s) { - s->files = 0; + int i; + + for (i = 0; i < SEL_MODES; i++) { + s->files[i] = 0; + FD_ZERO(&s->fd[i]); + } s->timers = 0; s->hooks = 0; - FD_ZERO(&s->fd[SEL_READ]); - FD_ZERO(&s->fd[SEL_WRITE]); - FD_ZERO(&s->fd[SEL_EXC]); + s->args = 0; } /* --- @sel_initfile@ --- * @@ -118,7 +133,7 @@ void sel_initfile(sel_state *s, sel_file *f, void sel_addfile(sel_file *f) { - sel_file **ff = &f->s->files; + sel_file **ff = &f->s->files[f->mode]; /* --- This little dance looks like line-noise, but it does the job --- */ @@ -132,6 +147,24 @@ void sel_addfile(sel_file *f) FD_SET(f->fd, f->s->fd + f->mode); } +/* --- @sel_force@ --- * + * + * Arguments: @sel_file *f@ = pointer to file selector + * + * Returns: --- + * + * Use: Forces a file selector to be considered ready. This is only + * useful during a call to @sel_select@. Of particular use is + * forcing a write selector when there's something interesting + * ready for it. + */ + +void sel_force(sel_file *f) +{ + if (f->s->args) + FD_SET(f->fd, &f->s->args->fd[f->mode]); +} + /* --- @sel_rmfile@ --- * * * Arguments: @sel_file *f@ = pointer to a file block @@ -245,7 +278,7 @@ void sel_rmhook(sel_hook *h) } /* --- @sel_fdmerge@ --- * - * + * * Arguments: @fd_set *dest@ = destination FD set * @fd_set *fd@ = pointer to set to merge * @int maxfd@ = highest numbered descriptor in @fd@ + 1 @@ -286,7 +319,15 @@ int sel_select(sel_state *s) /* --- Initialize the argument block --- */ - a.maxfd = s->files ? s->files->fd + 1 : 0; + { + int i; + a.maxfd = 0; + for (i = 0; i < SEL_MODES; i++) { + if (s->files[i] && s->files[i]->fd >= a.maxfd) + a.maxfd = s->files[i]->fd + 1; + } + } + memcpy(a.fd, s->fd, sizeof(a.fd)); if (s->timers || s->hooks) gettimeofday(&a.now, 0); @@ -296,6 +337,7 @@ int sel_select(sel_state *s) TV_SUB(&a.tv, &s->timers->tv, &a.now); a.tvp = &a.tv; } + s->args = &a; /* --- Grind through the pre hooks --- */ @@ -313,8 +355,10 @@ int sel_select(sel_state *s) if ((err = select(a.maxfd, &a.fd[SEL_READ], &a.fd[SEL_WRITE], &a.fd[SEL_EXC], - a.tvp)) < 0) + a.tvp)) < 0) { + s->args = 0; return (err); + } if (a.tvp) gettimeofday(&a.now, 0); @@ -333,29 +377,43 @@ int sel_select(sel_state *s) /* --- Run through the timers --- */ - { + if (s->timers && TV_CMP(&s->timers->tv, <=, &a.now)) { sel_timer *t, *tt; - for (t = s->timers; t && TV_CMP(&t->tv, <=, &a.now); t = tt) { + tt = s->timers; + for (t = tt; t && TV_CMP(&t->tv, <=, &a.now); t = t->next) + ; + if (t) { + t->prev->next = 0; + t->prev = (sel_timer *)&s->timers; + } + s->timers = t; + for (t = tt; t; t = tt) { tt = t->next; - t->next = t->prev = t; t->func(&a.now, t->p); } - s->timers = t; - if (t) - t->prev = (sel_timer *)&s->timers; } - /* --- And finally run through the files --- */ + /* --- And finally run through the files --- * + * + * Do reads first. It's quite possible that a read might prompt a write, + * but the other way around is less likely. Fortunately, the modes are + * in the right order for this. + */ { - sel_file *f, *ff; - for (f = s->files; f; f = ff) { - ff = f->next; - if (FD_ISSET(f->fd, a.fd + f->mode)) - f->func(f->fd, f->mode, f->p); + int i; + + for (i = 0; i < SEL_MODES; i++) { + sel_file *f, *ff; + for (f = s->files[i]; f; f = ff) { + ff = f->next; + if (FD_ISSET(f->fd, a.fd + i)) + f->func(f->fd, i, f->p); + } } } + s->args = 0; return (0); }