Mail Archives: djgpp-workers/2003/03/11/14:02:14
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 <sys/djtypes.h>
+
+ #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 <libc/stubs.h>
+ #include <unistd.h>
+ #include <errno.h>
+ #include <limits.h>
+ #include <sys/uio.h>
+
+ 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 <sys/uio.h>
+
+ 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 <libc/stubs.h>
+ #include <unistd.h>
+ #include <errno.h>
+ #include <limits.h>
+ #include <sys/uio.h>
+
+ 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 <sys/uio.h>
+
+ 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 <assert.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <unistd.h>
+ #include <sys/uio.h>
+ #include <fcntl.h>
+ #include <sys/stat.h>
+
+ #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 <assert.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <unistd.h>
+ #include <sys/uio.h>
+ #include <fcntl.h>
+ #include <sys/stat.h>
+ #include <libc/unconst.h>
+
+ #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
- Raw text -