/******************************************************************************* * BPoll.cpp File poll class * T.Barnaby, BEAM Ltd, 1/4/05 * updated by D.Korchagin, CERN AB-BI-SW, 2007-08-31 ******************************************************************************* */ #include #include #include #include #ifndef __Lynx__ #else #include /* Few defines for LynxOS portability NMN */ #define howmany(x,y) (((x)+((y)-1))/(y)) #define nfds_t unsigned long int #define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) #define bzero(b,len) (memset((b), '\0', (len)), (void) 0) int poll(struct pollfd *fds, nfds_t nfds, int timeout) { static int max_fd_size; struct timeval tv; fd_set *rset, *wset, *xset; struct pollfd *f; int ready; int maxfd = 0; int bytes; if (!max_fd_size) max_fd_size = getdtablesize (); bytes = howmany (max_fd_size, NFDBITS); rset = (fd_set *) alloca (bytes); wset = (fd_set *) alloca (bytes); xset = (fd_set *) alloca (bytes); /* We can't call FD_ZERO, since FD_ZERO only works with sets of exactly FD_SETSIZE size. */ bzero (rset, bytes); bzero (wset, bytes); bzero (xset, bytes); for (f = fds; f < &fds[nfds]; ++f) { f->revents = 0; if (f->fd >= 0) { if (f->fd >= max_fd_size) { /* The user provides a file descriptor number which is higher than the maximum we got from the `getdtablesize' call. Maybe this is ok so enlarge the arrays. */ fd_set *nrset, *nwset, *nxset; int nbytes; max_fd_size = roundup (f->fd, NFDBITS); nbytes = howmany (max_fd_size, NFDBITS); nrset = (fd_set *) alloca (nbytes); nwset = (fd_set *) alloca (nbytes); nxset = (fd_set *) alloca (nbytes); bzero ((char *) nrset + bytes, nbytes - bytes); bzero ((char *) nwset + bytes, nbytes - bytes); bzero ((char *) nxset + bytes, nbytes - bytes); rset = (fd_set *) memcpy (nrset, rset, bytes); wset = (fd_set *) memcpy (nwset, wset, bytes); xset = (fd_set *) memcpy (nxset, xset, bytes); bytes = nbytes; } if (f->events & POLLIN) FD_SET (f->fd, rset); if (f->events & POLLOUT) FD_SET (f->fd, wset); if (f->events & POLLPRI) FD_SET (f->fd, xset); if (f->fd > maxfd && (f->events & (POLLIN|POLLOUT|POLLPRI))) maxfd = f->fd; } } tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; while (true) { ready = select (maxfd + 1, rset, wset, xset, timeout == -1 ? NULL : &tv); /* It might be that one or more of the file descriptors is invalid. We now try to find and mark them and then try again. */ if (ready == -1 && errno == EBADF) { fd_set *sngl_rset = (fd_set *) alloca (bytes); fd_set *sngl_wset = (fd_set *) alloca (bytes); fd_set *sngl_xset = (fd_set *) alloca (bytes); struct timeval sngl_tv; /* Clear the original set. */ bzero (rset, bytes); bzero (wset, bytes); bzero (xset, bytes); /* This means we don't wait for input. */ sngl_tv.tv_sec = 0; sngl_tv.tv_usec = 0; maxfd = -1; /* Reset the return value. */ ready = 0; for (f = fds; f < &fds[nfds]; ++f) if (f->fd != -1 && (f->events & (POLLIN|POLLOUT|POLLPRI)) && (f->revents & POLLNVAL) == 0) { int n; bzero (sngl_rset, bytes); bzero (sngl_wset, bytes); bzero (sngl_xset, bytes); if (f->events & POLLIN) FD_SET (f->fd, sngl_rset); if (f->events & POLLOUT) FD_SET (f->fd, sngl_wset); if (f->events & POLLPRI) FD_SET (f->fd, sngl_xset); n = select (f->fd + 1, sngl_rset, sngl_wset, sngl_xset, &sngl_tv); if (n != -1) { /* This descriptor is ok. */ if (f->events & POLLIN) FD_SET (f->fd, rset); if (f->events & POLLOUT) FD_SET (f->fd, wset); if (f->events & POLLPRI) FD_SET (f->fd, xset); if (f->fd > maxfd) maxfd = f->fd; if (n > 0) ++ready; /* Count it as being available. */ } else if (errno == EBADF) f->revents |= POLLNVAL; } /* Try again. */ continue; } break; } if (ready > 0) for (f = fds; f < &fds[nfds]; ++f) { if (f->fd >= 0) { if (FD_ISSET (f->fd, rset)) f->revents |= POLLIN; if (FD_ISSET (f->fd, wset)) f->revents |= POLLOUT; if (FD_ISSET (f->fd, xset)) f->revents |= POLLPRI; } } return ready; } #endif BPoll::BPoll(){ ofdsNum = 0; ofds = 0; ofdsNext = 0; } BPoll::~BPoll(){ if(ofds) free(ofds); ofds = 0; ofdsNum = 0; ofdsNext = 0; } void BPoll::append(int fd, int events){ ofds = (PollFd*)realloc(ofds, (ofdsNum + 1) * sizeof(PollFd)); ofds[ofdsNum].fd = fd; ofds[ofdsNum].events = events; ofds[ofdsNum].revents = 0; ofdsNum++; } void BPoll::delFd(int fd){ int n; for(n = 0; n < ofdsNum; n++){ if(ofds[n].fd == fd){ break; } } if((n + 1) < ofdsNum) memcpy(&ofds[n], &ofds[n + 1], (ofdsNum - (n + 1)) * sizeof(PollFd)); ofdsNext = 0; ofdsNum--; ofds = (PollFd*)realloc(ofds, ofdsNum * sizeof(PollFd)); } int BPoll::nextFd(int i){ i++; if(i >= ofdsNum) i = 0; return i; } int BPoll::getPollFdsNum(){ return ofdsNum; } BPoll::PollFd* BPoll::getPollFds(){ return ofds; } BError BPoll::doPoll(int& fd, int timeoutUs){ BError err; int timeoutMs; int r; int i; if(timeoutUs >= 0) timeoutMs = timeoutUs / 1000; else timeoutMs = -1; r = poll(ofds, ofdsNum, timeoutMs); if(r > 0){ // Get next available fd in round robin fashion for(i = ofdsNext; ;){ if(ofds[i].revents){ fd = ofds[i].fd; ofdsNext = nextFd(i); break; } i = nextFd(i); if(i == ofdsNext) break; } } else if(r < 0){ err.set(-errno, strerror(errno)); fd = -errno; } else if(r == 0){ err.set(-ETIMEDOUT, "Timeout"); fd = -ETIMEDOUT; } return err; } BError BPoll::doPollEvents(int& fd, int& events, int timeoutUs){ BError err; int timeoutMs; int r; int i; if(timeoutUs >= 0) timeoutMs = timeoutUs / 1000; else timeoutMs = -1; r = poll(ofds, ofdsNum, timeoutMs); if(r > 0){ // Get next available fd in round robin fashion for(i = ofdsNext; ;){ if(ofds[i].revents){ fd = ofds[i].fd; events = ofds[i].revents; ofdsNext = nextFd(i); break; } i = nextFd(i); if(i == ofdsNext) break; } } else if(r < 0){ err.set(-errno, strerror(errno)); fd = -errno; } else if(r == 0){ err.set(-ETIMEDOUT, "Timeout"); fd = -ETIMEDOUT; } return err; } void BPoll::clear(){ if(ofds) free(ofds); ofds = 0; ofdsNum = 0; ofdsNext = 0; }