* sysdeps/unix/sysv/linux/kernel-features.h: Define

__ASSUME_COMPLETE_READV_WRITEV.
	* sysdeps/unix/sysv/linux/readv.c: No need for userlevel fallback
	with modern kernels.
	* sysdeps/unix/sysv/linux/writev.c: Likewise.

	* sysdeps/posix/readv.c: Since read is a cancellation point we have
	to free a possible malloced buffer in case of cancellation.
	* sysdeps/posix/writev.c: Likewise for write.

c2009-04-01  Ulrich Drepper  <drepper@redhat.com>
This commit is contained in:
Ulrich Drepper 2009-04-03 17:23:13 +00:00
parent a065c0076a
commit 2dbe6afe7c
6 changed files with 79 additions and 53 deletions

View File

@ -1,3 +1,15 @@
2009-04-03 Ulrich Drepper <drepper@redhat.com>
* sysdeps/unix/sysv/linux/kernel-features.h: Define
__ASSUME_COMPLETE_READV_WRITEV.
* sysdeps/unix/sysv/linux/readv.c: No need for userlevel fallback
with modern kernels.
* sysdeps/unix/sysv/linux/writev.c: Likewise.
* sysdeps/posix/readv.c: Since read is a cancellation point we have
to free a possible malloced buffer in case of cancellation.
* sysdeps/posix/writev.c: Likewise for write.
2009-04-02 Ulrich Drepper <drepper@redhat.com> 2009-04-02 Ulrich Drepper <drepper@redhat.com>
* sysdeps/unix/sysv/linux/bits/socket.h: Add missing protocol numbers. * sysdeps/unix/sysv/linux/bits/socket.h: Add missing protocol numbers.
@ -29,7 +41,7 @@
(R_SPARC_NUM): Update. (R_SPARC_NUM): Update.
From Dave Miller <davem@davemloft.net>. From Dave Miller <davem@davemloft.net>.
2009-04-01 Ulrich Drepper <drepper@redhat.com> c2009-04-01 Ulrich Drepper <drepper@redhat.com>
* sysdeps/unix/sysv/linux/sys/eventfd.h (EFD_SEMAPHORE): Define. * sysdeps/unix/sysv/linux/sys/eventfd.h (EFD_SEMAPHORE): Define.

View File

@ -1,4 +1,4 @@
/* Copyright (C) 1991, 1992, 1996, 1997, 2002 Free Software Foundation, Inc. /* Copyright (C) 1991,1992,1996,1997,2002,2009 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or The GNU C Library is free software; you can redistribute it and/or
@ -25,24 +25,24 @@
#include <sys/uio.h> #include <sys/uio.h>
#include <errno.h> #include <errno.h>
static void
ifree (char **ptrp)
{
free (*ptrp);
}
/* Read data from file descriptor FD, and put the result in the /* Read data from file descriptor FD, and put the result in the
buffers described by VECTOR, which is a vector of COUNT `struct iovec's. buffers described by VECTOR, which is a vector of COUNT 'struct iovec's.
The buffers are filled in the order specified. The buffers are filled in the order specified.
Operates just like `read' (see <unistd.h>) except that data are Operates just like 'read' (see <unistd.h>) except that data are
put in VECTOR instead of a contiguous buffer. */ put in VECTOR instead of a contiguous buffer. */
ssize_t ssize_t
__libc_readv (int fd, const struct iovec *vector, int count) __libc_readv (int fd, const struct iovec *vector, int count)
{ {
char *buffer;
char *buffer_start;
size_t bytes;
ssize_t bytes_read;
int i;
bool use_malloc = false;
/* Find the total number of bytes to be read. */ /* Find the total number of bytes to be read. */
bytes = 0; size_t bytes = 0;
for (i = 0; i < count; ++i) for (int i = 0; i < count; ++i)
{ {
/* Check for ssize_t overflow. */ /* Check for ssize_t overflow. */
if (SSIZE_MAX - bytes < vector[i].iov_len) if (SSIZE_MAX - bytes < vector[i].iov_len)
@ -57,28 +57,25 @@ __libc_readv (int fd, const struct iovec *vector, int count)
use alloca since it's faster and does not require synchronization use alloca since it's faster and does not require synchronization
with other threads. But we cannot if the amount of memory with other threads. But we cannot if the amount of memory
required is too large. */ required is too large. */
char *buffer;
char *malloced_buffer __attribute__ ((__cleanup__ (ifree))) = NULL;
if (__libc_use_alloca (bytes)) if (__libc_use_alloca (bytes))
buffer = (char *) __alloca (bytes); buffer = (char *) __alloca (bytes);
else else
{ {
buffer = (char *) malloc (bytes); malloced_buffer = buffer = (char *) malloc (bytes);
if (buffer == NULL) if (buffer == NULL)
/* XXX I don't know whether it is acceptable to try reading
the data in chunks. Probably not so we just fail here. */
return -1; return -1;
use_malloc = true;
} }
/* Read the data. */ /* Read the data. */
bytes_read = __read (fd, buffer, bytes); ssize_t bytes_read = __read (fd, buffer, bytes);
if (bytes_read <= 0) if (bytes_read <= 0)
return -1; return -1;
/* Copy the data from BUFFER into the memory specified by VECTOR. */ /* Copy the data from BUFFER into the memory specified by VECTOR. */
bytes = bytes_read; bytes = bytes_read;
buffer_start = buffer; for (int i = 0; i < count; ++i)
for (i = 0; i < count; ++i)
{ {
size_t copy = MIN (vector[i].iov_len, bytes); size_t copy = MIN (vector[i].iov_len, bytes);
@ -90,9 +87,6 @@ __libc_readv (int fd, const struct iovec *vector, int count)
break; break;
} }
if (use_malloc)
free (buffer_start);
return bytes_read; return bytes_read;
} }
#ifndef __libc_readv #ifndef __libc_readv

View File

@ -1,4 +1,4 @@
/* Copyright (C) 1991, 1992, 1996, 1997, 2002 Free Software Foundation, Inc. /* Copyright (C) 1991,1992,1996,1997,2002,2009 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or The GNU C Library is free software; you can redistribute it and/or
@ -25,24 +25,25 @@
#include <sys/uio.h> #include <sys/uio.h>
#include <errno.h> #include <errno.h>
static void
ifree (char **ptrp)
{
free (*ptrp);
}
/* Write data pointed by the buffers described by VECTOR, which /* Write data pointed by the buffers described by VECTOR, which
is a vector of COUNT `struct iovec's, to file descriptor FD. is a vector of COUNT 'struct iovec's, to file descriptor FD.
The data is written in the order specified. The data is written in the order specified.
Operates just like `write' (see <unistd.h>) except that the data Operates just like 'write' (see <unistd.h>) except that the data
are taken from VECTOR instead of a contiguous buffer. */ are taken from VECTOR instead of a contiguous buffer. */
ssize_t ssize_t
__libc_writev (int fd, const struct iovec *vector, int count) __libc_writev (int fd, const struct iovec *vector, int count)
{ {
char *buffer;
register char *bp;
size_t bytes, to_copy;
ssize_t bytes_written;
int i;
bool use_malloc = false;
/* Find the total number of bytes to be written. */ /* Find the total number of bytes to be written. */
bytes = 0; size_t bytes = 0;
for (i = 0; i < count; ++i) for (int i = 0; i < count; ++i)
{ {
/* Check for ssize_t overflow. */ /* Check for ssize_t overflow. */
if (SSIZE_MAX - bytes < vector[i].iov_len) if (SSIZE_MAX - bytes < vector[i].iov_len)
@ -57,23 +58,23 @@ __libc_writev (int fd, const struct iovec *vector, int count)
use alloca since it's faster and does not require synchronization use alloca since it's faster and does not require synchronization
with other threads. But we cannot if the amount of memory with other threads. But we cannot if the amount of memory
required is too large. */ required is too large. */
char *buffer;
char *malloced_buffer __attribute__ ((__cleanup__ (ifree))) = NULL;
if (__libc_use_alloca (bytes)) if (__libc_use_alloca (bytes))
buffer = (char *) __alloca (bytes); buffer = (char *) __alloca (bytes);
else else
{ {
buffer = (char *) malloc (bytes); malloced_buffer = buffer = (char *) malloc (bytes);
if (buffer == NULL) if (buffer == NULL)
/* XXX I don't know whether it is acceptable to try writing /* XXX I don't know whether it is acceptable to try writing
the data in chunks. Probably not so we just fail here. */ the data in chunks. Probably not so we just fail here. */
return -1; return -1;
use_malloc = true;
} }
/* Copy the data into BUFFER. */ /* Copy the data into BUFFER. */
to_copy = bytes; size_t to_copy = bytes;
bp = buffer; char *bp = buffer;
for (i = 0; i < count; ++i) for (int i = 0; i < count; ++i)
{ {
size_t copy = MIN (vector[i].iov_len, to_copy); size_t copy = MIN (vector[i].iov_len, to_copy);
@ -84,10 +85,7 @@ __libc_writev (int fd, const struct iovec *vector, int count)
break; break;
} }
bytes_written = __write (fd, buffer, bytes); ssize_t bytes_written = __write (fd, buffer, bytes);
if (use_malloc)
free (buffer);
return bytes_written; return bytes_written;
} }

View File

@ -462,6 +462,13 @@
# define __ASSUME_SET_ROBUST_LIST 1 # define __ASSUME_SET_ROBUST_LIST 1
#endif #endif
/* Pessimistically assume that 2.6.18 introduced real handling of
large numbers of requests to readv and writev and that we don't
need a fallback. It likely worked for much longer. */
#if __LINUX_KERNEL_VERSION >= 0x020612
# define __ASSUME_COMPLETE_READV_WRITEV 1
#endif
/* Support for PI futexes was added in 2.6.18. */ /* Support for PI futexes was added in 2.6.18. */
#if __LINUX_KERNEL_VERSION >= 0x020612 #if __LINUX_KERNEL_VERSION >= 0x020612
# define __ASSUME_FUTEX_LOCK_PI 1 # define __ASSUME_FUTEX_LOCK_PI 1

View File

@ -1,5 +1,5 @@
/* readv supports all Linux kernels >= 2.0. /* readv supports all Linux kernels >= 2.0.
Copyright (C) 1997,1998,2000,2002,2003 Free Software Foundation, Inc. Copyright (C) 1997,1998,2000,2002,2003,2009 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or The GNU C Library is free software; you can redistribute it and/or
@ -25,6 +25,7 @@
#include <sysdep-cancel.h> #include <sysdep-cancel.h>
#include <sys/syscall.h> #include <sys/syscall.h>
#include <bp-checks.h> #include <bp-checks.h>
#include <kernel-features.h>
static ssize_t __atomic_readv_replacement (int, __const struct iovec *, static ssize_t __atomic_readv_replacement (int, __const struct iovec *,
int) internal_function; int) internal_function;
@ -45,10 +46,14 @@ do_readv (int fd, const struct iovec *vector, int count)
bytes_read = INLINE_SYSCALL (readv, 3, fd, CHECK_N (vector, count), count); bytes_read = INLINE_SYSCALL (readv, 3, fd, CHECK_N (vector, count), count);
#ifdef __ASSUME_COMPLETE_READV_WRITEV
return bytes_read;
#else
if (bytes_read >= 0 || errno != EINVAL || count <= UIO_FASTIOV) if (bytes_read >= 0 || errno != EINVAL || count <= UIO_FASTIOV)
return bytes_read; return bytes_read;
return __atomic_readv_replacement (fd, vector, count); return __atomic_readv_replacement (fd, vector, count);
#endif
} }
@ -72,5 +77,7 @@ __libc_readv (fd, vector, count)
strong_alias (__libc_readv, __readv) strong_alias (__libc_readv, __readv)
weak_alias (__libc_readv, readv) weak_alias (__libc_readv, readv)
#define __libc_readv static internal_function __atomic_readv_replacement #ifndef __ASSUME_COMPLETE_READV_WRITEV
#include <sysdeps/posix/readv.c> # define __libc_readv static internal_function __atomic_readv_replacement
# include <sysdeps/posix/readv.c>
#endif

View File

@ -1,5 +1,5 @@
/* writev supports all Linux kernels >= 2.0. /* writev supports all Linux kernels >= 2.0.
Copyright (C) 1997, 1998, 2000, 2002, 2003 Free Software Foundation, Inc. Copyright (C) 1997,1998,2000,2002,2003,2009 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or The GNU C Library is free software; you can redistribute it and/or
@ -25,6 +25,7 @@
#include <sysdep-cancel.h> #include <sysdep-cancel.h>
#include <sys/syscall.h> #include <sys/syscall.h>
#include <bp-checks.h> #include <bp-checks.h>
#include <kernel-features.h>
static ssize_t __atomic_writev_replacement (int, const struct iovec *, static ssize_t __atomic_writev_replacement (int, const struct iovec *,
int) internal_function; int) internal_function;
@ -43,12 +44,17 @@ do_writev (int fd, const struct iovec *vector, int count)
{ {
ssize_t bytes_written; ssize_t bytes_written;
bytes_written = INLINE_SYSCALL (writev, 3, fd, CHECK_N (vector, count), count); bytes_written = INLINE_SYSCALL (writev, 3, fd, CHECK_N (vector, count),
count);
#ifdef __ASSUME_COMPLETE_READV_WRITEV
return bytes_written;
#else
if (bytes_written >= 0 || errno != EINVAL || count <= UIO_FASTIOV) if (bytes_written >= 0 || errno != EINVAL || count <= UIO_FASTIOV)
return bytes_written; return bytes_written;
return __atomic_writev_replacement (fd, vector, count); return __atomic_writev_replacement (fd, vector, count);
#endif
} }
ssize_t ssize_t
@ -71,5 +77,7 @@ __libc_writev (fd, vector, count)
strong_alias (__libc_writev, __writev) strong_alias (__libc_writev, __writev)
weak_alias (__libc_writev, writev) weak_alias (__libc_writev, writev)
#define __libc_writev static internal_function __atomic_writev_replacement #ifndef __ASSUME_COMPLETE_READV_WRITEV
#include <sysdeps/posix/writev.c> # define __libc_writev static internal_function __atomic_writev_replacement
# include <sysdeps/posix/writev.c>
#endif