diff options
author | jb <jb@FreeBSD.org> | 1998-05-27 00:44:58 +0000 |
---|---|---|
committer | jb <jb@FreeBSD.org> | 1998-05-27 00:44:58 +0000 |
commit | 11a0d9cda5d0182b3adac316eb661a76a8e1322c (patch) | |
tree | 344eafc402b037bc2b27e2971f576e7fa2e3ed56 /lib/libkse | |
parent | f5689a7c8aff4b5630b2d69fd836902db3b1d120 (diff) | |
download | FreeBSD-src-11a0d9cda5d0182b3adac316eb661a76a8e1322c.zip FreeBSD-src-11a0d9cda5d0182b3adac316eb661a76a8e1322c.tar.gz |
Make a copy of the caller's iovec array, mallocing if necessary,
and modify that if the writev() syscall does not completely write
all bytes in a single call.
Diffstat (limited to 'lib/libkse')
-rw-r--r-- | lib/libkse/thread/thr_writev.c | 76 |
1 files changed, 62 insertions, 14 deletions
diff --git a/lib/libkse/thread/thr_writev.c b/lib/libkse/thread/thr_writev.c index 23667be..26a6006 100644 --- a/lib/libkse/thread/thr_writev.c +++ b/lib/libkse/thread/thr_writev.c @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: uthread_writev.c,v 1.5 1998/04/29 09:59:34 jb Exp $ + * $Id: uthread_writev.c,v 1.6 1998/05/25 21:45:52 jb Exp $ * */ #include <sys/types.h> @@ -45,19 +45,31 @@ ssize_t writev(int fd, const struct iovec * iov, int iovcnt) { int blocking; - int status; + int idx = 0; + ssize_t cnt; ssize_t n; ssize_t num = 0; ssize_t ret; - struct iovec liov; + struct iovec liov[20]; + struct iovec *p_iov = liov; + + /* Check if the array size exceeds to compiled in size: */ + if (iovcnt > (sizeof(liov) / sizeof(struct iovec))) { + /* Allocate memory for the local array: */ + if ((p_iov = (struct iovec *) + malloc(iovcnt * sizeof(struct iovec))) == NULL) { + /* Insufficient memory: */ + errno = ENOMEM; + return (-1); + } + } + + /* Copy the caller's array so that it can be modified locally: */ + memcpy(p_iov,iov,iovcnt * sizeof(struct iovec)); /* Lock the file descriptor for write: */ if ((ret = _thread_fd_lock(fd, FD_WRITE, NULL, __FILE__, __LINE__)) == 0) { - /* Make a local copy of the caller's iov: */ - liov.iov_base = iov->iov_base; - liov.iov_len = iov->iov_len; - /* Check if file operations are to block */ blocking = ((_thread_fd_table[fd]->flags & O_NONBLOCK) == 0); @@ -67,19 +79,50 @@ writev(int fd, const struct iovec * iov, int iovcnt) */ while (ret == 0) { /* Perform a non-blocking write syscall: */ - n = _thread_sys_writev(fd, &liov, iovcnt - num); + n = _thread_sys_writev(fd, &p_iov[idx], iovcnt - idx); /* Check if one or more bytes were written: */ if (n > 0) { - /* Update the local iov: */ - liov.iov_base += n; - liov.iov_len += n; - /* * Keep a count of the number of bytes * written: */ num += n; + + /* + * Enter a loop to check if a short write + * occurred and move the index to the + * array entry where the short write + * ended: + */ + cnt = n; + while (cnt > 0 && idx < iovcnt) { + /* + * If the residual count exceeds + * the size of this vector, then + * it was completely written: + */ + if (cnt >= p_iov[idx].iov_len) + /* + * Decrement the residual + * count and increment the + * index to the next array + * entry: + */ + cnt -= p_iov[idx++].iov_len; + else { + /* + * This entry was only + * partially written, so + * adjust it's length + * and base pointer ready + * for the next write: + */ + p_iov[idx].iov_len -= cnt; + p_iov[idx].iov_base += cnt; + cnt = 0; + } + } } /* @@ -89,7 +132,7 @@ writev(int fd, const struct iovec * iov, int iovcnt) * write: */ if (blocking && ((n < 0 && (errno == EWOULDBLOCK || - errno == EAGAIN)) || num < iovcnt)) { + errno == EAGAIN)) || idx < iovcnt)) { _thread_run->data.fd.fd = fd; _thread_kern_set_timeout(NULL); @@ -119,12 +162,17 @@ writev(int fd, const struct iovec * iov, int iovcnt) break; /* Check if the write has completed: */ - } else if (num >= iovcnt) + } else if (idx == iovcnt) /* Return the number of bytes written: */ ret = num; } _thread_fd_unlock(fd, FD_RDWR); } + + /* If memory was allocated for the array, free it: */ + if (p_iov != liov) + free(p_iov); + return (ret); } #endif |