/* This file is in the public domain. */ #include #include #include "pollloop.h" #ifndef POLLRDNORM #define POLLRDNORM 0 #endif #ifndef POLLWRNORM #define POLLWRNORM 0 #endif #ifndef INFTIM #define INFTIM (-1) #endif typedef struct iofd IOFD; typedef struct blockfn BLOCKFN; struct iofd { int fd; int (*rtest)(void *); int (*wtest)(void *); void (*rd)(void *); void (*wr)(void *); 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)(void *); 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 struct pollfd *pfds; static int pfdn; static int pfdmax; static int justloop; void init_polling(void) { iofds = 0; niofds = 0; blockfns = 0; nblockfns = 0; cblockfns = 0; pfds = 0; pfdn = 0; pfdmax = 0; justloop = 0; } int add_poll_fd(int fd, int (*rtest)(void *), int (*wtest)(void *), void (*rd)(void *), void (*wr)(void *), 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 *), 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; 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)(io->arg) ? IOFF_WANT_R : 0) | ((*io->wtest)(io->arg) ? IOFF_WANT_W : 0); if (io->flags & (IOFF_WANT_R|IOFF_WANT_W)) { struct pollfd *pfd; if (pfdn >= pfdmax) pfds = realloc(pfds,(pfdmax=pfdn+8)*sizeof(*pfds)); io->px = pfdn++; pfd = &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; int us; int tmo; tmo = INFTIM; if (cblockfns) { int i; int c; BLOCKFN *bf; n = poll(pfds,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 ++; us = (*bf->fn)(bf->arg); if (us < 0) { switch (us) { case BLOCK_NIL: break; case BLOCK_LOOP: again = 1; break; default: abort(); break; } } else { if ((tmo == INFTIM) || (us < tmo)) tmo = us; } } if (c != cblockfns) abort(); if (again) { justloop = 1; return(0); } } return(poll(pfds,pfdn,tmo)); } 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) && (pfds[io->px].revents & (POLLIN|POLLRDNORM)) ) (*io->rd)(io->arg); if ( (io->flags & IOFF_WANT_W) && (pfds[io->px].revents & (POLLOUT|POLLWRNORM)) ) (*io->wr)(io->arg); } } int rwtest_always(void *arg __attribute__((__unused__))) { return(1); } int rwtest_never(void *arg __attribute__((__unused__))) { return(0); }