1/*++ 2/* NAME 3/* read_wait 3 4/* SUMMARY 5/* wait until descriptor becomes readable 6/* SYNOPSIS 7/* #include <iostuff.h> 8/* 9/* int read_wait(fd, timeout) 10/* int fd; 11/* int timeout; 12/* DESCRIPTION 13/* read_wait() blocks the current process until the specified file 14/* descriptor becomes readable, or until the deadline is exceeded. 15/* 16/* Arguments: 17/* .IP fd 18/* File descriptor in the range 0..FD_SETSIZE (on systems that 19/* need to use select(2)). 20/* .IP timeout 21/* If positive, deadline in seconds. A zero value effects a poll. 22/* A negative value means wait until something happens. 23/* DIAGNOSTICS 24/* Panic: interface violation. All system call errors are fatal. 25/* 26/* A zero result means success. When the specified deadline is 27/* exceeded, read_wait() returns -1 and sets errno to ETIMEDOUT. 28/* LICENSE 29/* .ad 30/* .fi 31/* The Secure Mailer license must be distributed with this software. 32/* AUTHOR(S) 33/* Wietse Venema 34/* IBM T.J. Watson Research 35/* P.O. Box 704 36/* Yorktown Heights, NY 10598, USA 37/*--*/ 38 39/* System library. */ 40 41#include <sys_defs.h> 42#include <sys/time.h> 43#include <signal.h> 44#include <errno.h> 45#include <unistd.h> 46#include <string.h> 47 48#ifdef USE_SYSV_POLL 49#include <poll.h> 50#endif 51 52#ifdef USE_SYS_SELECT_H 53#include <sys/select.h> 54#endif 55 56/* Utility library. */ 57 58#include <msg.h> 59#include <iostuff.h> 60 61/* read_wait - block with timeout until file descriptor is readable */ 62 63int read_wait(int fd, int timeout) 64{ 65#ifndef USE_SYSV_POLL 66 fd_set read_fds; 67 fd_set except_fds; 68 struct timeval tv; 69 struct timeval *tp; 70 71 /* 72 * Sanity checks. 73 */ 74 if (FD_SETSIZE <= fd) 75 msg_panic("descriptor %d does not fit FD_SETSIZE %d", fd, FD_SETSIZE); 76 77 /* 78 * Use select() so we do not depend on alarm() and on signal() handlers. 79 * Restart the select when interrupted by some signal. Some select() 80 * implementations reduce the time to wait when interrupted, which is 81 * exactly what we want. 82 */ 83 FD_ZERO(&read_fds); 84 FD_SET(fd, &read_fds); 85 FD_ZERO(&except_fds); 86 FD_SET(fd, &except_fds); 87 if (timeout >= 0) { 88 tv.tv_usec = 0; 89 tv.tv_sec = timeout; 90 tp = &tv; 91 } else { 92 tp = 0; 93 } 94 95 for (;;) { 96 switch (select(fd + 1, &read_fds, (fd_set *) 0, &except_fds, tp)) { 97 case -1: 98 if (errno != EINTR) 99 msg_fatal("select: %m"); 100 continue; 101 case 0: 102 errno = ETIMEDOUT; 103 return (-1); 104 default: 105 return (0); 106 } 107 } 108#else 109 110 /* 111 * System-V poll() is optimal for polling a few descriptors. 112 */ 113 struct pollfd pollfd; 114 115#define WAIT_FOR_EVENT (-1) 116 117 pollfd.fd = fd; 118 pollfd.events = POLLIN; 119 for (;;) { 120 switch (poll(&pollfd, 1, timeout < 0 ? 121 WAIT_FOR_EVENT : timeout * 1000)) { 122 case -1: 123 if (errno != EINTR) 124 msg_fatal("poll: %m"); 125 continue; 126 case 0: 127 errno = ETIMEDOUT; 128 return (-1); 129 default: 130 if (pollfd.revents & POLLNVAL) 131 msg_fatal("poll: %m"); 132 return (0); 133 } 134 } 135#endif 136} 137 138#ifdef __APPLE_OS_X_SERVER__ 139/* read_wait - block with timeout until file descriptor is readable */ 140 141int read_wait_no_poll(int fd, int timeout) 142{ 143 fd_set read_fds; 144 fd_set except_fds; 145 struct timeval tv; 146 struct timeval *tp; 147 148 /* 149 * Sanity checks. 150 */ 151 if (FD_SETSIZE <= fd) 152 msg_panic("descriptor %d does not fit FD_SETSIZE %d", fd, FD_SETSIZE); 153 154 /* 155 * Use select() so we do not depend on alarm() and on signal() handlers. 156 * Restart the select when interrupted by some signal. Some select() 157 * implementations reduce the time to wait when interrupted, which is 158 * exactly what we want. 159 */ 160 FD_ZERO(&read_fds); 161 FD_SET(fd, &read_fds); 162 FD_ZERO(&except_fds); 163 FD_SET(fd, &except_fds); 164 if (timeout >= 0) { 165 tv.tv_usec = 0; 166 tv.tv_sec = timeout; 167 tp = &tv; 168 } else { 169 tp = 0; 170 } 171 172 for (;;) { 173 switch (select(fd + 1, &read_fds, (fd_set *) 0, &except_fds, tp)) { 174 case -1: 175 if (errno != EINTR) 176 msg_fatal("select: %m"); 177 continue; 178 case 0: 179 errno = ETIMEDOUT; 180 return (-1); 181 default: 182 return (0); 183 } 184 } 185} 186#endif /* __APPLE_OS_X_SERVER__ */ 187