diff options
author | Ulrich Drepper <drepper@redhat.com> | 2006-01-21 08:21:04 +0000 |
---|---|---|
committer | Ulrich Drepper <drepper@redhat.com> | 2006-01-21 08:21:04 +0000 |
commit | 5c983cdd089ef485b6f903efcf9e597eb1cb37ab (patch) | |
tree | 9006a5251d9cbab218850bd9939b0c6e417444da | |
parent | e6c8af451f8ccdbd28ea6e8419eedb5551ba4c48 (diff) | |
download | glibc-5c983cdd089ef485b6f903efcf9e597eb1cb37ab.tar.gz glibc-5c983cdd089ef485b6f903efcf9e597eb1cb37ab.tar.xz glibc-5c983cdd089ef485b6f903efcf9e597eb1cb37ab.zip |
* sysdeps/unix/sysv/linux/pselect.c (__pselect): Allow actual
system call code to be redefined in macro CALL_PSELECT6. * sysdeps/unix/sysv/linux/i386/Makefile [subdir=misc] (sysdep_routines): Add call_pselect6. * sysdeps/unix/sysv/linux/i386/call_pselect6.c: New file. * sysdeps/unix/sysv/linux/i386/pselect.c: New file. * misc/Makefile (tests): Add tst-pselect. * misc/tst-pselect.c: New file. * sysdeps/unix/sysv/linux/pselect.c: Fix typo in declaration. * sysdeps/unix/sysv/linux/xmknodat.c (__xmknodat): Cast k_dev value to unsigned int to match kernel.
-rw-r--r-- | ChangeLog | 16 | ||||
-rw-r--r-- | misc/Makefile | 2 | ||||
-rw-r--r-- | misc/tst-pselect.c | 120 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/i386/Makefile | 2 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/i386/call_pselect6.S | 65 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/i386/pselect.c | 18 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/pselect.c | 20 |
7 files changed, 235 insertions, 8 deletions
diff --git a/ChangeLog b/ChangeLog index cf3f93a8e4..6614e24b89 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,25 @@ +2006-01-21 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/pselect.c (__pselect): Allow actual + system call code to be redefined in macro CALL_PSELECT6. + * sysdeps/unix/sysv/linux/i386/Makefile [subdir=misc] + (sysdep_routines): Add call_pselect6. + * sysdeps/unix/sysv/linux/i386/call_pselect6.c: New file. + * sysdeps/unix/sysv/linux/i386/pselect.c: New file. + * misc/Makefile (tests): Add tst-pselect. + * misc/tst-pselect.c: New file. + 2006-01-20 Roland McGrath <roland@frob.com> * sysdeps/mach/hurd/ppoll.c: New file. 2006-01-20 Ulrich Drepper <drepper@redhat.com> + * sysdeps/unix/sysv/linux/pselect.c: Fix typo in declaration. + + * sysdeps/unix/sysv/linux/xmknodat.c (__xmknodat): Cast k_dev + value to unsigned int to match kernel. + * sysdeps/unix/sysv/linux/faccessat.c (faccessat): Try using the syscall in more cases. diff --git a/misc/Makefile b/misc/Makefile index dc993c4174..7d60baa7d6 100644 --- a/misc/Makefile +++ b/misc/Makefile @@ -77,7 +77,7 @@ endif gpl2lgpl := error.c error.h tests := tst-dirname tst-tsearch tst-fdset tst-efgcvt tst-mntent tst-hsearch \ - tst-error1 + tst-error1 tst-pselect ifeq (no,$(cross-compiling)) tests: $(objpfx)tst-error1-mem endif diff --git a/misc/tst-pselect.c b/misc/tst-pselect.c new file mode 100644 index 0000000000..55253ded84 --- /dev/null +++ b/misc/tst-pselect.c @@ -0,0 +1,120 @@ +#include <errno.h> +#include <signal.h> +#include <stdio.h> +#include <sys/select.h> +#include <sys/wait.h> + + +static volatile int handler_called; + +static void +handler (int sig) +{ + handler_called = 1; +} + + +static int +do_test (void) +{ + struct sigaction sa; + sa.sa_handler = handler; + sa.sa_flags = 0; + sigemptyset (&sa.sa_mask); + + if (sigaction (SIGUSR1, &sa, NULL) != 0) + { + puts ("sigaction failed"); + return 1; + } + + if (sigblock (SIGUSR1) != 0) + { + puts ("sigblock failed"); + return 1; + } + + int fds[2][2]; + + if (pipe (fds[0]) != 0 || pipe (fds[1]) != 0) + { + puts ("pipe failed"); + return 1; + } + + fd_set rfds; + FD_ZERO (&rfds); + + sigset_t ss; + sigprocmask (SIG_SETMASK, NULL, &ss); + sigdelset (&ss, SIGUSR1); + + struct timespec to = { .tv_sec = 0, .tv_nsec = 500000000 }; + + pid_t p = fork (); + if (p == 0) + { + close (fds[0][1]); + close (fds[1][0]); + + FD_SET (fds[0][0], &rfds); + + int e; + do + { + errno = 0; + e = pselect (fds[0][0] + 1, &rfds, NULL, NULL, &to, &ss); + } + while (e == 0); + + if (e != -1) + { + puts ("child: pselect did not fail"); + return 0; + } + if (errno != EINTR) + { + puts ("child: pselect did not set errno to EINTR"); + return 0; + } + + TEMP_FAILURE_RETRY (write (fds[1][1], "foo", 3)); + + exit (0); + } + + close (fds[0][0]); + close (fds[1][1]); + + FD_SET (fds[1][0], &rfds); + + kill (p, SIGUSR1); + + int e = pselect (fds[1][0] + 1, &rfds, NULL, NULL, NULL, &ss); + if (e == -1) + { + puts ("parent: pselect failed"); + return 1; + } + if (e != 1) + { + puts ("parent: pselect did not report readable fd"); + return 1; + } + if (!FD_ISSET (fds[1][0], &rfds)) + { + puts ("parent: pselect reports wrong fd"); + return 1; + } + + if (TEMP_FAILURE_RETRY (waitpid (p, NULL, 0)) != p) + { + puts ("waitpid failed"); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/sysdeps/unix/sysv/linux/i386/Makefile b/sysdeps/unix/sysv/linux/i386/Makefile index 7db3e3eeac..9e84975635 100644 --- a/sysdeps/unix/sysv/linux/i386/Makefile +++ b/sysdeps/unix/sysv/linux/i386/Makefile @@ -1,5 +1,5 @@ ifeq ($(subdir),misc) -sysdep_routines += ioperm iopl vm86 +sysdep_routines += ioperm iopl vm86 call_pselect6 sysdep_headers += sys/elf.h sys/perm.h sys/reg.h sys/vm86.h sys/debugreg.h sys/io.h endif diff --git a/sysdeps/unix/sysv/linux/i386/call_pselect6.S b/sysdeps/unix/sysv/linux/i386/call_pselect6.S new file mode 100644 index 0000000000..a356f1dfa9 --- /dev/null +++ b/sysdeps/unix/sysv/linux/i386/call_pselect6.S @@ -0,0 +1,65 @@ +/* Copyright (C) 2006 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2006. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> + +#ifdef __NR_pselect6 + .text +ENTRY(__call_pselect6) + .hidden __call_pselect6 + pushl %ebx + cfi_adjust_cfa_offset (4) + pushl %esi + cfi_adjust_cfa_offset (4) + pushl %edi + cfi_adjust_cfa_offset (4) + pushl %ebp + cfi_adjust_cfa_offset (4) + cfi_rel_offset (ebp, 0) + cfi_rel_offset (edi, 4) + cfi_rel_offset (esi, 8) + cfi_rel_offset (ebx, 12) + + movl $__NR_pselect6, %eax + movl 20(%esp), %ebx + movl 24(%esp), %ecx + movl 28(%esp), %edx + movl 32(%esp), %esi + movl 36(%esp), %edi + movl 40(%esp), %ebp + + /* The syscall handling cannot handle 6 parameters. Yet. */ + int $0x80 + + popl %ebp + cfi_adjust_cfa_offset (-4) + cfi_restore (ebp) + popl %edi + cfi_adjust_cfa_offset (-4) + cfi_restore (edi) + popl %esi + cfi_adjust_cfa_offset (-4) + cfi_restore (esi) + popl %ebx + cfi_adjust_cfa_offset (-4) + cfi_restore (ebx) + + ret +END(__call_pselect6) +#endif diff --git a/sysdeps/unix/sysv/linux/i386/pselect.c b/sysdeps/unix/sysv/linux/i386/pselect.c new file mode 100644 index 0000000000..2646608786 --- /dev/null +++ b/sysdeps/unix/sysv/linux/i386/pselect.c @@ -0,0 +1,18 @@ +#include <sys/select.h> + +extern int __call_pselect6 (int nfds, fd_set *readfds, fd_set *writefds, + fd_set *exceptfds, const struct timespec *timeout, + void *data) attribute_hidden; + + +#define CALL_PSELECT6(nfds, readfds, writefds, exceptfds, timeout, data) \ + ({ int r = __call_pselect6 (nfds, readfds, writefds, exceptfds, timeout, \ + data); \ + if (r < 0 && r > -4096) \ + { \ + __set_errno (-r); \ + r = -1; \ + } \ + r; }) + +#include "../pselect.c" diff --git a/sysdeps/unix/sysv/linux/pselect.c b/sysdeps/unix/sysv/linux/pselect.c index 6fd4d3e071..0dd744f527 100644 --- a/sysdeps/unix/sysv/linux/pselect.c +++ b/sysdeps/unix/sysv/linux/pselect.c @@ -29,7 +29,7 @@ static int __generic_pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, - const sigset_t *sigmask) + const sigset_t *sigmask); int @@ -51,7 +51,7 @@ __pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, be created. */ struct { - sigset_t *ss; + const sigset_t *ss; size_t ss_len; } data; @@ -60,15 +60,21 @@ __pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, int result; +#ifndef CALL_PSELECT6 +# define CALL_PSELECT6(nfds, readfds, writefds, exceptfds, timeout, data) \ + INLINE_SYSCALL (pselect6, 6, nfds, readfds, writefds, exceptfds, \ + timeout, data) +#endif + if (SINGLE_THREAD_P) - result = INLINE_SYSCALL (pselect6, 6, nfds, readfds, writefds, exceptfds, - timeout, &data); + result = CALL_PSELECT6 (nfds, readfds, writefds, exceptfds, timeout, + &data); else { int oldtype = LIBC_CANCEL_ASYNC (); - result = INLINE_SYSCALL (pselect6, 6, nfds, readfds, writefds, exceptfds, - timeout, &data); + result = CALL_PSELECT6 (nfds, readfds, writefds, exceptfds, timeout, + &data); LIBC_CANCEL_RESET (oldtype); } @@ -81,6 +87,8 @@ __pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, return result; } +weak_alias (__pselect, pselect) +strong_alias (__pselect, __libc_pselect) # ifndef __ASSUME_PSELECT # define __pselect static __generic_pselect |