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