#include #include "taia.h" #include "select.h" #include "iopause.h" /** @file iopause.c @author djb @source qmail @brief stateful reading from net @return > 0 if successful */ int iopause(iopause_fd *x,unsigned int len,struct taia *deadline,struct taia *stamp) { struct taia t; int millisecs; double d; int i, r; if (taia_less(deadline,stamp)) millisecs = 0; else { t = *stamp; taia_sub(&t,deadline,&t); d = taia_approx(&t); if (d > 1000.0) d = 1000.0; millisecs = d * 1000.0 + 20.0; if (millisecs < 0) millisecs = 20.0; } for (i = 0; i < len; ++i) x[i].revents = 0; #ifdef IOPAUSE_POLL r = poll(x,len,millisecs); /* XXX: some kernels apparently need x[0] even if len is 0 */ /* XXX: how to handle EAGAIN? are kernels really this dumb? */ /* XXX: how to handle EINVAL? when exactly can this happen? */ #else struct timeval tv; fd_set rfds; fd_set wfds; int nfds; int fd; FD_ZERO(&rfds); FD_ZERO(&wfds); nfds = 1; for (i = 0; i < len; ++i) { fd = x[i].fd; if (fd < 0) continue; if (fd >= 8 * sizeof(fd_set)) continue; /*XXX*/ if (fd >= nfds) nfds = fd + 1; if (x[i].events & IOPAUSE_READ) FD_SET(fd,&rfds); if (x[i].events & IOPAUSE_WRITE) FD_SET(fd,&wfds); } tv.tv_sec = millisecs / 1000; tv.tv_usec = 1000 * (millisecs % 1000); r = select(nfds,&rfds,&wfds,(fd_set *) 0,&tv); if (r <= 0) return r; /* XXX: for EBADF, could seek out and destroy the bad descriptor */ for (i = 0; i < len; ++i) { fd = x[i].fd; if (fd < 0) continue; if (fd >= 8 * sizeof(fd_set)) continue; /*XXX*/ if (x[i].events & IOPAUSE_READ) if (FD_ISSET(fd,&rfds)) x[i].revents |= IOPAUSE_READ; if (x[i].events & IOPAUSE_WRITE) if (FD_ISSET(fd,&wfds)) x[i].revents |= IOPAUSE_WRITE; } #endif return r; }