/* This file is in the public domain. */ #include #include #include "pollloop.h" struct plctx { int timeout; struct pollfd *pfds; int pfdn; int pfdmax; } ; typedef struct iofd IOFD; typedef struct blockfn BLOCKFN; struct iofd { int fd; int (*rtest)(RWTESTFN_PROTO); int (*wtest)(RWTESTFN_PROTO); void (*rd)(RWFN_PROTO); void (*wr)(RWFN_PROTO); void *arg; unsigned int flags; #define IOFF_WANT_R 0x00000001 #define IOFF_WANT_W 0x00000002 #define IOFF_DEAD 0x00000004 int px; } ; struct blockfn { int (*fn)(BLOCKFN_PROTO); void *arg; unsigned int flags; #define BFF_DEAD 0x00000001 } ; static IOFD **iofds; static int niofds; static BLOCKFN **blockfns; static int nblockfns; static int cblockfns; static int justloop; static PLCTX ctx; void poll_init(void) { iofds = 0; niofds = 0; blockfns = 0; nblockfns = 0; cblockfns = 0; ctx.pfds = 0; ctx.pfdmax = 0; justloop = 0; } int add_poll_fd( int fd, int (*rtest)(RWTESTFN_PROTO), int (*wtest)(RWTESTFN_PROTO), void (*rd)(RWFN_PROTO), void (*wr)(RWFN_PROTO), void *arg ) { IOFD *io; int i; io = malloc(sizeof(IOFD)); do <"gotspace"> { for (i=0;i; iofds = realloc(iofds,sizeof(IOFD *)*++niofds); } while (0); iofds[i] = io; io->fd = fd; io->rtest = rtest; io->wtest = wtest; io->rd = rd; io->wr = wr; io->arg = arg; io->flags = 0; return(i); } int add_block_fn(int (*fn)(void *, PLCTX *), void *arg) { BLOCKFN *bf; int i; bf = malloc(sizeof(BLOCKFN)); do <"gotspace"> { for (i=0;i; blockfns = realloc(blockfns,sizeof(BLOCKFN *)*++nblockfns); } while (0); blockfns[i] = bf; bf->fn = fn; bf->arg = arg; bf->flags = 0; cblockfns ++; return(i); } void remove_poll_id(int id) { if ((id < 0) || (id >= niofds) || !iofds[id]) abort(); iofds[id]->flags |= IOFF_DEAD; } void remove_block_id(int id) { if ((id < 0) || (id >= nblockfns) || !blockfns[id]) abort(); blockfns[id]->flags |= BFF_DEAD; } void pre_poll(void) { int i; IOFD *io; ctx.timeout = INFTIM; ctx.pfdn = 0; for (i=0;iflags & IOFF_DEAD) { free(io); iofds[i] = 0; continue; } io->flags = (io->flags & ~(IOFF_WANT_R|IOFF_WANT_W)) | ((*io->rtest)(i,io->arg,&ctx) ? IOFF_WANT_R : 0) | ((*io->wtest)(i,io->arg,&ctx) ? IOFF_WANT_W : 0); if (io->flags & (IOFF_WANT_R|IOFF_WANT_W)) { struct pollfd *pfd; if (ctx.pfdn >= ctx.pfdmax) { ctx.pfds = realloc(ctx.pfds,(ctx.pfdmax=ctx.pfdn+8)*sizeof(*ctx.pfds)); } io->px = ctx.pfdn++; pfd = &ctx.pfds[io->px]; pfd->fd = io->fd; pfd->events = ((io->flags & IOFF_WANT_R) ? POLLIN|POLLRDNORM : 0) | ((io->flags & IOFF_WANT_W) ? POLLOUT|POLLWRNORM : 0); } else { io->px = -1; } } } int do_poll(void) { int n; int again; if (cblockfns) { int i; int c; BLOCKFN *bf; n = poll(ctx.pfds,ctx.pfdn,0); if (n != 0) return(n); c = 0; again = 0; for (i=0;iflags & BFF_DEAD) { free(bf); blockfns[i] = 0; cblockfns --; continue; } c ++; if ((*bf->fn)(bf->arg,&ctx)) again = 1; } if (again) { justloop = 1; return(0); } if (c != cblockfns) abort(); } return(poll(ctx.pfds,ctx.pfdn,ctx.timeout)); } void post_poll(void) { int i; IOFD *io; if (justloop) { justloop = 0; return; } for (i=0;iflags & IOFF_DEAD) continue; if ( (io->flags & IOFF_WANT_R) && (ctx.pfds[io->px].revents & (POLLIN|POLLRDNORM)) ) (*io->rd)(io->arg,i); if ( (io->flags & IOFF_WANT_W) && (ctx.pfds[io->px].revents & (POLLOUT|POLLWRNORM)) ) (*io->wr)(io->arg,i); } } int rwtest_always(RWTESTFN_ARGS) { return(1); } int rwtest_never(RWTESTFN_ARGS) { return(0); } void block_lower_timeout(PLCTX *ctx, int ms) { if (ms < 0) abort(); if ((ctx->timeout == INFTIM) || (ms < ctx->timeout)) ctx->timeout = ms; }