From f93fc0b75a50d3ba8d4d69313e3c84ac0b62905b Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Wed, 3 Dec 2008 04:23:18 +0000 Subject: [PATCH] * socket/sys/socket.h: Declare accept4. * socket/accept4.c: New file. * sysdeps/unix/sysv/linux/accept4.c: New file. * sysdeps/unix/sysv/linux/i386/accept4.S: New file. * socket/Makefile (routines): Add accept4. * socket/Versions: Export accept4 with version GLIBC_2.10. * socket/paccept.c: Removed. * sysdeps/unix/sysv/linux/paccept.c: Removed. * sysdeps/unix/sysv/linux/i386/paccept.S: Removed. * Versions.def: Define GLIBC_2.10 for libc. * sysdeps/unix/sysv/linux/kernel-features.h: Define __ASSUME_ACCEPT4. * nscd/connections.c: Use accept4. * sysdeps/unix/sysv/linux/i386/socket.S: Fix comment. --- ChangeLog | 18 ++ Versions.def | 1 + nscd/connections.c | 55 ++++-- socket/Makefile | 2 +- socket/Versions | 3 + socket/{paccept.c => accept4.c} | 11 +- socket/sys/socket.h | 9 + .../unix/sysv/linux/{paccept.c => accept4.c} | 20 +-- .../sysv/linux/i386/{paccept.S => accept4.S} | 164 +++++++++++------- sysdeps/unix/sysv/linux/i386/socket.S | 4 +- sysdeps/unix/sysv/linux/kernel-features.h | 8 +- 11 files changed, 198 insertions(+), 97 deletions(-) rename socket/{paccept.c => accept4.c} (84%) rename sysdeps/unix/sysv/linux/{paccept.c => accept4.c} (73%) rename sysdeps/unix/sysv/linux/i386/{paccept.S => accept4.S} (50%) diff --git a/ChangeLog b/ChangeLog index 776adcf36d..9f8f52273d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +2008-12-02 Ulrich Drepper + + * socket/sys/socket.h: Declare accept4. + * socket/accept4.c: New file. + * sysdeps/unix/sysv/linux/accept4.c: New file. + * sysdeps/unix/sysv/linux/i386/accept4.S: New file. + * socket/Makefile (routines): Add accept4. + * socket/Versions: Export accept4 with version GLIBC_2.10. + * socket/paccept.c: Removed. + * sysdeps/unix/sysv/linux/paccept.c: Removed. + * sysdeps/unix/sysv/linux/i386/paccept.S: Removed. + * Versions.def: Define GLIBC_2.10 for libc. + * sysdeps/unix/sysv/linux/kernel-features.h: Define __ASSUME_ACCEPT4. + + * nscd/connections.c: Use accept4. + + * sysdeps/unix/sysv/linux/i386/socket.S: Fix comment. + 2008-12-01 Ulrich Drepper * resolv/res_send.c (send_dg): Create sockets with non-blocking diff --git a/Versions.def b/Versions.def index 856d878068..031e2a3541 100644 --- a/Versions.def +++ b/Versions.def @@ -26,6 +26,7 @@ libc { GLIBC_2.7 GLIBC_2.8 GLIBC_2.9 + GLIBC_2.10 %ifdef USE_IN_LIBIO HURD_CTHREADS_0.3 %endif diff --git a/nscd/connections.c b/nscd/connections.c index e3a67386d0..2b795494ea 100644 --- a/nscd/connections.c +++ b/nscd/connections.c @@ -238,8 +238,9 @@ static int resolv_conf_descr = -1; /* Negative if SOCK_CLOEXEC is not supported, positive if it is, zero before be know the result. */ static int have_sock_cloexec; -/* The paccept syscall was introduced at the same time as SOCK_CLOEXEC. */ -# define have_paccept -1 // XXX For the time being there is no such call +#endif +#ifndef __ASSUME_ACCEPT4 +static int have_accept4; #endif /* Number of times clients had to wait. */ @@ -1609,8 +1610,8 @@ nscd_run_worker (void *p) /* We are done with the list. */ pthread_mutex_unlock (&readylist_lock); -#ifndef __ASSUME_SOCK_CLOEXEC - if (have_sock_cloexec < 0) +#ifndef __ASSUME_ACCEPT4 + if (have_accept4 < 0) { /* We do not want to block on a short read or so. */ int fl = fcntl (fd, F_GETFL); @@ -1819,22 +1820,20 @@ main_loop_poll (void) /* We have a new incoming connection. Accept the connection. */ int fd; -#ifndef __ASSUME_PACCEPT +#ifndef __ASSUME_ACCEPT4 fd = -1; - if (have_paccept >= 0) + if (have_accept4 >= 0) #endif { -#if 0 - fd = TEMP_FAILURE_RETRY (paccept (sock, NULL, NULL, NULL, + fd = TEMP_FAILURE_RETRY (accept4 (sock, NULL, NULL, SOCK_NONBLOCK)); -#ifndef __ASSUME_PACCEPT - if (have_paccept == 0) - have_paccept = fd != -1 || errno != ENOSYS ? 1 : -1; -#endif +#ifndef __ASSUME_ACCEPT4 + if (have_accept4 == 0) + have_accept4 = fd != -1 || errno != ENOSYS ? 1 : -1; #endif } -#ifndef __ASSUME_PACCEPT - if (have_paccept < 0) +#ifndef __ASSUME_ACCEPT4 + if (have_accept4 < 0) fd = TEMP_FAILURE_RETRY (accept (sock, NULL, NULL)); #endif @@ -2000,7 +1999,7 @@ main_loop_epoll (int efd) /* We cannot use epoll. */ return; -#ifdef HAVE_INOTIFY +# ifdef HAVE_INOTIFY if (inotify_fd != -1) { ev.events = EPOLLRDNORM; @@ -2010,7 +2009,7 @@ main_loop_epoll (int efd) return; nused = 2; } -#endif +# endif while (1) { @@ -2025,8 +2024,26 @@ main_loop_epoll (int efd) if (revs[cnt].data.fd == sock) { /* A new connection. */ - int fd = TEMP_FAILURE_RETRY (accept (sock, NULL, NULL)); + int fd; +# ifndef __ASSUME_ACCEPT4 + fd = -1; + if (have_accept4 >= 0) +# endif + { + fd = TEMP_FAILURE_RETRY (accept4 (sock, NULL, NULL, + SOCK_NONBLOCK)); +# ifndef __ASSUME_ACCEPT4 + if (have_accept4 == 0) + have_accept4 = fd != -1 || errno != ENOSYS ? 1 : -1; +# endif + } +# ifndef __ASSUME_ACCEPT4 + if (have_accept4 < 0) + fd = TEMP_FAILURE_RETRY (accept (sock, NULL, NULL)); +# endif + + /* Use the descriptor if we have not reached the limit. */ if (fd >= 0) { /* Try to add the new descriptor. */ @@ -2048,7 +2065,7 @@ main_loop_epoll (int efd) } } } -#ifdef HAVE_INOTIFY +# ifdef HAVE_INOTIFY else if (revs[cnt].data.fd == inotify_fd) { bool to_clear[lastdb] = { false, }; @@ -2104,7 +2121,7 @@ main_loop_epoll (int efd) pthread_cond_signal (&dbs[dbcnt].prune_cond); } } -#endif +# endif else { /* Remove the descriptor from the epoll descriptor. */ diff --git a/socket/Makefile b/socket/Makefile index 92a87079e3..0e242b579c 100644 --- a/socket/Makefile +++ b/socket/Makefile @@ -27,7 +27,7 @@ headers := sys/socket.h sys/un.h bits/sockaddr.h bits/socket.h \ routines := accept bind connect getpeername getsockname getsockopt \ listen recv recvfrom recvmsg send sendmsg sendto \ setsockopt shutdown socket socketpair isfdtype opensock \ - sockatmark + sockatmark accept4 aux := have_sock_cloexec diff --git a/socket/Versions b/socket/Versions index d282eff79e..7a96b1e934 100644 --- a/socket/Versions +++ b/socket/Versions @@ -31,4 +31,7 @@ libc { # Addition from P1003.1-200x sockatmark; } + GLIBC_2.10 { + accept4; + } } diff --git a/socket/paccept.c b/socket/accept4.c similarity index 84% rename from socket/paccept.c rename to socket/accept4.c index 777dd8c300..40709d5704 100644 --- a/socket/paccept.c +++ b/socket/accept4.c @@ -23,21 +23,20 @@ When a connection arrives, open a new socket to communicate with it, set *ADDR (which is *ADDR_LEN bytes long) to the address of the connecting peer and *ADDR_LEN to the address's actual length, and return the - new socket's descriptor, or -1 for errors. SS is installed as - the thread's signal mask and FLAGS are additional flags. */ + new socket's descriptor, or -1 for errors. The operation can be influenced + by the FLAGS parameter. */ int -paccept (fd, addr, addr_len, ss, flags) +accept4 (fd, addr, addr_len, flags) int fd; __SOCKADDR_ARG addr; socklen_t *addr_len; - const __sigset_t *ss; int flags; { __set_errno (ENOSYS); return -1; } -libc_hidden_def (paccept) +libc_hidden_def (accept4) -stub_warning (paccept) +stub_warning (accept4) #include diff --git a/socket/sys/socket.h b/socket/sys/socket.h index e0a6a5216a..9b1f56f8b0 100644 --- a/socket/sys/socket.h +++ b/socket/sys/socket.h @@ -214,6 +214,15 @@ extern int listen (int __fd, int __n) __THROW; extern int accept (int __fd, __SOCKADDR_ARG __addr, socklen_t *__restrict __addr_len); +#ifdef __USE_GNU +/* Similar to 'accept' but takes an additional parameter to specify flags. + + This function is a cancellation point and therefore not marked with + __THROW. */ +extern int accept4 (int __fd, __SOCKADDR_ARG __addr, + socklen_t *__restrict __addr_len, int __flags); +#endif + /* Shut down all or part of the connection open on socket FD. HOW determines what to shut down: SHUT_RD = No more receptions; diff --git a/sysdeps/unix/sysv/linux/paccept.c b/sysdeps/unix/sysv/linux/accept4.c similarity index 73% rename from sysdeps/unix/sysv/linux/paccept.c rename to sysdeps/unix/sysv/linux/accept4.c index cc2979c0ed..97f7b8ce62 100644 --- a/sysdeps/unix/sysv/linux/paccept.c +++ b/sysdeps/unix/sysv/linux/accept4.c @@ -24,19 +24,20 @@ #include #include -#ifdef __NR_paccept +#define __NR_accept4 288 + + +#ifdef __NR_accept4 int -paccept (int fd, __SOCKADDR_ARG addr, socklen_t *addr_len, - const __sigset_t *ss, int flags) +accept4 (int fd, __SOCKADDR_ARG addr, socklen_t *addr_len, int flags) { if (SINGLE_THREAD_P) - return INLINE_SYSCALL (paccept, 6, fd, addr.__sockaddr__, addr_len, ss, - _NSIG / 8, flags); + return INLINE_SYSCALL (accept4, 4, fd, addr.__sockaddr__, addr_len, flags); int oldtype = LIBC_CANCEL_ASYNC (); - int result = INLINE_SYSCALL (paccept, 6, fd, addr.__sockaddr__, addr_len, ss, - _NSIG / 8, flags); + int result = INLINE_SYSCALL (accept4, 4, fd, addr.__sockaddr__, addr_len, + flags); LIBC_CANCEL_RESET (oldtype); @@ -44,11 +45,10 @@ paccept (int fd, __SOCKADDR_ARG addr, socklen_t *addr_len, } #else int -paccept (int fd, __SOCKADDR_ARG addr, socklen_t *addr_len, - const __sigset_t *ss, int flags) +accept4 (int fd, __SOCKADDR_ARG addr, socklen_t *addr_len, int flags) { __set_errno (ENOSYS); return -1; -stub_warning (epoll_pwait) } +stub_warning (accept4) #endif diff --git a/sysdeps/unix/sysv/linux/i386/paccept.S b/sysdeps/unix/sysv/linux/i386/accept4.S similarity index 50% rename from sysdeps/unix/sysv/linux/i386/paccept.S rename to sysdeps/unix/sysv/linux/i386/accept4.S index 02ad78dd47..087ccc456f 100644 --- a/sysdeps/unix/sysv/linux/i386/paccept.S +++ b/sysdeps/unix/sysv/linux/i386/accept4.S @@ -1,4 +1,4 @@ -/* Copyright (C) 1995-1998,2002,2003,2005,2008 Free Software Foundation, Inc. +/* Copyright (C) 1995-1998,2002,2003,2005, 2008 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -19,67 +19,33 @@ #include #include #include +#include -#define _NSIG 64 +#define EINVAL 22 +#define ENOSYS 38 -#define P(a, b) P2(a, b) -#define P2(a, b) a##b +#ifndef SOCKOP_accept4 +# define SOCKOP_accept4 18 +#endif + +#ifdef __ASSUME_ACCEPT4 +# define errlabel SYSCALL_ERROR_LABEL +#else +# define errlabel .Lerr + .data +have_accept4: + .long 0 +#endif .text -/* The socket-oriented system calls are handled unusally in Linux. +/* The socket-oriented system calls are handled unusally in Linux/i386. They are all gated through the single `socketcall' system call number. `socketcall' takes two arguments: the first is the subcode, specifying which socket function is being called; and the second is a pointer to the arguments to the specific function. */ -ENTRY(do_paccept) -#ifdef SOCKOP_paccept - subl $6*4, %esp - cfi_adjust_cfa_offset(6*4) - - movl (%eax), %ecx - movl %ecx, (%esp) - movl 4(%eax), %ecx - movl %ecx, 4(%esp) - movl 8(%eax), %ecx - movl %ecx, 8(%esp) - movl 12(%eax), %ecx - movl %ecx, 12(%esp) - movl $(_NSIG / 8), 16(%esp) - movl 16(%eax), %ecx - movl %ecx, 20(%esp) - - movl $SYS_ify(socketcall), %eax /* System call number in %eax. */ - - movl $SOCKOP_paccept, %ebx /* Subcode is first arg to syscall. */ - movl %esp, %ecx /* Address of args is 2nd arg. */ - - /* Do the system call trap. */ - ENTER_KERNEL - - addl $6*4, %esp - cfi_adjust_cfa_offset(-6*4) - - /* %eax is < 0 if there was an error. */ - cmpl $-125, %eax - jae SYSCALL_ERROR_LABEL -#else - movl $-ENOSYS, %eax - jmp SYSCALL_ERROR_LABEL - - .section .gnu.glibc-stub.paccept - .previous - .section .gnu.warning.paccept - .string "warning: paccept is not implemented and will always fail" - .previous -#endif -L(pseudo_end): - ret -PSEUDO_END(do_paccept) - - - .globl paccept -ENTRY (paccept) +.globl __libc_accept4 +ENTRY (__libc_accept4) #ifdef CENABLE SINGLE_THREAD_P jne 1f @@ -89,15 +55,27 @@ ENTRY (paccept) movl %ebx, %edx cfi_register (3, 2) - lea 4(%esp), %eax - call do_paccept + movl $SYS_ify(socketcall), %eax /* System call number in %eax. */ + + movl $SOCKOP_accept4, %ebx /* Subcode is first arg to syscall. */ + lea 4(%esp), %ecx /* Address of args is 2nd arg. */ + + /* Do the system call trap. */ + ENTER_KERNEL /* Restore registers. */ movl %edx, %ebx cfi_restore (3) + /* %eax is < 0 if there was an error. */ + cmpl $-125, %eax + jae errlabel + + /* Successful; return the syscall's value. */ +L(pseudo_end): ret + #ifdef CENABLE /* We need one more register. */ 1: pushl %esi @@ -112,8 +90,13 @@ ENTRY (paccept) movl %ebx, %edx cfi_register (3, 2) - lea 8(%esp), %eax - call do_paccept + movl $SYS_ify(socketcall), %eax /* System call number in %eax. */ + + movl $SOCKOP_accept4, %ebx /* Subcode is first arg to syscall. */ + lea 8(%esp), %ecx /* Address of args is 2nd arg. */ + + /* Do the system call trap. */ + ENTER_KERNEL /* Restore registers. */ movl %edx, %ebx @@ -129,7 +112,72 @@ ENTRY (paccept) cfi_restore (6) cfi_adjust_cfa_offset(-4) + /* %eax is < 0 if there was an error. */ + cmpl $-125, %eax + jae errlabel + /* Successful; return the syscall's value. */ ret #endif -PSEUDO_END (paccept) + +#ifndef __ASSUME_ACCEPT4 + /* The kernel returns -EINVAL for unknown socket operations. + We need to convert that error to an ENOSYS error. */ +.Lerr: cmpl $-EINVAL, %eax + jne SYSCALL_ERROR_LABEL + + /* Save registers. */ + pushl %ebx + cfi_adjust_cfa_offset(4) + cfi_offset(ebx, -8) + +# ifdef PIC + SETUP_PIC_REG (dx) + addl $_GLOBAL_OFFSET_TABLE_, %edx + movl have_accept4@GOTOFF(%edx), %eax +# else + movl have_accept4, %eax +# endif + testl %eax, %eax + jne 1f + + /* Try another call, this time with the FLAGS parameter + cleared and an invalid file descriptor. This call will not + cause any harm and it will return immediately. */ + movl $-1, 8(%esp) + movl $0, 20(%esp) + + movl $SYS_ify(socketcall), %eax /* System call number in %eax. */ + + movl $SOCKOP_accept4, %ebx /* Subcode is first arg to syscall. */ + lea 8(%esp), %ecx /* Address of args is 2nd arg. */ + + /* Do the system call trap. */ + ENTER_KERNEL + + cmpl $-EINVAL, %eax + movl $-1, %eax + je 3f + movl $1, %eax +3: +# ifdef PIC + movl %eax, have_accept4@GOTOFF(%edx) +# else + movl %eax, have_accept4 +# endif + + testl %eax, %eax + +1: movl $-EINVAL, %eax + jns 2f + movl $-ENOSYS, %eax + + /* Restore registers. */ +2: popl %ebx + cfi_restore (ebx) + + jmp SYSCALL_ERROR_LABEL +#endif +PSEUDO_END (__libc_accept4) + +weak_alias (__libc_accept4, accept4) diff --git a/sysdeps/unix/sysv/linux/i386/socket.S b/sysdeps/unix/sysv/linux/i386/socket.S index 7c8ac29b86..889e5c7060 100644 --- a/sysdeps/unix/sysv/linux/i386/socket.S +++ b/sysdeps/unix/sysv/linux/i386/socket.S @@ -1,4 +1,4 @@ -/* Copyright (C) 1995-1998,2002,2003,2005 Free Software Foundation, Inc. +/* Copyright (C) 1995-1998,2002,2003,2005,2008 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -24,7 +24,7 @@ #define P2(a, b) a##b .text -/* The socket-oriented system calls are handled unusally in Linux. +/* The socket-oriented system calls are handled unusally in Linux/i386. They are all gated through the single `socketcall' system call number. `socketcall' takes two arguments: the first is the subcode, specifying which socket function is being called; and the second is a pointer to diff --git a/sysdeps/unix/sysv/linux/kernel-features.h b/sysdeps/unix/sysv/linux/kernel-features.h index 6031eae2d0..900baf10c7 100644 --- a/sysdeps/unix/sysv/linux/kernel-features.h +++ b/sysdeps/unix/sysv/linux/kernel-features.h @@ -509,5 +509,11 @@ # define __ASSUME_SOCK_CLOEXEC 1 # define __ASSUME_IN_NONBLOCK 1 # define __ASSUME_PIPE2 1 -# define __ASSUME_PACCEPT 1 +#endif + +/* Support for the accept4 syscall was added in 2.6.28. */ +#if __LINUX_KERNEL_VERSION >= 0x02061b \ + && (defined __i386__ || defined __x86_64__ || defined __powerpc__ \ + || defined __ia64__ || defined __sparc__ || __s390__) +# define __ASSUME_ACCEPT4 1 #endif