From 1101f87ace7e0b3be886220d4faa13954fd35c6b Mon Sep 17 00:00:00 2001 Message-Id: <1101f87ace7e0b3be886220d4faa13954fd35c6b.1714381688.git.mdw@distorted.org.uk> From: Mark Wooding Date: Tue, 31 Aug 1999 17:42:23 +0000 Subject: [PATCH] New function `sel_force' to force a descriptor to be `selected'. Organization: Straylight/Edgeware From: mdw --- man/sel.3 | 23 ++++++++++++--- man/sel_force.3 | 1 + sel.c | 73 +++++++++++++++++++++++++++++++++++++--------- sel.h | 77 ++++++++++++++++++++++++++++++------------------- 4 files changed, 126 insertions(+), 48 deletions(-) create mode 100644 man/sel_force.3 diff --git a/man/sel.3 b/man/sel.3 index e1dd9ee..8af80f0 100644 --- a/man/sel.3 +++ b/man/sel.3 @@ -5,6 +5,7 @@ sel \- low level interface for waiting for I/O .\" @sel_init .\" @sel_initfile .\" @sel_addfile +.\" @sel_force .\" @sel_rmfile .\" @sel_addtimer .\" @sel_rmtimer @@ -23,6 +24,7 @@ sel \- low level interface for waiting for I/O .BI " void (*" func ")(int " fd ", unsigned " mode ", void *" p ), .BI " void *" p ); .BI "void sel_addfile(sel_file *" f ); +.BI "void sel_force(sel_file *" f ); .BI "void sel_rmfile(sel_file *" f ); .BI "void sel_addtimer(sel_state *" s ", sel_timer *" t , @@ -110,6 +112,7 @@ interface. For examples, see and .BR conn (3). .SH "PROGRAMMING INTERFACE" +.SS "Multiplexors" A multiplexor is represented using the type .B sel_state defined in the @@ -129,7 +132,7 @@ initialization, addition to multiplexor, and removal from a multiplexor. It's convenient to separate addition and removal from initialization because file selectors often get added and removed many times over during their lifetimes. -.PP +.SS "File selectors" A file selector is initialized by the .B sel_initfile function. This requires a large number of arguments: @@ -192,6 +195,16 @@ the file descriptor for the file, a mode argument which describes the file's new condition, and the pointer argument set up at initialization time. .PP +The function +.B sel_force +will sometimes be useful while a +.B sel_select +call (see below) is in progress. It marks a file selector as being +ready even if it's not really. This is most useful when dynamically +adding a write selector: it's likely that the write will succeed +immediately, so it's worth trying. This will only work properly if +the write is non-blocking. +.PP The member .B fd of the @@ -199,7 +212,7 @@ of the structure is exported. It contains the file descriptor in which the selector is interested. You may not modify this value, but it's useful to be able to read it out \- it saves having to keep a copy. -.PP +.SS "Timer selectors" Timer selectors are simpler. There are only two operations provided on timer selectors: addition and removal. Initialization is performed as part of the addition operation. @@ -250,7 +263,7 @@ Note that timer events are a one-shot thing. Once they've happened, the timer selector is removed and the event can't happen again. This is normally what you want. Removing a timer is only useful (or safe!) before the timer event has been sent. -.PP +.SS "Performing I/O" Finally, the function .B sel_select is passed a multiplexor object. It waits for something interesting to @@ -260,7 +273,7 @@ everything went according to plan, returns zero. Otherwise it returns -1, and the global variable .B errno is set appropriately. -.SH "SELECT HOOK FUNCTIONS" +.SS "Hook functions" In order to interface other I/O multiplexing systems to this one, it's possible to register .I hook @@ -373,6 +386,8 @@ though. .SH "SEE ALSO" .BR select (2), .BR poll (2), +.BR conn (3), +.BR selbuf (3), .BR mLib (3). .SH AUTHOR Mark Wooding, diff --git a/man/sel_force.3 b/man/sel_force.3 new file mode 100644 index 0000000..2c8967b --- /dev/null +++ b/man/sel_force.3 @@ -0,0 +1 @@ +.so man3/sel.3 diff --git a/sel.c b/sel.c index de8cdef..a9dd4cf 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.5 1999/08/31 17:42:22 mdw Exp $ * * I/O multiplexing support * @@ -30,6 +30,9 @@ /*----- Revision history --------------------------------------------------* * * $Log: sel.c,v $ + * 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 +74,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 +124,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 +138,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 @@ -286,7 +310,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 +328,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 +346,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); @@ -345,17 +380,27 @@ int sel_select(sel_state *s) 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 + f->mode)) + f->func(f->fd, f->mode, f->p); + } } } + s->args = 0; return (0); } diff --git a/sel.h b/sel.h index c2aa57f..391fe29 100644 --- a/sel.h +++ b/sel.h @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: sel.h,v 1.5 1999/08/19 18:30:26 mdw Exp $ + * $Id: sel.h,v 1.6 1999/08/31 17:42:22 mdw Exp $ * * I/O multiplexing support * @@ -30,6 +30,9 @@ /*----- Revision history --------------------------------------------------* * * $Log: sel.h,v $ + * Revision 1.6 1999/08/31 17:42:22 mdw + * New function `sel_force' to force a descriptor to be `selected'. + * * Revision 1.5 1999/08/19 18:30:26 mdw * Implement hooks for foreign select-using systems (currently not well * tested). @@ -107,49 +110,49 @@ */ enum { - SEL_READ, - SEL_WRITE, - SEL_EXC, - SEL_MODES + SEL_READ, /* File is ready to read */ + SEL_WRITE, /* File is ready to write */ + SEL_EXC, /* Something odd has happened */ + SEL_MODES /* Number of modes available */ }; typedef struct sel_state { - struct sel_file *files; - struct sel_timer *timers; - struct sel_hook *hooks; - fd_set fd[SEL_MODES]; - struct timeval tv; + struct sel_file *files[SEL_MODES]; /* Lists of interesting files */ + struct sel_timer *timers; /* List of timers */ + struct sel_hook *hooks; /* List of hook functions applied */ + fd_set fd[SEL_MODES]; /* Quick reference table for files */ + struct sel_args *args; /* Pointer to arguments */ } sel_state; /* --- Listening for a file --- */ typedef struct sel_file { - struct sel_file *next; - struct sel_file *prev; - struct sel_state *s; - int fd; - unsigned mode; - void (*func)(int /*fd*/, unsigned /*mode*/, void */*p*/); - void *p; + struct sel_file *next; /* Next file in the list */ + struct sel_file *prev; /* Previous file in the list */ + struct sel_state *s; /* Pointer to select multiplexor */ + int fd; /* File descriptor */ + unsigned mode; /* Interesting event for file */ + void (*func)(int /*fd*/, unsigned /*mode*/, void */*p*/); /* Handler */ + void *p; /* Argument for the handler */ } sel_file; /* --- Waiting for a timeout --- */ typedef struct sel_timer { - struct sel_timer *next; - struct sel_timer *prev; - struct timeval tv; - void (*func)(struct timeval */*tv*/, void */*p*/); - void *p; + struct sel_timer *next; /* Next timer in the list */ + struct sel_timer *prev; /* Previous timer in the list */ + struct timeval tv; /* Real time when timer should go */ + void (*func)(struct timeval */*tv*/, void */*p*/); /* Handler function */ + void *p; /* Argument for the handler */ } sel_timer; /* --- A select argument block --- */ typedef struct sel_args { - int maxfd; - fd_set fd[SEL_MODES]; - struct timeval tv, *tvp; - struct timeval now; + int maxfd; /* Highest-numbered file */ + fd_set fd[SEL_MODES]; /* Bit flags for all the files */ + struct timeval tv, *tvp; /* Time to return */ + struct timeval now; /* Current time */ } sel_args; /* --- A selector hook --- * @@ -162,10 +165,10 @@ typedef void (*sel_hookfn)(sel_state */*s*/, void */*p*/); typedef struct sel_hook { - struct sel_hook *next; - struct sel_hook *prev; - sel_hookfn before, after; - void *p; + struct sel_hook *next; /* Next hook in the list */ + struct sel_hook *prev; /* Previous hook in the list */ + sel_hookfn before, after; /* Hook functions */ + void *p; /* Argument for the hook functions */ } sel_hook; /*----- Functions provided ------------------------------------------------*/ @@ -226,6 +229,20 @@ extern void sel_addfile(sel_file */*f*/); extern void sel_rmfile(sel_file */*f*/); +/* --- @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. + */ + +extern void sel_force(sel_file */*f*/); + /* --- @sel_addtimer@ --- * * * Arguments: @sel_state *s@ = pointer to a state block -- [mdw]