Home | History | Annotate | Line # | Download | only in util
      1 /*	$NetBSD: timed_write.c,v 1.2 2017/02/14 01:16:49 christos Exp $	*/
      2 
      3 /*++
      4 /* NAME
      5 /*	timed_write 3
      6 /* SUMMARY
      7 /*	write operation with pre-write timeout
      8 /* SYNOPSIS
      9 /*	#include <iostuff.h>
     10 /*
     11 /*	ssize_t	timed_write(fd, buf, len, timeout, context)
     12 /*	int	fd;
     13 /*	const void *buf;
     14 /*	size_t	len;
     15 /*	int	timeout;
     16 /*	void	*context;
     17 /* DESCRIPTION
     18 /*	timed_write() performs a write() operation when the specified
     19 /*	descriptor becomes writable within a user-specified deadline.
     20 /*
     21 /*	Arguments:
     22 /* .IP fd
     23 /*	File descriptor in the range 0..FD_SETSIZE.
     24 /* .IP buf
     25 /*	Write buffer pointer.
     26 /* .IP len
     27 /*	Write buffer size.
     28 /* .IP timeout
     29 /*	The deadline in seconds. If this is <= 0, the deadline feature
     30 /*	is disabled.
     31 /* .IP context
     32 /*	Application context. This parameter is unused. It exists only
     33 /*	for the sake of VSTREAM compatibility.
     34 /* DIAGNOSTICS
     35 /*	When the operation does not complete within the deadline, the
     36 /*	result value is -1, and errno is set to ETIMEDOUT.
     37 /*	All other returns are identical to those of a write(2) operation.
     38 /* LICENSE
     39 /* .ad
     40 /* .fi
     41 /*	The Secure Mailer license must be distributed with this software.
     42 /* AUTHOR(S)
     43 /*	Wietse Venema
     44 /*	IBM T.J. Watson Research
     45 /*	P.O. Box 704
     46 /*	Yorktown Heights, NY 10598, USA
     47 /*--*/
     48 
     49 /* System library. */
     50 
     51 #include <sys_defs.h>
     52 #include <unistd.h>
     53 #include <errno.h>
     54 
     55 /* Utility library. */
     56 
     57 #include <msg.h>
     58 #include <iostuff.h>
     59 
     60 /* timed_write - write with deadline */
     61 
     62 ssize_t timed_write(int fd, const void *buf, size_t len,
     63 		            int timeout, void *unused_context)
     64 {
     65     ssize_t ret;
     66 
     67     /*
     68      * Wait for a limited amount of time for something to happen. If nothing
     69      * happens, report an ETIMEDOUT error.
     70      *
     71      * XXX Solaris 8 read() fails with EAGAIN after read-select() returns
     72      * success. The code below exists just in case their write implementation
     73      * is equally broken.
     74      *
     75      * This condition may also be found on systems where select() returns
     76      * success on pipes with less than PIPE_BUF bytes of space, and with
     77      * badly designed software where multiple writers are fighting for access
     78      * to the same resource.
     79      */
     80     for (;;) {
     81 	if (timeout > 0 && write_wait(fd, timeout) < 0)
     82 	    return (-1);
     83 	if ((ret = write(fd, buf, len)) < 0 && timeout > 0 && errno == EAGAIN) {
     84 	    msg_warn("write() returns EAGAIN on a writable file descriptor!");
     85 	    msg_warn("pausing to avoid going into a tight select/write loop!");
     86 	    sleep(1);
     87 	    continue;
     88 	} else if (ret < 0 && errno == EINTR) {
     89 	    continue;
     90 	} else {
     91 	    return (ret);
     92 	}
     93     }
     94 }
     95