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