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