From 5c983cdd089ef485b6f903efcf9e597eb1cb37ab Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Sat, 21 Jan 2006 08:21:04 +0000 Subject: [PATCH] * 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. --- ChangeLog | 16 ++++ misc/Makefile | 2 +- misc/tst-pselect.c | 120 +++++++++++++++++++++++++++ sysdeps/unix/sysv/linux/i386/Makefile | 2 +- sysdeps/unix/sysv/linux/i386/call_pselect6.S | 65 +++++++++++++++ sysdeps/unix/sysv/linux/i386/pselect.c | 18 ++++ sysdeps/unix/sysv/linux/pselect.c | 20 +++-- 7 files changed, 235 insertions(+), 8 deletions(-) create mode 100644 misc/tst-pselect.c create mode 100644 sysdeps/unix/sysv/linux/i386/call_pselect6.S create mode 100644 sysdeps/unix/sysv/linux/i386/pselect.c diff --git a/ChangeLog b/ChangeLog index cf3f93a..6614e24 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,25 @@ +2006-01-21 Ulrich Drepper + + * 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 * sysdeps/mach/hurd/ppoll.c: New file. 2006-01-20 Ulrich Drepper + * 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 dc993c4..7d60baa 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 0000000..55253de --- /dev/null +++ b/misc/tst-pselect.c @@ -0,0 +1,120 @@ +#include +#include +#include +#include +#include + + +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 7db3e3e..9e84975 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 0000000..a356f1d --- /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 , 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 + +#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 0000000..2646608 --- /dev/null +++ b/sysdeps/unix/sysv/linux/i386/pselect.c @@ -0,0 +1,18 @@ +#include + +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 6fd4d3e..0dd744f 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 -- 2.7.4