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