thr_writev.c revision 50476
113546Sjulian/*
235509Sjb * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
313546Sjulian * All rights reserved.
413546Sjulian *
513546Sjulian * Redistribution and use in source and binary forms, with or without
613546Sjulian * modification, are permitted provided that the following conditions
713546Sjulian * are met:
813546Sjulian * 1. Redistributions of source code must retain the above copyright
913546Sjulian *    notice, this list of conditions and the following disclaimer.
1013546Sjulian * 2. Redistributions in binary form must reproduce the above copyright
1113546Sjulian *    notice, this list of conditions and the following disclaimer in the
1213546Sjulian *    documentation and/or other materials provided with the distribution.
1313546Sjulian * 3. All advertising materials mentioning features or use of this software
1413546Sjulian *    must display the following acknowledgement:
1513546Sjulian *	This product includes software developed by John Birrell.
1613546Sjulian * 4. Neither the name of the author nor the names of any co-contributors
1713546Sjulian *    may be used to endorse or promote products derived from this software
1813546Sjulian *    without specific prior written permission.
1913546Sjulian *
2013546Sjulian * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
2113546Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2213546Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2349439Sdeischen * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2413546Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2513546Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2613546Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2713546Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2813546Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2913546Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3013546Sjulian * SUCH DAMAGE.
3113546Sjulian *
3250476Speter * $FreeBSD: head/lib/libkse/thread/thr_writev.c 50476 1999-08-28 00:22:10Z peter $
3324518Sjb *
3413546Sjulian */
3513546Sjulian#include <sys/types.h>
3613546Sjulian#include <sys/fcntl.h>
3713546Sjulian#include <sys/uio.h>
3813546Sjulian#include <errno.h>
3936830Sjb#include <stdlib.h>
4036830Sjb#include <string.h>
4113546Sjulian#include <unistd.h>
4213546Sjulian#ifdef _THREAD_SAFE
4313546Sjulian#include <pthread.h>
4413546Sjulian#include "pthread_private.h"
4513546Sjulian
4613546Sjulianssize_t
4713546Sjulianwritev(int fd, const struct iovec * iov, int iovcnt)
4813546Sjulian{
4936382Sjb	int	blocking;
5036402Sjb	int	idx = 0;
5136877Sjb	int	type;
5236402Sjb	ssize_t cnt;
5336382Sjb	ssize_t n;
5436382Sjb	ssize_t num = 0;
5536382Sjb	ssize_t	ret;
5636402Sjb	struct iovec liov[20];
5736402Sjb	struct iovec *p_iov = liov;
5822315Sjulian
5936402Sjb	/* Check if the array size exceeds to compiled in size: */
6036402Sjb	if (iovcnt > (sizeof(liov) / sizeof(struct iovec))) {
6136402Sjb		/* Allocate memory for the local array: */
6236402Sjb		if ((p_iov = (struct iovec *)
6336402Sjb		    malloc(iovcnt * sizeof(struct iovec))) == NULL) {
6436402Sjb			/* Insufficient memory: */
6536402Sjb			errno = ENOMEM;
6636402Sjb			return (-1);
6736402Sjb		}
6836402Sjb	}
6936402Sjb
7036402Sjb	/* Copy the caller's array so that it can be modified locally: */
7136402Sjb	memcpy(p_iov,iov,iovcnt * sizeof(struct iovec));
7236402Sjb
7333292Sjulian	/* Lock the file descriptor for write: */
7436830Sjb	if ((ret = _FD_LOCK(fd, FD_WRITE, NULL)) == 0) {
7536877Sjb		/* Get the read/write mode type: */
7636877Sjb		type = _thread_fd_table[fd]->flags & O_ACCMODE;
7736877Sjb
7836877Sjb		/* Check if the file is not open for write: */
7936877Sjb		if (type != O_WRONLY && type != O_RDWR) {
8036877Sjb			/* File is not open for write: */
8136877Sjb			errno = EBADF;
8236877Sjb			_FD_UNLOCK(fd, FD_WRITE);
8336877Sjb			return (-1);
8436877Sjb		}
8536877Sjb
8636382Sjb		/* Check if file operations are to block */
8736382Sjb		blocking = ((_thread_fd_table[fd]->flags & O_NONBLOCK) == 0);
8836382Sjb
8936382Sjb		/*
9036382Sjb		 * Loop while no error occurs and until the expected number
9136382Sjb		 * of bytes are written if performing a blocking write:
9236382Sjb		 */
9336382Sjb		while (ret == 0) {
9436382Sjb			/* Perform a non-blocking write syscall: */
9536402Sjb			n = _thread_sys_writev(fd, &p_iov[idx], iovcnt - idx);
9636382Sjb
9736382Sjb			/* Check if one or more bytes were written: */
9836382Sjb			if (n > 0) {
9936382Sjb				/*
10036382Sjb				 * Keep a count of the number of bytes
10136382Sjb				 * written:
10236382Sjb				 */
10336382Sjb				num += n;
10436402Sjb
10536402Sjb				/*
10636402Sjb				 * Enter a loop to check if a short write
10736402Sjb				 * occurred and move the index to the
10836402Sjb				 * array entry where the short write
10936402Sjb				 * ended:
11036402Sjb				 */
11136402Sjb				cnt = n;
11236402Sjb				while (cnt > 0 && idx < iovcnt) {
11336402Sjb					/*
11436402Sjb					 * If the residual count exceeds
11536402Sjb					 * the size of this vector, then
11636402Sjb					 * it was completely written:
11736402Sjb					 */
11836402Sjb					if (cnt >= p_iov[idx].iov_len)
11936402Sjb						/*
12036402Sjb						 * Decrement the residual
12136402Sjb						 * count and increment the
12236402Sjb						 * index to the next array
12336402Sjb						 * entry:
12436402Sjb						 */
12536402Sjb						cnt -= p_iov[idx++].iov_len;
12636402Sjb					else {
12736402Sjb						/*
12836402Sjb						 * This entry was only
12936402Sjb						 * partially written, so
13036402Sjb						 * adjust it's length
13136402Sjb						 * and base pointer ready
13236402Sjb						 * for the next write:
13336402Sjb						 */
13436402Sjb						p_iov[idx].iov_len -= cnt;
13536402Sjb						p_iov[idx].iov_base += cnt;
13636402Sjb						cnt = 0;
13736402Sjb					}
13836402Sjb				}
13936382Sjb			}
14036382Sjb
14136382Sjb			/*
14236382Sjb			 * If performing a blocking write, check if the
14336382Sjb			 * write would have blocked or if some bytes
14436382Sjb			 * were written but there are still more to
14536382Sjb			 * write:
14636382Sjb			 */
14736382Sjb			if (blocking && ((n < 0 && (errno == EWOULDBLOCK ||
14836965Sjb			    errno == EAGAIN)) || (n >= 0 && idx < iovcnt))) {
14913546Sjulian				_thread_run->data.fd.fd = fd;
15013546Sjulian				_thread_kern_set_timeout(NULL);
15122315Sjulian
15222315Sjulian				/* Reset the interrupted operation flag: */
15322315Sjulian				_thread_run->interrupted = 0;
15422315Sjulian
15522315Sjulian				_thread_kern_sched_state(PS_FDW_WAIT,
15622315Sjulian				    __FILE__, __LINE__);
15722315Sjulian
15822315Sjulian				/*
15922315Sjulian				 * Check if the operation was
16022315Sjulian				 * interrupted by a signal
16122315Sjulian				 */
16222315Sjulian				if (_thread_run->interrupted) {
16336382Sjb					/* Return an error: */
16413546Sjulian					ret = -1;
16513546Sjulian				}
16636382Sjb
16736382Sjb			/*
16836382Sjb			 * If performing a non-blocking write or if an
16936382Sjb			 * error occurred, just return whatever the write
17036382Sjb			 * syscall did:
17136382Sjb			 */
17236382Sjb			} else if (!blocking || n < 0) {
17336382Sjb				/* A non-blocking call might return zero: */
17436382Sjb				ret = n;
17513546Sjulian				break;
17636382Sjb
17736382Sjb			/* Check if the write has completed: */
17836402Sjb			} else if (idx == iovcnt)
17936382Sjb				/* Return the number of bytes written: */
18036382Sjb				ret = num;
18113546Sjulian		}
18236830Sjb		_FD_UNLOCK(fd, FD_RDWR);
18313546Sjulian	}
18436402Sjb
18536402Sjb	/* If memory was allocated for the array, free it: */
18636402Sjb	if (p_iov != liov)
18736402Sjb		free(p_iov);
18836402Sjb
18913546Sjulian	return (ret);
19013546Sjulian}
19113546Sjulian#endif
192