1 /* 2 * Copyright (c) 2004, 2005, 2007 Darren Tucker (dtucker at zip com au). 3 * 4 * Permission to use, copy, modify, and distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 #include "includes.h" 18 #if !defined(HAVE_POLL) 19 20 #include <sys/types.h> 21 #include <sys/time.h> 22 #ifdef HAVE_SYS_SELECT_H 23 # include <sys/select.h> 24 #endif 25 26 #include <errno.h> 27 #include <stdlib.h> 28 #include <unistd.h> 29 #include "bsd-poll.h" 30 31 /* 32 * A minimal implementation of poll(2), built on top of select(2). 33 * 34 * Only supports POLLIN and POLLOUT flags in pfd.events, and POLLIN, POLLOUT 35 * and POLLERR flags in revents. 36 * 37 * Supports pfd.fd = -1 meaning "unused" although it's not standard. 38 */ 39 40 int 41 poll(struct pollfd *fds, nfds_t nfds, int timeout) 42 { 43 nfds_t i; 44 int saved_errno, ret, fd, maxfd = 0; 45 fd_set *readfds = NULL, *writefds = NULL, *exceptfds = NULL; 46 size_t nmemb; 47 struct timeval tv, *tvp = NULL; 48 49 for (i = 0; i < nfds; i++) { 50 fd = fds[i].fd; 51 if (fd >= FD_SETSIZE) { 52 errno = EINVAL; 53 return -1; 54 } 55 maxfd = MAX(maxfd, fd); 56 } 57 58 nmemb = howmany(maxfd + 1 , NFDBITS); 59 if ((readfds = calloc(nmemb, sizeof(fd_mask))) == NULL || 60 (writefds = calloc(nmemb, sizeof(fd_mask))) == NULL || 61 (exceptfds = calloc(nmemb, sizeof(fd_mask))) == NULL) { 62 saved_errno = ENOMEM; 63 ret = -1; 64 goto out; 65 } 66 67 /* populate event bit vectors for the events we're interested in */ 68 for (i = 0; i < nfds; i++) { 69 fd = fds[i].fd; 70 if (fd == -1) 71 continue; 72 if (fds[i].events & POLLIN) { 73 FD_SET(fd, readfds); 74 FD_SET(fd, exceptfds); 75 } 76 if (fds[i].events & POLLOUT) { 77 FD_SET(fd, writefds); 78 FD_SET(fd, exceptfds); 79 } 80 } 81 82 /* poll timeout is msec, select is timeval (sec + usec) */ 83 if (timeout >= 0) { 84 tv.tv_sec = timeout / 1000; 85 tv.tv_usec = (timeout % 1000) * 1000; 86 tvp = &tv; 87 } 88 89 ret = select(maxfd + 1, readfds, writefds, exceptfds, tvp); 90 saved_errno = errno; 91 92 /* scan through select results and set poll() flags */ 93 for (i = 0; i < nfds; i++) { 94 fd = fds[i].fd; 95 fds[i].revents = 0; 96 if (fd == -1) 97 continue; 98 if (FD_ISSET(fd, readfds)) { 99 fds[i].revents |= POLLIN; 100 } 101 if (FD_ISSET(fd, writefds)) { 102 fds[i].revents |= POLLOUT; 103 } 104 if (FD_ISSET(fd, exceptfds)) { 105 fds[i].revents |= POLLERR; 106 } 107 } 108 109 out: 110 free(readfds); 111 free(writefds); 112 free(exceptfds); 113 if (ret == -1) 114 errno = saved_errno; 115 return ret; 116 } 117 #endif 118