about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog18
-rw-r--r--Versions.def1
-rw-r--r--nscd/connections.c55
-rw-r--r--socket/Makefile2
-rw-r--r--socket/Versions3
-rw-r--r--socket/accept4.c (renamed from socket/paccept.c)11
-rw-r--r--socket/sys/socket.h9
-rw-r--r--sysdeps/unix/sysv/linux/accept4.c (renamed from sysdeps/unix/sysv/linux/paccept.c)20
-rw-r--r--sysdeps/unix/sysv/linux/i386/accept4.S (renamed from sysdeps/unix/sysv/linux/i386/paccept.S)164
-rw-r--r--sysdeps/unix/sysv/linux/i386/socket.S4
-rw-r--r--sysdeps/unix/sysv/linux/kernel-features.h8
11 files changed, 198 insertions, 97 deletions
diff --git a/ChangeLog b/ChangeLog
index 776adcf36d..9f8f52273d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+2008-12-02  Ulrich Drepper  <drepper@redhat.com>
+
+	* 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  <drepper@redhat.com>
 
 	* 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
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 <stub-tag.h>
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
index cc2979c0ed..97f7b8ce62 100644
--- a/sysdeps/unix/sysv/linux/paccept.c
+++ b/sysdeps/unix/sysv/linux/accept4.c
@@ -24,19 +24,20 @@
 #include <sysdep-cancel.h>
 #include <sys/syscall.h>
 
-#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
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 <sysdep-cancel.h>
 #include <socketcall.h>
 #include <tls.h>
+#include <kernel-features.h>
 
-#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