diff options
-rw-r--r-- | nptl/ChangeLog | 42 | ||||
-rw-r--r-- | nptl/Makefile | 11 | ||||
-rw-r--r-- | nptl/init.c | 8 | ||||
-rw-r--r-- | nptl/pt-longjmp.c | 14 | ||||
-rw-r--r-- | nptl/sysdeps/alpha/jmpbuf-unwind.h (renamed from nptl/sysdeps/pthread/jmpbuf-unwind.h) | 8 | ||||
-rw-r--r-- | nptl/sysdeps/i386/jmpbuf-unwind.h | 28 | ||||
-rw-r--r-- | nptl/sysdeps/powerpc/jmpbuf-unwind.h | 28 | ||||
-rw-r--r-- | nptl/sysdeps/s390/jmpbuf-unwind.h | 29 | ||||
-rw-r--r-- | nptl/sysdeps/sh/jmpbuf-unwind.h | 28 | ||||
-rw-r--r-- | nptl/sysdeps/sparc/sparc32/jmpbuf-unwind.h | 28 | ||||
-rw-r--r-- | nptl/sysdeps/unix/sysv/linux/ia64/jmpbuf-unwind.h | 16 | ||||
-rw-r--r-- | nptl/sysdeps/x86_64/jmpbuf-unwind.h | 28 | ||||
-rw-r--r-- | nptl/tst-cancel20.c | 263 | ||||
-rw-r--r-- | nptl/tst-cancel21.c | 292 | ||||
-rw-r--r-- | nptl/tst-cancelx20.c | 1 | ||||
-rw-r--r-- | nptl/tst-cancelx21.c | 1 | ||||
-rw-r--r-- | nptl/tst-eintr1.c | 16 | ||||
-rw-r--r-- | nptl/tst-eintr2.c | 118 | ||||
-rw-r--r-- | nptl/unwind.c | 19 |
19 files changed, 953 insertions, 25 deletions
diff --git a/nptl/ChangeLog b/nptl/ChangeLog index 2d10eccccc..bca4533902 100644 --- a/nptl/ChangeLog +++ b/nptl/ChangeLog @@ -1,3 +1,45 @@ +2003-12-18 Ulrich Drepper <drepper@redhat.com> + + * tst-eintr1.c: Better error messages. + + * Makefile (tests): Add tst-eintr2. + * tst-eintr2.c: New file. + +2003-12-18 Jakub Jelinek <jakub@redhat.com> + + * Makefile (tests): Add tst-cancel21 and tst-cancelx21. + (CFLAGS-tst-cancelx21.c): Set. + * tst-cancel21.c: New test. + * tst-cancelx21.c: New test. + + * unwind.c (FRAME_LEFT): Add adj argument. Subtract it from each + comparison operand. + (unwind_stop): Use _JMPBUF_CFA_UNWINDS_ADJ macro instead of + _JMPBUF_CFA_UNWINDS. Adjust FRAME_LEFT invocations. + * pt-longjmp.c: Include jmpbuf-unwind.h. + (__pthread_cleanup_upto): Use _JMPBUF_UNWINDS_ADJ macro instead of + _JMPBUF_UNWINDS. Adjust compared pointers. + * init.c (__pthread_initialize_minimal_internal): Initialize + pd->stackblock_size. + * sysdeps/pthread/jmpbuf-unwind.h: Removed. + * sysdeps/alpha/jmpbuf-unwind.h: New file. + * sysdeps/i386/jmpbuf-unwind.h: New file. + * sysdeps/powerpc/jmpbuf-unwind.h: New file. + * sysdeps/s390/jmpbuf-unwind.h: New file. + * sysdeps/sh/jmpbuf-unwind.h: New file. + * sysdeps/sparc/sparc32/jmpbuf-unwind.h: New file. + * sysdeps/x86_64/jmpbuf-unwind.h: New file. + * sysdeps/ia64/jmpbuf-unwind.h: Include stdint.h. + (_JMPBUF_CFA_UNWINDS): Remove. + (_JMPBUF_CFA_UNWINDS_ADJ, _JMPBUF_UNWINDS_ADJ): Define. + +2003-12-12 Jakub Jelinek <jakub@redhat.com> + + * Makefile (tests): Add tst-cancel20 and tst-cancelx20. + (CFLAGS-tst-cancelx20.c): Set. + * tst-cancel20.c: New test. + * tst-cancelx20.c: New test. + 2003-12-17 Ulrich Drepper <drepper@redhat.com> * init.c (__pthread_initialize_minimal_internal): Don't treat diff --git a/nptl/Makefile b/nptl/Makefile index 8112a4d837..91d43d85ee 100644 --- a/nptl/Makefile +++ b/nptl/Makefile @@ -207,7 +207,7 @@ tests = tst-attr1 tst-attr2 tst-attr3 \ tst-kill1 tst-kill2 tst-kill3 tst-kill4 tst-kill5 tst-kill6 \ tst-join1 tst-join2 tst-join3 tst-join4 tst-join5 \ tst-detach1 \ - tst-eintr1 \ + tst-eintr1 tst-eintr2 \ tst-tsd1 tst-tsd2 tst-tsd3 tst-tsd4 \ tst-tls1 tst-tls2 \ tst-fork1 tst-fork2 tst-fork3 tst-fork4 \ @@ -215,7 +215,8 @@ tests = tst-attr1 tst-attr2 tst-attr3 \ tst-cancel1 tst-cancel2 tst-cancel3 tst-cancel4 tst-cancel5 \ tst-cancel6 tst-cancel7 tst-cancel8 tst-cancel9 tst-cancel10 \ tst-cancel11 tst-cancel12 tst-cancel13 tst-cancel14 tst-cancel15 \ - tst-cancel16 tst-cancel17 tst-cancel18 tst-cancel19 \ + tst-cancel16 tst-cancel17 tst-cancel18 tst-cancel19 tst-cancel20 \ + tst-cancel21 \ tst-cleanup0 tst-cleanup1 tst-cleanup2 tst-cleanup3 tst-cleanup4 \ tst-flock1 tst-flock2 \ tst-signal1 tst-signal2 tst-signal3 tst-signal4 tst-signal5 \ @@ -246,8 +247,8 @@ include ../Makeconfig ifeq ($(have-forced-unwind),yes) tests += tst-cancelx2 tst-cancelx3 tst-cancelx4 tst-cancelx5 \ tst-cancelx6 tst-cancelx7 tst-cancelx8 tst-cancelx9 tst-cancelx10 \ - tst-cancelx11 tst-cancelx12 tst-cancelx13 tst-cancelx14 tst-cancelx15\ - tst-cancelx16 tst-cancelx17 tst-cancelx18 \ + tst-cancelx11 tst-cancelx12 tst-cancelx13 tst-cancelx14 tst-cancelx15 \ + tst-cancelx16 tst-cancelx17 tst-cancelx18 tst-cancelx20 tst-cancelx21 \ tst-cleanupx0 tst-cleanupx1 tst-cleanupx2 tst-cleanupx3 tst-cleanupx4 \ tst-oncex3 tst-oncex4 endif @@ -388,6 +389,8 @@ CFLAGS-tst-cancelx15.c += -fexceptions CFLAGS-tst-cancelx16.c += -fexceptions CFLAGS-tst-cancelx17.c += -fexceptions CFLAGS-tst-cancelx18.c += -fexceptions +CFLAGS-tst-cancelx20.c += -fexceptions -fasynchronous-unwind-tables +CFLAGS-tst-cancelx21.c += -fexceptions -fasynchronous-unwind-tables CFLAGS-tst-cleanupx0.c += -fexceptions -fasynchronous-unwind-tables CFLAGS-tst-cleanupx1.c += -fexceptions -fasynchronous-unwind-tables CFLAGS-tst-cleanupx2.c += -fexceptions diff --git a/nptl/init.c b/nptl/init.c index 4318552226..b38b9be550 100644 --- a/nptl/init.c +++ b/nptl/init.c @@ -217,6 +217,14 @@ __pthread_initialize_minimal_internal (void) THREAD_SETMEM (pd, cpuclock_offset, GL(dl_cpuclock_offset)); #endif + /* Defined in ld.so. */ + extern void *__libc_stack_end; + + /* Set initial thread's stack block from 0 up to __libc_stack_end. + It will be bigger than it actually is, but for unwind.c/pt-longjmp.c + purposes this is good enough. */ + THREAD_SETMEM (pd, stackblock_size, (size_t) __libc_stack_end); + /* Initialize the list of all running threads with the main thread. */ INIT_LIST_HEAD (&__stack_user); list_add (&pd->list, &__stack_user); diff --git a/nptl/pt-longjmp.c b/nptl/pt-longjmp.c index f217e307f9..2022386c5b 100644 --- a/nptl/pt-longjmp.c +++ b/nptl/pt-longjmp.c @@ -20,7 +20,7 @@ #include <setjmp.h> #include <stdlib.h> #include "pthreadP.h" - +#include "jmpbuf-unwind.h" void __pthread_cleanup_upto (__jmp_buf target, char *targetframe) @@ -28,18 +28,24 @@ __pthread_cleanup_upto (__jmp_buf target, char *targetframe) struct pthread *self = THREAD_SELF; struct _pthread_cleanup_buffer *cbuf; + /* Adjust all pointers used in comparisons, so that top of thread's + stack is at the top of address space. Without that, things break + if stack is allocated above the main stack. */ + uintptr_t adj = (uintptr_t) self->stackblock + self->stackblock_size; + uintptr_t targetframe_adj = (uintptr_t) targetframe - adj; + for (cbuf = THREAD_GETMEM (self, cleanup); - cbuf != NULL && _JMPBUF_UNWINDS (target, cbuf); + cbuf != NULL && _JMPBUF_UNWINDS_ADJ (target, cbuf, adj); cbuf = cbuf->__prev) { #if _STACK_GROWS_DOWN - if ((char *) cbuf <= targetframe) + if ((uintptr_t) cbuf - adj <= targetframe_adj) { cbuf = NULL; break; } #elif _STACK_GROWS_UP - if ((char *) cbuf >= targetframe) + if ((uintptr_t) cbuf - adj >= targetframe_adj) { cbuf = NULL; break; diff --git a/nptl/sysdeps/pthread/jmpbuf-unwind.h b/nptl/sysdeps/alpha/jmpbuf-unwind.h index fef293ac17..ad77816ca0 100644 --- a/nptl/sysdeps/pthread/jmpbuf-unwind.h +++ b/nptl/sysdeps/alpha/jmpbuf-unwind.h @@ -18,7 +18,11 @@ 02111-1307 USA. */ #include <setjmp.h> +#include <stdint.h> #include <unwind.h> -#define _JMPBUF_CFA_UNWINDS(_jmpbuf, _context) \ - _JMPBUF_UNWINDS (_jmpbuf, (void *) _Unwind_GetCFA (_context)) +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ + _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) + +#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \ + ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[JB_SP] - (_adj)) diff --git a/nptl/sysdeps/i386/jmpbuf-unwind.h b/nptl/sysdeps/i386/jmpbuf-unwind.h new file mode 100644 index 0000000000..ad77816ca0 --- /dev/null +++ b/nptl/sysdeps/i386/jmpbuf-unwind.h @@ -0,0 +1,28 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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 <setjmp.h> +#include <stdint.h> +#include <unwind.h> + +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ + _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) + +#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \ + ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[JB_SP] - (_adj)) diff --git a/nptl/sysdeps/powerpc/jmpbuf-unwind.h b/nptl/sysdeps/powerpc/jmpbuf-unwind.h new file mode 100644 index 0000000000..dc8bebf99c --- /dev/null +++ b/nptl/sysdeps/powerpc/jmpbuf-unwind.h @@ -0,0 +1,28 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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 <setjmp.h> +#include <stdint.h> +#include <unwind.h> + +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ + _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) + +#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \ + ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[JB_GPR1] - (_adj)) diff --git a/nptl/sysdeps/s390/jmpbuf-unwind.h b/nptl/sysdeps/s390/jmpbuf-unwind.h new file mode 100644 index 0000000000..409408f5d2 --- /dev/null +++ b/nptl/sysdeps/s390/jmpbuf-unwind.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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 <setjmp.h> +#include <stdint.h> +#include <unwind.h> + +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ + _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) + +#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \ + ((uintptr_t) (_address) - (_adj) \ + < (uintptr_t) (_jmpbuf)->__gregs[__JB_GPR15] - (_adj)) diff --git a/nptl/sysdeps/sh/jmpbuf-unwind.h b/nptl/sysdeps/sh/jmpbuf-unwind.h new file mode 100644 index 0000000000..0fae2c2c23 --- /dev/null +++ b/nptl/sysdeps/sh/jmpbuf-unwind.h @@ -0,0 +1,28 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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 <setjmp.h> +#include <stdint.h> +#include <unwind.h> + +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ + _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) + +#define _JMPBUF_UNWINDS_ADJ(jmpbuf, address, adj) \ + ((uintptr_t) (address) - (adj) < (uintptr_t) (_jmpbuf)[0].__regs[7] - (adj)) diff --git a/nptl/sysdeps/sparc/sparc32/jmpbuf-unwind.h b/nptl/sysdeps/sparc/sparc32/jmpbuf-unwind.h new file mode 100644 index 0000000000..ad77816ca0 --- /dev/null +++ b/nptl/sysdeps/sparc/sparc32/jmpbuf-unwind.h @@ -0,0 +1,28 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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 <setjmp.h> +#include <stdint.h> +#include <unwind.h> + +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ + _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) + +#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \ + ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[JB_SP] - (_adj)) diff --git a/nptl/sysdeps/unix/sysv/linux/ia64/jmpbuf-unwind.h b/nptl/sysdeps/unix/sysv/linux/ia64/jmpbuf-unwind.h index 4a526b0f72..90b5764e81 100644 --- a/nptl/sysdeps/unix/sysv/linux/ia64/jmpbuf-unwind.h +++ b/nptl/sysdeps/unix/sysv/linux/ia64/jmpbuf-unwind.h @@ -18,12 +18,16 @@ 02111-1307 USA. */ #include <setjmp.h> +#include <stdint.h> #include <unwind.h> -#define _JMPBUF_CFA_UNWINDS(_jmpbuf, _context) \ - ({ void *_cfa = (void *) _Unwind_GetCFA (_context); \ - (_cfa < (void *)(((long *)(_jmpbuf))[0]) \ - || (_cfa == (void *)(((long *)(_jmpbuf))[0]) \ - && (void *) _Unwind_GetBSP (_context) \ - >= (void *)(((long *)(_jmpbuf))[17]))); \ +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ + ({ uintptr_t _cfa = (uintptr_t) _Unwind_GetCFA (_context) - (_adj); \ + (_cfa < (uintptr_t)(((long *)(_jmpbuf))[0]) - (_adj) \ + || (_cfa == (uintptr_t)(((long *)(_jmpbuf))[0]) - (_adj) \ + && (uintptr_t) _Unwind_GetBSP (_context) - (_adj) \ + >= (uintptr_t)(((long *)(_jmpbuf))[17]) - (_adj))); \ }) + +#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \ + ((uintptr_t)(_address) - (_adj) < (uintptr_t)(((long *)_jmpbuf)[0]) - (_adj)) diff --git a/nptl/sysdeps/x86_64/jmpbuf-unwind.h b/nptl/sysdeps/x86_64/jmpbuf-unwind.h new file mode 100644 index 0000000000..f0a22e7d9c --- /dev/null +++ b/nptl/sysdeps/x86_64/jmpbuf-unwind.h @@ -0,0 +1,28 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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 <setjmp.h> +#include <stdint.h> +#include <unwind.h> + +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ + _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) + +#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \ + ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[JB_RSP] - (_adj)) diff --git a/nptl/tst-cancel20.c b/nptl/tst-cancel20.c new file mode 100644 index 0000000000..8155c0e9fa --- /dev/null +++ b/nptl/tst-cancel20.c @@ -0,0 +1,263 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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 <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static int fd[4]; +static pthread_barrier_t b; +volatile int in_sh_body; +unsigned long cleanups; + +static void +cl (void *arg) +{ + cleanups = (cleanups << 4) | (long) arg; +} + + +static void __attribute__((noinline)) +sh_body (void) +{ + char c; + + pthread_cleanup_push (cl, (void *) 1L); + + in_sh_body = 1; + if (read (fd[2], &c, 1) == 1) + { + puts ("read succeeded"); + exit (1); + } + + pthread_cleanup_pop (0); +} + + +static void +sh (int sig) +{ + pthread_cleanup_push (cl, (void *) 2L); + sh_body (); + in_sh_body = 0; + + pthread_cleanup_pop (0); +} + + +static void __attribute__((noinline)) +tf_body (void) +{ + char c; + + pthread_cleanup_push (cl, (void *) 3L); + + int r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("child thread: barrier_wait failed"); + exit (1); + } + + if (read (fd[0], &c, 1) == 1) + { + puts ("read succeeded"); + exit (1); + } + + read (fd[0], &c, 1); + + pthread_cleanup_pop (0); +} + + +static void * +tf (void *arg) +{ + pthread_cleanup_push (cl, (void *) 4L); + tf_body (); + pthread_cleanup_pop (0); + return NULL; +} + + +static int +do_one_test (void) +{ + cleanups = 0; + if (pipe (fd) != 0 || pipe (fd + 2) != 0) + { + puts ("pipe failed"); + return 1; + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + return 1; + } + + int r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("parent thread: barrier_wait failed"); + return 1; + } + + sleep (1); + + r = pthread_kill (th, SIGHUP); + if (r) + { + errno = r; + printf ("pthread_kill failed %m\n"); + return 1; + } + + while (in_sh_body == 0) + sleep (1); + + if (pthread_cancel (th) != 0) + { + puts ("cancel failed"); + return 1; + } + + /* This will cause the read in the child to return. */ + close (fd[0]); + close (fd[1]); + close (fd[2]); + close (fd[3]); + + void *ret; + if (pthread_join (th, &ret) != 0) + { + puts ("join failed"); + return 1; + } + + if (ret != PTHREAD_CANCELED) + { + puts ("result is wrong"); + return 1; + } + + if (cleanups != 0x1234L) + { + printf ("called cleanups %lx\n", cleanups); + return 1; + } + + return 0; +} + + +static int +do_test (void) +{ + stack_t ss; + ss.ss_sp = malloc (2 * SIGSTKSZ); + if (ss.ss_sp == NULL) + { + puts ("failed to allocate alternate stack"); + return 1; + } + ss.ss_flags = 0; + ss.ss_size = 2 * SIGSTKSZ; + if (sigaltstack (&ss, NULL) < 0) + { + printf ("sigaltstack failed %m\n"); + return 1; + } + + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + struct sigaction sa; + sa.sa_handler = sh; + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + + if (sigaction (SIGHUP, &sa, NULL) != 0) + { + puts ("sigaction failed"); + return 1; + } + + puts ("sa_flags = 0 test"); + if (do_one_test ()) + return 1; + + sa.sa_handler = sh; + sigemptyset (&sa.sa_mask); + sa.sa_flags = SA_ONSTACK; + + if (sigaction (SIGHUP, &sa, NULL) != 0) + { + puts ("sigaction failed"); + return 1; + } + + puts ("sa_flags = SA_ONSTACK test"); + if (do_one_test ()) + return 1; + + sa.sa_sigaction = (void (*)(int, siginfo_t *, void *)) sh; + sigemptyset (&sa.sa_mask); + sa.sa_flags = SA_SIGINFO; + + if (sigaction (SIGHUP, &sa, NULL) != 0) + { + puts ("sigaction failed"); + return 1; + } + + puts ("sa_flags = SA_SIGINFO test"); + if (do_one_test ()) + return 1; + + sa.sa_sigaction = (void (*)(int, siginfo_t *, void *)) sh; + sigemptyset (&sa.sa_mask); + sa.sa_flags = SA_SIGINFO | SA_ONSTACK; + + if (sigaction (SIGHUP, &sa, NULL) != 0) + { + puts ("sigaction failed"); + return 1; + } + + puts ("sa_flags = SA_SIGINFO|SA_ONSTACK test"); + if (do_one_test ()) + return 1; + + return 0; +} + +#define TIMEOUT 40 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/nptl/tst-cancel21.c b/nptl/tst-cancel21.c new file mode 100644 index 0000000000..c40d87b84b --- /dev/null +++ b/nptl/tst-cancel21.c @@ -0,0 +1,292 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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 <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/wait.h> +#include <unistd.h> + + +static int fd[4]; +static pthread_barrier_t b; +volatile int in_sh_body; +unsigned long cleanups; + +static void +cl (void *arg) +{ + cleanups = (cleanups << 4) | (long) arg; +} + + +static void __attribute__((noinline)) +sh_body (void) +{ + char c; + + pthread_cleanup_push (cl, (void *) 1L); + + in_sh_body = 1; + if (read (fd[2], &c, 1) == 1) + { + puts ("read succeeded"); + exit (1); + } + + pthread_cleanup_pop (0); +} + + +static void +sh (int sig) +{ + pthread_cleanup_push (cl, (void *) 2L); + sh_body (); + in_sh_body = 0; + + pthread_cleanup_pop (0); +} + + +static void __attribute__((noinline)) +tf_body (void) +{ + char c; + + pthread_cleanup_push (cl, (void *) 3L); + + int r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("child thread: barrier_wait failed"); + exit (1); + } + + if (read (fd[0], &c, 1) == 1) + { + puts ("read succeeded"); + exit (1); + } + + read (fd[0], &c, 1); + + pthread_cleanup_pop (0); +} + + +static void * +tf (void *arg) +{ + pthread_t th = (pthread_t) arg; + + int r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("parent thread: barrier_wait failed"); + exit (1); + } + + sleep (1); + + r = pthread_kill (th, SIGHUP); + if (r) + { + errno = r; + printf ("pthread_kill failed %m\n"); + exit (1); + } + + while (in_sh_body == 0) + sleep (1); + + if (pthread_cancel (th) != 0) + { + puts ("cancel failed"); + exit (1); + } + + /* This will cause the read in the initial thread to return. */ + close (fd[0]); + close (fd[1]); + close (fd[2]); + close (fd[3]); + + void *ret; + if (pthread_join (th, &ret) != 0) + { + puts ("join failed"); + exit (1); + } + + if (ret != PTHREAD_CANCELED) + { + puts ("result is wrong"); + exit (1); + } + + if (cleanups != 0x1234L) + { + printf ("called cleanups %lx\n", cleanups); + exit (1); + } + + if (pthread_barrier_destroy (&b)) + { + puts ("barrier destroy failed"); + exit (1); + } + + exit (0); +} + + +static int +do_one_test (void) +{ + pid_t pid = fork (); + + if (pid == -1) + { + printf ("fork failed: %m\n"); + return 1; + } + + if (pid) + { + int status; + if (waitpid (pid, &status, 0) < 0) + { + printf ("waitpid failed %m\n"); + return 1; + } + + return !WIFEXITED (status) || WEXITSTATUS (status); + } + + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + cleanups = 0; + if (pipe (fd) != 0 || pipe (fd + 2) != 0) + { + puts ("pipe failed"); + exit (1); + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, (void *) pthread_self ()) != 0) + { + puts ("create failed"); + exit (1); + } + + pthread_cleanup_push (cl, (void *) 4L); + tf_body (); + pthread_cleanup_pop (0); + exit (1); +} + + +static int +do_test (void) +{ + stack_t ss; + ss.ss_sp = malloc (2 * SIGSTKSZ); + if (ss.ss_sp == NULL) + { + puts ("failed to allocate alternate stack"); + return 1; + } + ss.ss_flags = 0; + ss.ss_size = 2 * SIGSTKSZ; + if (sigaltstack (&ss, NULL) < 0) + { + printf ("sigaltstack failed %m\n"); + return 1; + } + + struct sigaction sa; + sa.sa_handler = sh; + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + + if (sigaction (SIGHUP, &sa, NULL) != 0) + { + puts ("sigaction failed"); + return 1; + } + + puts ("sa_flags = 0 test"); + if (do_one_test ()) + return 1; + + sa.sa_handler = sh; + sigemptyset (&sa.sa_mask); + sa.sa_flags = SA_ONSTACK; + + if (sigaction (SIGHUP, &sa, NULL) != 0) + { + puts ("sigaction failed"); + return 1; + } + + puts ("sa_flags = SA_ONSTACK test"); + if (do_one_test ()) + return 1; + + sa.sa_sigaction = (void (*)(int, siginfo_t *, void *)) sh; + sigemptyset (&sa.sa_mask); + sa.sa_flags = SA_SIGINFO; + + if (sigaction (SIGHUP, &sa, NULL) != 0) + { + puts ("sigaction failed"); + return 1; + } + + puts ("sa_flags = SA_SIGINFO test"); + if (do_one_test ()) + return 1; + + sa.sa_sigaction = (void (*)(int, siginfo_t *, void *)) sh; + sigemptyset (&sa.sa_mask); + sa.sa_flags = SA_SIGINFO | SA_ONSTACK; + + if (sigaction (SIGHUP, &sa, NULL) != 0) + { + puts ("sigaction failed"); + return 1; + } + + puts ("sa_flags = SA_SIGINFO|SA_ONSTACK test"); + if (do_one_test ()) + return 1; + + return 0; +} + +#define TIMEOUT 40 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/nptl/tst-cancelx20.c b/nptl/tst-cancelx20.c new file mode 100644 index 0000000000..6bd86376ca --- /dev/null +++ b/nptl/tst-cancelx20.c @@ -0,0 +1 @@ +#include "tst-cancel20.c" diff --git a/nptl/tst-cancelx21.c b/nptl/tst-cancelx21.c new file mode 100644 index 0000000000..2a01061ea8 --- /dev/null +++ b/nptl/tst-cancelx21.c @@ -0,0 +1 @@ +#include "tst-cancel21.c" diff --git a/nptl/tst-eintr1.c b/nptl/tst-eintr1.c index 72e4397b4e..41ec2508e0 100644 --- a/nptl/tst-eintr1.c +++ b/nptl/tst-eintr1.c @@ -22,6 +22,7 @@ #include <signal.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include "eintr.c" @@ -49,7 +50,9 @@ tf1 (void *arg) exit (1); } - puts ("pthread_create failed"); + char buf[100]; + printf ("tf1: pthread_create failed: %s\n", + strerror_r (e, buf, sizeof (buf))); exit (1); } @@ -62,7 +65,9 @@ tf1 (void *arg) exit (1); } - puts ("join failed"); + char buf[100]; + printf ("tf1: pthread_join failed: %s\n", + strerror_r (e, buf, sizeof (buf))); exit (1); } } @@ -78,9 +83,12 @@ do_test (void) for (i = 0; i < 10; ++i) { pthread_t th; - if (pthread_create (&th, NULL, tf1, NULL) != 0) + int e = pthread_create (&th, NULL, tf1, NULL); + if (e != 0) { - puts ("pthread_create failed"); + char buf[100]; + printf ("main: pthread_create failed: %s\n", + strerror_r (e, buf, sizeof (buf))); exit (1); } } diff --git a/nptl/tst-eintr2.c b/nptl/tst-eintr2.c new file mode 100644 index 0000000000..00b2ecdfcd --- /dev/null +++ b/nptl/tst-eintr2.c @@ -0,0 +1,118 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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 <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> + +#include "eintr.c" + + +static pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t m2 = PTHREAD_MUTEX_INITIALIZER; + + +static void * +tf1 (void *arg) +{ + struct timespec ts; + struct timeval tv; + + gettimeofday (&tv, NULL); + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ts.tv_sec += 10000; + + /* This call must never return. */ + int e = pthread_mutex_timedlock (&m1, &ts); + char buf[100]; + printf ("tf1: mutex_lock returned: %s\n", + strerror_r (e, buf, sizeof (buf))); + + exit (1); +} + + +static void * +tf2 (void *arg) +{ + while (1) + { + int e = pthread_mutex_lock (&m2); + if (e != 0) + { + puts ("tf2: mutex_lock failed"); + exit (1); + } + e = pthread_mutex_unlock (&m2); + if (e != 0) + { + puts ("tf2: mutex_unlock failed"); + exit (1); + } + struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000 }; + nanosleep (&ts, NULL); + } +} + + +static int +do_test (void) +{ + if (pthread_mutex_lock (&m1) != 0) + { + puts ("mutex_lock failed"); + exit (1); + } + + setup_eintr (SIGUSR1); + + pthread_t th; + char buf[100]; + int e = pthread_create (&th, NULL, tf1, NULL); + if (e != 0) + { + printf ("main: 1st pthread_create failed: %s\n", + strerror_r (e, buf, sizeof (buf))); + exit (1); + } + + e = pthread_create (&th, NULL, tf2, NULL); + if (e != 0) + { + printf ("main: 2nd pthread_create failed: %s\n", + strerror_r (e, buf, sizeof (buf))); + exit (1); + } + + /* This call must never return. */ + e = pthread_mutex_lock (&m1); + printf ("main: mutex_lock returned: %s\n", + strerror_r (e, buf, sizeof (buf))); + + return 0; +} + +#define EXPECTED_SIGNAL SIGALRM +#define TIMEOUT 3 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/nptl/unwind.c b/nptl/unwind.c index 8013b5a829..f72c33891d 100644 --- a/nptl/unwind.c +++ b/nptl/unwind.c @@ -28,9 +28,11 @@ #ifdef HAVE_FORCED_UNWIND #ifdef _STACK_GROWS_DOWN -# define FRAME_LEFT(frame, other) ((char *) frame >= (char *) other) +# define FRAME_LEFT(frame, other, adj) \ + ((uintptr_t) frame - adj >= (uintptr_t) other - adj) #elif _STACK_GROWS_UP -# define FRAME_LEFT(frame, other) ((char *) frame <= (char *) other) +# define FRAME_LEFT(frame, other, adj) \ + ((uintptr_t) frame - adj <= (uintptr_t) other - adj) #else # error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP" #endif @@ -45,6 +47,11 @@ unwind_stop (int version, _Unwind_Action actions, struct pthread *self = THREAD_SELF; struct _pthread_cleanup_buffer *curp = THREAD_GETMEM (self, cleanup); int do_longjump = 0; + + /* Adjust all pointers used in comparisons, so that top of thread's + stack is at the top of address space. Without that, things break + if stack is allocated above the main stack. */ + uintptr_t adj = (uintptr_t) self->stackblock + self->stackblock_size; /* Do longjmp if we're at "end of stack", aka "end of unwind data". We assume there are only C frame without unwind data in between @@ -52,7 +59,8 @@ unwind_stop (int version, _Unwind_Action actions, of a function is NOT within it's stack frame; it's the SP of the previous frame. */ if ((actions & _UA_END_OF_STACK) - || ! _JMPBUF_CFA_UNWINDS (buf->cancel_jmp_buf[0].jmp_buf, context)) + || ! _JMPBUF_CFA_UNWINDS_ADJ (buf->cancel_jmp_buf[0].jmp_buf, context, + adj)) do_longjump = 1; if (__builtin_expect (curp != NULL, 0)) @@ -63,7 +71,7 @@ unwind_stop (int version, _Unwind_Action actions, struct _pthread_cleanup_buffer *oldp = buf->priv.data.cleanup; void *cfa = (void *) _Unwind_GetCFA (context); - if (curp != oldp && (do_longjump || FRAME_LEFT (cfa, curp))) + if (curp != oldp && (do_longjump || FRAME_LEFT (cfa, curp, adj))) { do { @@ -76,7 +84,8 @@ unwind_stop (int version, _Unwind_Action actions, /* To the next. */ curp = nextp; } - while (curp != oldp && (do_longjump || FRAME_LEFT (cfa, curp))); + while (curp != oldp + && (do_longjump || FRAME_LEFT (cfa, curp, adj))); /* Mark the current element as handled. */ THREAD_SETMEM (self, cleanup, curp); |