Date: Tue, 11 Mar 2003 19:04:59 +0000 From: "Richard Dawe" Sender: rich AT phekda DOT freeserve DOT co DOT uk To: djgpp-workers AT delorie DOT com X-Mailer: Emacs 21.3.50 (via feedmail 8.3.emacs20_6 I) and Blat ver 1.8.6 Subject: readv, writev, revision 2 [PATCH] Message-Id: Reply-To: djgpp-workers AT delorie DOT com Hello. Below is revision of the implementation of readv, writev for DJGPP. Unlike revision 1, this does not use a temporary buffer - it writes out the data chunk-by-chunk. OK to commit? Bye, Rich =] Index: src/docs/kb/wc204.txi =================================================================== RCS file: /cvs/djgpp/djgpp/src/docs/kb/wc204.txi,v retrieving revision 1.147 diff -p -c -3 -r1.147 wc204.txi *** src/docs/kb/wc204.txi 8 Mar 2003 01:19:20 -0000 1.147 --- src/docs/kb/wc204.txi 11 Mar 2003 19:00:29 -0000 *************** *** 1,4 **** - @node Changes in 2.04, , Changes in 2.03, What Changed @section Changes in 2.04 --- 1,3 ---- *************** The function @code{fchmod} was added. *** 911,913 **** --- 910,916 ---- @findex _tolower @findex _toupper The functions @code{_tolower} and @code{_toupper} were added. + + @findex readv + @findex writev + The functions @code{readv} and @code{writev} were added. *** /dev/null Tue Mar 11 19:03:42 2003 --- include/sys/uio.h Wed Jan 22 12:05:12 2003 *************** *** 0 **** --- 1,49 ---- + /* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */ + #ifndef __dj_include_sys_uio_h__ + #define __dj_include_sys_uio_h__ + + #ifdef __cplusplus + extern "C" + { + #endif + + #ifndef __dj_ENFORCE_ANSI_FREESTANDING + + #include + + #ifndef __STRICT_ANSI__ + + #ifndef _SIZE_T + __DJ_size_t + #define _SIZE_T + #endif + + #ifndef _SSIZE_T + __DJ_ssize_t + #define _SSIZE_T + #endif + + #define IOV_MAX 16 + + struct iovec { + void *iov_base; /* Base address of a memory region for I/O */ + size_t iov_len; /* Size of memory region */ + }; + + extern ssize_t readv (int _fd, const struct iovec *_iov, int _iovcnt); + extern ssize_t writev (int _fd, const struct iovec *_iov, int _iovcnt); + + #ifndef _POSIX_SOURCE + + #endif /* !_POSIX_SOURCE */ + #endif /* !__STRICT_ANSI__ */ + #endif /* !__dj_ENFORCE_ANSI_FREESTANDING */ + + #ifndef __dj_ENFORCE_FUNCTION_CALLS + #endif /* !__dj_ENFORCE_FUNCTION_CALLS */ + + #ifdef __cplusplus + } + #endif + + #endif /* __dj_include_sys_uio_h__ */ *** /dev/null Tue Mar 11 19:03:42 2003 --- src/libc/posix/sys/uio/makefile Wed Jan 22 11:54:48 2003 *************** *** 0 **** --- 1,7 ---- + # Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details + TOP=../../.. + + SRC += readv.c + SRC += writev.c + + include $(TOP)/../makefile.inc *** /dev/null Tue Mar 11 19:03:42 2003 --- src/libc/posix/sys/uio/readv.c Tue Mar 11 17:01:30 2003 *************** *** 0 **** --- 1,60 ---- + /* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */ + #include + #include + #include + #include + #include + + ssize_t + readv (int fd, const struct iovec *iov, int iovcnt) + { + int old_errno = errno; + size_t maxbytes; + ssize_t nbytes = 0; + ssize_t ret; + int i; + + /* Check args */ + if ((iovcnt <= 0) || (iovcnt > IOV_MAX)) { + errno = EINVAL; + return(-1); + } + + /* Calculate total number of bytes that can be read. */ + for (maxbytes = 0, i = 0; i < iovcnt; i++) { + maxbytes += iov[i].iov_len; + if (maxbytes > SSIZE_MAX) + break; + } + + /* If we read the maximum number of bytes, we may overflow the return + * value. Return an error if this is the case. */ + if (maxbytes > SSIZE_MAX) { + errno = EINVAL; + return(-1); + } + + /* Read in the data vector-by-vector. */ + for (i = 0; i < iovcnt; i++) { + ret = read(fd, iov[i].iov_base, iov[i].iov_len); + + if (ret < 0) { + if (!i) { + /* Fail of the first one. Fail and pass through errno. */ + return(-1); + } else { + /* Hide the error and return what we've got so far. */ + errno = old_errno; + return(nbytes); + } + } + + nbytes += ret; + + /* If we didn't read in a whole vector, stop. */ + if ((size_t) ret < iov[i].iov_len) + break; + } + + return(nbytes); + } *** /dev/null Tue Mar 11 19:03:42 2003 --- src/libc/posix/sys/uio/readv.txh Tue Mar 11 19:03:04 2003 *************** *** 0 **** --- 1,49 ---- + @node readv, io + @findex readv + + @subheading Syntax + + @example + #include + + ssize_t readv(int fd, const struct iovec *iov, int iovcnt); + @end example + + @subheading Description + + @code{readv} performs a scatter-gather read from the specified file + descriptor @var{fd}. The data is written into a group of buffers described + by the array @var{iov} with @var{iovcnt} entries in a similar way to + @code{read} (@pxref{read, , read, libc}). + + @code{struct iovec} is defined as follows: + + @example + struct iovec @{ + void *iov_base; /* Base address of a memory region for I/O */ + size_t iov_len; /* Size of memory region */ + @}; + @end example + + @subheading Return Value + + On successful completion the function returns the number of bytes read. + Otherwise, a value of -1 is returned and @var{errno} is set appropriately. + + @table @samp + + @item EINVAL + One of the following conditions is true: + + @itemize @bullet + @item + The total length to read could overflow a @code{ssize_t}. + @item + @var{iovcnt} was negative, zero or larger than @code{IOV_MAX}. + @end itemize + + @end table + + @subheading Portability + + @portability !ansi, !posix-1003.2-1992, posix-1003.1-2001 *** /dev/null Tue Mar 11 19:03:42 2003 --- src/libc/posix/sys/uio/writev.c Tue Mar 11 17:00:46 2003 *************** *** 0 **** --- 1,60 ---- + /* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */ + #include + #include + #include + #include + #include + + ssize_t + writev (int fd, const struct iovec *iov, int iovcnt) + { + int old_errno = errno; + size_t maxbytes; + ssize_t nbytes = 0; + ssize_t ret; + int i; + + /* Check args */ + if ((iovcnt <= 0) || (iovcnt > IOV_MAX)) { + errno = EINVAL; + return(-1); + } + + /* Calculate the total number of bytes needed to write data. */ + for (maxbytes = 0, i = 0; i < iovcnt; i++) { + maxbytes += iov[i].iov_len; + if (maxbytes > SSIZE_MAX) + break; + } + + /* If we write the maximum number of bytes, we may overflow the return + * value. Return an error if this is the case. */ + if (maxbytes > SSIZE_MAX) { + errno = EINVAL; + return(-1); + } + + /* Write out the data vector-by-vector. */ + for (i = 0; i < iovcnt; i++) { + ret = write(fd, iov[i].iov_base, iov[i].iov_len); + + if (ret < 0) { + if (!i) { + /* Fail of the first one. Fail and pass through errno. */ + return(-1); + } else { + /* Hide the error and return what we've written so far. */ + errno = old_errno; + return(nbytes); + } + } + + nbytes += ret; + + /* If we didn't write out a whole vector, stop. */ + if ((size_t) ret < iov[i].iov_len) + break; + } + + return(nbytes); + } *** /dev/null Tue Mar 11 19:03:42 2003 --- src/libc/posix/sys/uio/writev.txh Tue Mar 11 19:03:10 2003 *************** *** 0 **** --- 1,49 ---- + @node writev, io + @findex writev + + @subheading Syntax + + @example + #include + + ssize_t writev(int fd, const struct iovec *iov, int iovcnt); + @end example + + @subheading Description + + @code{writev} performs a scatter-gather write to the specified file + descriptor @var{fd}. A group of buffers described by the array @var{iov}, + with @var{iovcnt} entries, is written to @var{fd} in a similar + way to @code{write} (@pxref{write, , write, libc}). + + @code{struct iovec} is defined as follows: + + @example + struct iovec @{ + void *iov_base; /* Base address of a memory region for I/O */ + size_t iov_len; /* Size of memory region */ + @}; + @end example + + @subheading Return Value + + On successful completion the function returns the number of bytes written. + Otherwise, a value of -1 is returned and @var{errno} is set appropriately. + + @table @samp + + @item EINVAL + One of the following conditions is true: + + @itemize @bullet + @item + The total length to write would overflow a @code{ssize_t}. + @item + @var{iovcnt} was negative, zero or larger than @code{IOV_MAX}. + @end itemize + + @end table + + @subheading Portability + + @portability !ansi, !posix-1003.2-1992, posix-1003.1-2001 *** /dev/null Tue Mar 11 19:03:42 2003 --- tests/libc/posix/sys/uio/makefile Wed Jan 22 12:16:14 2003 *************** *** 0 **** --- 1,6 ---- + TOP=../../.. + + SRC += t-readv.c + SRC += t-writev.c + + include $(TOP)/../makefile.inc *** /dev/null Tue Mar 11 19:03:43 2003 --- tests/libc/posix/sys/uio/t-readv.c Wed Jan 22 12:41:40 2003 *************** *** 0 **** --- 1,80 ---- + #include + #include + #include + #include + #include + #include + #include + #include + + #define DATA_FILENAME "t-readv.dat" + + void + fail (const char *argv0) + { + perror(argv0); + puts("FAIL"); + exit(EXIT_FAILURE); + } + + int + main (int argc, char *argv[]) + { + char data[] = "somedata"; + char bufs[5][4]; + const size_t n_bufs = 5; + struct iovec iov[IOV_MAX]; + char *p = NULL; + char allbuf[128]; + int fd; + int ret; + int i; + + assert(n_bufs <= IOV_MAX); + + /* Construct the iovec. */ + iov[0].iov_base = (void *) bufs[0]; + iov[0].iov_len = 4; + + for (i = 1; i < 5; i++) { + iov[i].iov_base = (void *) bufs[i]; + iov[i].iov_len = 1; + } + + /* Create the data file. */ + fd = open(DATA_FILENAME, O_RDWR|O_TEXT|O_TRUNC|O_CREAT, S_IRUSR|S_IWUSR); + + if (fd < 0) + fail(argv[0]); + + /* Don't write the nul to the file. */ + ret = write(fd, data, strlen(data)); + + close(fd); + + /* Read the data back in. */ + fd = open(DATA_FILENAME, O_RDONLY|O_TEXT); + + if (fd < 0) + fail(argv[0]); + + ret = readv(fd, iov, n_bufs); + if (ret < 0) + fail(argv[0]); + + close(fd); + + /* Reconstruct the string in bufs. */ + for (p = allbuf, i = 0; i < n_bufs; p += iov[i].iov_len, i++) { + memcpy(p, bufs[i], iov[i].iov_len); + } + *p = '\0'; + + if (strcmp(allbuf, data) != 0) { + printf("Expected '%s' - got '%s'\nFAIL\n", data, allbuf); + return(EXIT_FAILURE); + } + + puts("PASS"); + return(EXIT_SUCCESS); + } *** /dev/null Tue Mar 11 19:03:43 2003 --- tests/libc/posix/sys/uio/t-writev.c Wed Jan 22 12:38:30 2003 *************** *** 0 **** --- 1,76 ---- + #include + #include + #include + #include + #include + #include + #include + #include + #include + + #define DATA_FILENAME "t-writev.dat" + + void + fail (const char *argv0) + { + perror(argv0); + puts("FAIL"); + exit(EXIT_FAILURE); + } + + int + main (int argc, char *argv[]) + { + const char *data[] = { "some", "d", "a", "t", "a" }; + /* NB: data[0] is a pointer. */ + const size_t n_data = sizeof(data) / sizeof(data[0]); + struct iovec iov[IOV_MAX]; + char alldata[128]; + int fd; + int ret; + char buf[128]; + int i; + + assert(n_data <= IOV_MAX); + + /* Construct the iovec & collapse data into one string. */ + alldata[0] = '\0'; + for (i = 0; i < n_data; i++) { + iov[i].iov_base = (void *) unconst(data[i], char *); + iov[i].iov_len = strlen(data[i]); + + strcat(alldata, data[i]); + } + + /* Write out the data. */ + fd = open(DATA_FILENAME, O_RDWR|O_TEXT|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR); + if (fd < 0) + fail(argv[0]); + + ret = writev(fd, iov, n_data); + if (ret < 0) + fail(argv[0]); + + close(fd); + + /* Read back the data and check it. */ + fd = open(DATA_FILENAME, O_RDONLY|O_TEXT); + if (fd < 0) + fail(argv[0]); + + ret = read(fd, buf, sizeof(buf) - 1 /* leave space for nul */); + if (ret < 0) + fail(argv[0]); + + close(fd); + + buf[ret] = '\0'; + + if (strcmp(buf, alldata) != 0) { + printf("Expected '%s' - got '%s'\nFAIL\n", alldata, buf); + return(EXIT_FAILURE); + } + + puts("PASS"); + return(EXIT_SUCCESS); + } *** /dev/null Tue Mar 11 19:03:43 2003 --- tests/libc/posix/sys/uio/.cvsignore Wed Jan 22 12:15:30 2003 *************** *** 0 **** --- 1 ---- + *.d