Update.
authorUlrich Drepper <drepper@redhat.com>
Sun, 8 Jun 2003 05:28:14 +0000 (05:28 +0000)
committerUlrich Drepper <drepper@redhat.com>
Sun, 8 Jun 2003 05:28:14 +0000 (05:28 +0000)
2003-06-07  Ulrich Drepper  <drepper@redhat.com>

* cleanup_routine.c: New file.
* Versions (libpthread) [GLIBC_2.3.3]: Add __pthread_cleanup_routine.
* sysdeps/pthread/pthread.h: Add support for fully exception-based
cleanup handling.
* Makefile (libpthread-routines): Add cleanup_routine.
Add more CFLAGS variables to compile with exceptions.  Add comments
why which file needs unwind tables.
(tests) [have-forced-unwind==yes]: Add tst-cancelx* and tst-cleanupx*
tests.
* tst-cancelx1.c: New file.
* tst-cancelx2.c: New file.
* tst-cancelx3.c: New file.
* tst-cancelx4.c: New file.
* tst-cancelx5.c: New file.
* tst-cancelx6.c: New file.
* tst-cancelx7.c: New file.
* tst-cancelx8.c: New file.
* tst-cancelx9.c: New file.
* tst-cancelx10.c: New file.
* tst-cancelx11.c: New file.
* tst-cancelx12.c: New file.
* tst-cancelx13.c: New file.
* tst-cancelx14.c: New file.
* tst-cancelx15.c: New file.
* tst-cleanupx0.c: New file.
* tst-cleanupx0.expect: New file.
* tst-cleanupx1.c: New file.
* tst-cleanupx2.c: New file.
* tst-cleanupx3.c: New file.

* tst-cleanup0.c: Make standard compliant.
* tst-cleanup1.c: Likewise.

* sysdeps/unix/sysv/linux/sem_timedwait.c: Add cancellation support.
* sysdeps/unix/sysv/linux/sem_wait.c: Likewise.
* sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S: Likewise.
* sysdeps/unix/sysv/linux/i386/i486/sem_wait.S: Likewise.
* sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S: Likewise.
* sysdeps/unix/sysv/linux/x86_64/sem_wait.S: Likewise.
* sysdeps/i386/tcb-offsets.sym: Add RESULT, CANCELHANDLING, and
CLEANUP_JMP_BUF.
* sysdeps/x86_64/tcb-offsets.sym: Likewise.
* tst-cancel12.c: New file.
* tst-cancel13.c: New file.
* tst-cancel14.c: New file.
* tst-cancel15.c: New file.
* Makefile (tests): Add tst-cancel12, tst-cancel13, tst-cancel14,
and tst-cancel15.

* tst-cancel1.c: Add some comments.

* sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S: Compute relative
timeout correctly.

40 files changed:
nptl/ChangeLog
nptl/Makefile
nptl/Versions
nptl/cleanup_routine.c [new file with mode: 0644]
nptl/sysdeps/i386/tcb-offsets.sym
nptl/sysdeps/pthread/pthread.h
nptl/sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S
nptl/sysdeps/unix/sysv/linux/i386/i486/sem_wait.S
nptl/sysdeps/unix/sysv/linux/sem_timedwait.c
nptl/sysdeps/unix/sysv/linux/sem_wait.c
nptl/sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S
nptl/sysdeps/unix/sysv/linux/x86_64/sem_wait.S
nptl/sysdeps/x86_64/tcb-offsets.sym
nptl/tst-cancel1.c
nptl/tst-cancel12.c [new file with mode: 0644]
nptl/tst-cancel13.c [new file with mode: 0644]
nptl/tst-cancel14.c [new file with mode: 0644]
nptl/tst-cancel15.c [new file with mode: 0644]
nptl/tst-cancelx1.c [new file with mode: 0644]
nptl/tst-cancelx10.c [new file with mode: 0644]
nptl/tst-cancelx11.c [new file with mode: 0644]
nptl/tst-cancelx12.c [new file with mode: 0644]
nptl/tst-cancelx13.c [new file with mode: 0644]
nptl/tst-cancelx14.c [new file with mode: 0644]
nptl/tst-cancelx15.c [new file with mode: 0644]
nptl/tst-cancelx2.c [new file with mode: 0644]
nptl/tst-cancelx3.c [new file with mode: 0644]
nptl/tst-cancelx4.c [new file with mode: 0644]
nptl/tst-cancelx5.c [new file with mode: 0644]
nptl/tst-cancelx6.c [new file with mode: 0644]
nptl/tst-cancelx7.c [new file with mode: 0644]
nptl/tst-cancelx8.c [new file with mode: 0644]
nptl/tst-cancelx9.c [new file with mode: 0644]
nptl/tst-cleanup0.c
nptl/tst-cleanup1.c
nptl/tst-cleanupx0.c [new file with mode: 0644]
nptl/tst-cleanupx0.expect [new file with mode: 0644]
nptl/tst-cleanupx1.c [new file with mode: 0644]
nptl/tst-cleanupx2.c [new file with mode: 0644]
nptl/tst-cleanupx3.c [new file with mode: 0644]

index 0d0c568..aa18be2 100644 (file)
@@ -1,3 +1,59 @@
+2003-06-07  Ulrich Drepper  <drepper@redhat.com>
+
+       * cleanup_routine.c: New file.
+       * Versions (libpthread) [GLIBC_2.3.3]: Add __pthread_cleanup_routine.
+       * sysdeps/pthread/pthread.h: Add support for fully exception-based
+       cleanup handling.
+       * Makefile (libpthread-routines): Add cleanup_routine.
+       Add more CFLAGS variables to compile with exceptions.  Add comments
+       why which file needs unwind tables.
+       (tests) [have-forced-unwind==yes]: Add tst-cancelx* and tst-cleanupx*
+       tests.
+       * tst-cancelx1.c: New file.
+       * tst-cancelx2.c: New file.
+       * tst-cancelx3.c: New file.
+       * tst-cancelx4.c: New file.
+       * tst-cancelx5.c: New file.
+       * tst-cancelx6.c: New file.
+       * tst-cancelx7.c: New file.
+       * tst-cancelx8.c: New file.
+       * tst-cancelx9.c: New file.
+       * tst-cancelx10.c: New file.
+       * tst-cancelx11.c: New file.
+       * tst-cancelx12.c: New file.
+       * tst-cancelx13.c: New file.
+       * tst-cancelx14.c: New file.
+       * tst-cancelx15.c: New file.
+       * tst-cleanupx0.c: New file.
+       * tst-cleanupx0.expect: New file.
+       * tst-cleanupx1.c: New file.
+       * tst-cleanupx2.c: New file.
+       * tst-cleanupx3.c: New file.
+
+       * tst-cleanup0.c: Make standard compliant.
+       * tst-cleanup1.c: Likewise.
+
+       * sysdeps/unix/sysv/linux/sem_timedwait.c: Add cancellation support.
+       * sysdeps/unix/sysv/linux/sem_wait.c: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/sem_wait.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/sem_wait.S: Likewise.
+       * sysdeps/i386/tcb-offsets.sym: Add RESULT, CANCELHANDLING, and
+       CLEANUP_JMP_BUF.
+       * sysdeps/x86_64/tcb-offsets.sym: Likewise.
+       * tst-cancel12.c: New file.
+       * tst-cancel13.c: New file.
+       * tst-cancel14.c: New file.
+       * tst-cancel15.c: New file.
+       * Makefile (tests): Add tst-cancel12, tst-cancel13, tst-cancel14,
+       and tst-cancel15.
+
+       * tst-cancel1.c: Add some comments.
+
+       * sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S: Compute relative
+       timeout correctly.
+
 2003-06-06  Ulrich Drepper  <drepper@redhat.com>
 
        * Makefile (CFLAGS-pthread_cancel.c): Define.
index 78d05f4..74ede77 100644 (file)
@@ -116,7 +116,8 @@ libpthread-routines = init events version \
                      sigaction \
                      herrno res pt-allocrtsig \
                      pthread_kill_other_threads \
-                     pthread_getaffinity pthread_setaffinity
+                     pthread_getaffinity pthread_setaffinity \
+                     cleanup_routine
 
 libpthread-shared-only-routines = version pt-allocrtsig
 libpthread-static-only-routines = pthread_atfork
@@ -124,16 +125,41 @@ libpthread-static-only-routines = pthread_atfork
 libpthread-nonshared = pthread_atfork
 
 CFLAGS-pthread_atfork.c = -DNOT_IN_libc
+
+# Since cancellation handling is in large parts handled using exceptions
+# we have to compile some files with exception handling enabled, some
+# even with asynchronous unwind tables.
+
+# init.c contains sigcancel_handler().
 CFLAGS-init.c = -fexceptions -fasynchronous-unwind-tables
+# The unwind code itself,
 CFLAGS-unwind.c = -fexceptions
+
+# The following three functions must be async-cancel safe.
+CFLAGS-pthread_cancel.c = -fexceptions -fasynchronous-unwind-tables
+CFLAGS-pthread_setcancelstate.c = -fexceptions -fasynchronous-unwind-tables
+CFLAGS-pthread_setcanceltype.c = -fexceptions -fasynchronous-unwind-tables
+
+# These are internal functions which similar functionality as setcancelstate
+# and setcanceltype.
+CFLAGS-cancellation.c = -fasynchronous-unwind-tables
+CFLAGS-libc-cancellation.c = -fasynchronous-unwind-tables
+
+# Calling pthread_exit() must cause the registered cancel handlers to
+# be executed.  Therefore exceptions have to be thrown through this
+# function.
+CFLAGS-pthread_exit.c = -fexceptions
+
+# The following are cancellation points.  Some of the functions can
+# block and therefore temporarily enable asynchronous cancellation.
+# Those must be compiled asynchronous unwind tables.
 CFLAGS-pthread_testcancel.c = -fexceptions
 CFLAGS-pthread_join.c = -fexceptions -fasynchronous-unwind-tables
 CFLAGS-pthread_timedjoin.c = -fexceptions -fasynchronous-unwind-tables
 CFLAGS-pthread_cond_wait.c = -fexceptions -fasynchronous-unwind-tables
 CFLAGS-pthread_cond_timedwait.c = -fexceptions -fasynchronous-unwind-tables
-CFLAGS-pthread_cancel.c = -fexceptions -fasynchronous-unwind-tables
-CFLAGS-cancellation.c = -fasynchronous-unwind-tables
-CFLAGS-libc-cancellation.c = -fasynchronous-unwind-tables
+CFLAGS-sem_wait.c = -fexceptions -fasynchronous-unwind-tables
+CFLAGS-sem_timedwait.c = -fexceptions -fasynchronous-unwind-tables
 
 # Don't generate deps for calls with no sources.  See sysdeps/unix/Makefile.
 omit-deps = $(unix-syscalls:%=ptw-%)
@@ -165,7 +191,7 @@ tests = tst-attr1 tst-attr2 \
        tst-atfork1 \
        tst-cancel1 tst-cancel2 tst-cancel3 tst-cancel4 tst-cancel5 \
        tst-cancel6 tst-cancel7 tst-cancel8 tst-cancel9 tst-cancel10 \
-       tst-cancel11 \
+       tst-cancel11 tst-cancel12 tst-cancel13 tst-cancel14 tst-cancel15 \
        tst-cleanup0 tst-cleanup1 tst-cleanup2 tst-cleanup3 \
        tst-flock1 tst-flock2 \
        tst-signal1 tst-signal2 tst-signal3 tst-signal4 tst-signal5 \
@@ -192,6 +218,12 @@ LDFLAGS-pthread.so = -Wl,--enable-new-dtags,-z,nodelete,-z,initfirst
 
 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-cleanupx0 tst-cleanupx1 tst-cleanupx2 tst-cleanupx3
+endif
 ifeq ($(build-shared),yes)
 tests += tst-atfork2 tst-tls3
 endif
@@ -292,6 +324,23 @@ CFLAGS-pthread_self.os += -fomit-frame-pointer
 
 CFLAGS-tst-unload.c += -DPREFIX=\"$(objpfx)\"
 
+# Run the cancellation and cleanup tests also for the modern, exception-based
+# implementation.  For this we have to pass the -fexceptions parameter.
+CFLAGS-tst-cancelx2.c += -fexceptions
+CFLAGS-tst-cancelx3.c += -fexceptions
+CFLAGS-tst-cancelx4.c += -fexceptions
+CFLAGS-tst-cancelx5.c += -fexceptions
+CFLAGS-tst-cancelx6.c += -fexceptions
+CFLAGS-tst-cancelx7.c += -fexceptions
+CFLAGS-tst-cancelx8.c += -fexceptions
+CFLAGS-tst-cancelx9.c += -fexceptions
+CFLAGS-tst-cancelx10.c += -fexceptions
+CFLAGS-tst-cancelx11.c += -fexceptions
+CFLAGS-tst-cleanupx0.c += -fexceptions -fasynchronous-unwind-tables
+CFLAGS-tst-cleanupx1.c += -fexceptions -fasynchronous-unwind-tables
+CFLAGS-tst-cleanupx2.c += -fexceptions
+CFLAGS-tst-cleanupx3.c += -fexceptions
+
 tst-cancel7-ARGS = --command "$(built-program-cmd)"
 tst-umask1-ARGS = $(objpfx)tst-umask1.temp
 
index c602d5e..a8fa3c8 100644 (file)
@@ -216,6 +216,7 @@ libpthread {
     __pthread_register_cancel; __pthread_unregister_cancel;
     __pthread_register_cancel_defer; __pthread_unregister_cancel_restore;
     __pthread_unwind_next;
+    __pthread_cleanup_routine;
 
     # New affinity interfaces.
     pthread_getaffinity_np; pthread_setaffinity_np;
diff --git a/nptl/cleanup_routine.c b/nptl/cleanup_routine.c
new file mode 100644 (file)
index 0000000..cbf2318
--- /dev/null
@@ -0,0 +1,28 @@
+/* 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 <pthread.h>
+
+
+void
+__pthread_cleanup_routine (struct __pthread_cleanup_frame *f)
+{
+  if (f->__do_it)
+    f->__cancel_routine (f->__cancel_arg);
+}
index 12cb6f0..a83c3c9 100644 (file)
@@ -1,7 +1,10 @@
 #include <sysdep.h>
 #include <tls.h>
 
+RESULT                 offsetof (struct pthread, result)
 TID                    offsetof (struct pthread, tid)
+CANCELHANDLING         offsetof (struct pthread, cancelhandling)
+CLEANUP_JMP_BUF                offsetof (struct pthread, cleanup_jmp_buf)
 MULTIPLE_THREADS_OFFSET        offsetof (tcbhead_t, multiple_threads)
 SYSINFO_OFFSET         offsetof (tcbhead_t, sysinfo)
 CLEANUP                        offsetof (struct pthread, cleanup)
index c0375ae..1f0a34b 100644 (file)
@@ -419,14 +419,132 @@ typedef struct
 #endif
 
 
+/* Structure to hold the cleanup handler information.  */
+struct __pthread_cleanup_frame
+{
+  void (*__cancel_routine) (void *);
+  void *__cancel_arg;
+  int __do_it;
+  int __cancel_type;
+};
+
+#if defined __GNUC__ && defined __EXCEPTIONS
+# ifdef __cplusplus
+/* Class to handle cancellation handler invocation.  */
+class __pthread_cleanup_class
+{
+  void (*__cancel_routine) (void *);
+  void *__cancel_arg;
+  int __do_it;
+  int __cancel_type;
+
+ public:
+  __pthread_cleanup_class (void (*__fct) (void *), void *__arg)
+    : __cancel_routine (__fct), __cancel_arg (__arg), __do_it (1) { }
+  ~__pthread_cleanup_class () { if (__do_it) __cancel_routine (__cancel_arg); }
+  __setdoit (int __newval) { __do_it = __newval; }
+  __defer () { pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED,
+                                     &__cancel_type);
+  __restore () const { pthread_setcanceltype (__cancel_type, 0);
+};
+
+/* Install a cleanup handler: ROUTINE will be called with arguments ARG
+   when the thread is canceled or calls pthread_exit.  ROUTINE will also
+   be called with arguments ARG when the matching pthread_cleanup_pop
+   is executed with non-zero EXECUTE argument.
+
+   pthread_cleanup_push and pthread_cleanup_pop are macros and must always
+   be used in matching pairs at the same nesting level of braces.  */
+#  define pthread_cleanup_push(routine, arg) \
+  do {                                                                       \
+    __pthread_cleanup_class __clframe (routine, arg)
+
+/* Remove a cleanup handler installed by the matching pthread_cleanup_push.
+   If EXECUTE is non-zero, the handler function is called. */
+#  define pthread_cleanup_pop(execute) \
+    __clframe.__setdoit (execute);                                           \
+  } while (0)
+
+#  ifdef __USE_GNU
+/* Install a cleanup handler as pthread_cleanup_push does, but also
+   saves the current cancellation type and sets it to deferred
+   cancellation.  */
+#   define pthread_cleanup_push_defer_np(routine, arg) \
+  do {                                                                       \
+    __pthread_cleanup_class __clframe (routine, arg);                        \
+    __clframe.__defer ()
+
+/* Remove a cleanup handler as pthread_cleanup_pop does, but also
+   restores the cancellation type that was in effect when the matching
+   pthread_cleanup_push_defer was called.  */
+#   define pthread_cleanup_pop_restore_np(execute) \
+    __clframe.__restore ();                                                  \
+    __clframe.__setdoit (execute);                                           \
+  } while (0)
+#  endif
+# else
+/* Function called to call the cleanup handler.  As an extern inline
+   function the compiler is free to decide inlining the change when
+   needed or fall back on the copy which must exist somewhere
+   else.  */
+extern inline void
+__pthread_cleanup_routine (struct __pthread_cleanup_frame *__frame)
+{
+  if (__frame->__do_it)
+    __frame->__cancel_routine (__frame->__cancel_arg);
+}
+
 /* Install a cleanup handler: ROUTINE will be called with arguments ARG
-   when the thread is cancelled or calls pthread_exit.  ROUTINE will also
+   when the thread is canceled or calls pthread_exit.  ROUTINE will also
    be called with arguments ARG when the matching pthread_cleanup_pop
    is executed with non-zero EXECUTE argument.
 
    pthread_cleanup_push and pthread_cleanup_pop are macros and must always
    be used in matching pairs at the same nesting level of braces.  */
-#define pthread_cleanup_push(routine, arg) \
+#  define pthread_cleanup_push(routine, arg) \
+  do {                                                                       \
+    struct __pthread_cleanup_frame __clframe                                 \
+      __attribute__ ((__cleanup__ (__pthread_cleanup_routine)))                      \
+      = { .__cancel_routine = (routine), .__cancel_arg = (arg),                      \
+         .__do_it = 1 };
+
+/* Remove a cleanup handler installed by the matching pthread_cleanup_push.
+   If EXECUTE is non-zero, the handler function is called. */
+#  define pthread_cleanup_pop(execute) \
+    __clframe.__do_it = (execute);                                           \
+  } while (0)
+
+#  ifdef __USE_GNU
+/* Install a cleanup handler as pthread_cleanup_push does, but also
+   saves the current cancellation type and sets it to deferred
+   cancellation.  */
+#   define pthread_cleanup_push_defer_np(routine, arg) \
+  do {                                                                       \
+    struct __pthread_cleanup_frame __clframe                                 \
+      __attribute__ ((__cleanup__ (__pthread_cleanup_routine)))                      \
+      = { .__cancel_routine = (routine), .__cancel_arg = (arg),                      \
+         .__do_it = 1 };                                                     \
+    (void) pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED,                   \
+                                 &__clframe.__cancel_type)
+
+/* Remove a cleanup handler as pthread_cleanup_pop does, but also
+   restores the cancellation type that was in effect when the matching
+   pthread_cleanup_push_defer was called.  */
+#   define pthread_cleanup_pop_restore_np(execute) \
+    (void) pthread_setcanceltype (__clframe.__cancel_type, NULL);            \
+    __clframe.__do_it = (execute);                                           \
+  } while (0)
+#  endif
+# endif
+#else
+/* Install a cleanup handler: ROUTINE will be called with arguments ARG
+   when the thread is canceled or calls pthread_exit.  ROUTINE will also
+   be called with arguments ARG when the matching pthread_cleanup_pop
+   is executed with non-zero EXECUTE argument.
+
+   pthread_cleanup_push and pthread_cleanup_pop are macros and must always
+   be used in matching pairs at the same nesting level of braces.  */
+# define pthread_cleanup_push(routine, arg) \
   do {                                                                       \
     __pthread_unwind_buf_t __cancel_buf;                                     \
     void (*__cancel_routine) (void *) = (routine);                           \
@@ -447,7 +565,7 @@ extern void __pthread_register_cancel (__pthread_unwind_buf_t *__buf)
 
 /* Remove a cleanup handler installed by the matching pthread_cleanup_push.
    If EXECUTE is non-zero, the handler function is called. */
-#define pthread_cleanup_pop(execute) \
+# define pthread_cleanup_pop(execute) \
     } while (0);                                                             \
     __pthread_unregister_cancel (&__cancel_buf);                             \
     if (execute)                                                             \
@@ -456,11 +574,11 @@ extern void __pthread_register_cancel (__pthread_unwind_buf_t *__buf)
 extern void __pthread_unregister_cancel (__pthread_unwind_buf_t *__buf)
   __cleanup_fct_attribute;
 
-#ifdef __USE_GNU
+# ifdef __USE_GNU
 /* Install a cleanup handler as pthread_cleanup_push does, but also
    saves the current cancellation type and sets it to deferred
    cancellation.  */
-# define pthread_cleanup_push_defer(routine, arg) \
+#  define pthread_cleanup_push_defer_np(routine, arg) \
   do {                                                                       \
     __pthread_unwind_buf_t __cancel_buf;                                     \
     void (*__cancel_routine) (void *) = (routine);                           \
@@ -482,7 +600,7 @@ extern void __pthread_register_cancel_defer (__pthread_unwind_buf_t *__buf)
 /* Remove a cleanup handler as pthread_cleanup_pop does, but also
    restores the cancellation type that was in effect when the matching
    pthread_cleanup_push_defer was called.  */
-# define pthread_cleanup_pop_cleanup(execute) \
+#  define pthread_cleanup_pop_restore_np(execute) \
     } while (0);                                                             \
     __pthread_unregister_cancel_restore (&__cancel_buf);                     \
     if (execute)                                                             \
@@ -490,15 +608,16 @@ extern void __pthread_register_cancel_defer (__pthread_unwind_buf_t *__buf)
   } while (0)
 extern void __pthread_unregister_cancel_restore (__pthread_unwind_buf_t *__buf)
   __cleanup_fct_attribute;
-#endif
+# endif
 
 /* Internal interface to initiate cleanup.  */
 extern void __pthread_unwind_next (__pthread_unwind_buf_t *__buf)
      __cleanup_fct_attribute __attribute ((__noreturn__))
-#ifndef SHARED
+# ifndef SHARED
      __attribute ((__weak__))
-#endif
+# endif
      ;
+#endif
 
 /* Function used in the macros.  */
 struct __jmp_buf_tag;
index aa3d745..9afe85f 100644 (file)
        .globl  sem_timedwait
        .type   sem_timedwait,@function
        .align  16
+       cfi_startproc
 sem_timedwait:
+       /* First check for cancellation.  */
+       movl    %gs:CANCELHANDLING, %eax
+       andl    $0xfffffff9, %eax
+       cmpl    $8, %eax
+       je      10f
+
        movl    4(%esp), %ecx
 
        movl    (%ecx), %eax
@@ -54,19 +61,28 @@ sem_timedwait:
 
        /* Check whether the timeout value is valid.  */
 1:     pushl   %esi
+       cfi_adjust_cfa_offset(4)
        pushl   %edi
+       cfi_adjust_cfa_offset(4)
        pushl   %ebx
-       subl    $8, %esp
+       cfi_adjust_cfa_offset(4)
+       subl    $12, %esp
+       cfi_adjust_cfa_offset(12)
 
-       movl    %esp, %esi
-       movl    28(%esp), %edi
+       movl    32(%esp), %edi
+       cfi_offset(7, -12)              /* %edi */
 
        /* Check for invalid nanosecond field.  */
        cmpl    $1000000000, 4(%edi)
-       movl    $EINVAL, %eax
+       movl    $EINVAL, %esi
+       cfi_offset(6, -8)               /* %esi */
        jae     6f
 
-7:     xorl    %ecx, %ecx
+       cfi_offset(3, -16)              /* %ebx */
+7:     call    __pthread_enable_asynccancel
+       movl    %eax, 8(%esp)
+
+       xorl    %ecx, %ecx
        movl    %esp, %ebx
        movl    %ecx, %edx
        movl    $SYS_gettimeofday, %eax
@@ -84,20 +100,25 @@ sem_timedwait:
        addl    $1000000000, %edx
        subl    $1, %ecx
 5:     testl   %ecx, %ecx
-       movl    $ETIMEDOUT, %eax
+       movl    $ETIMEDOUT, %esi
        js      6f              /* Time is already up.  */
 
        movl    %ecx, (%esp)    /* Store relative timeout.  */
        movl    %edx, 4(%esp)
-       movl    24(%esp), %ebx
+       movl    28(%esp), %ebx
        xorl    %ecx, %ecx
+       movl    %esp, %esi
        movl    $SYS_futex, %eax
        xorl    %edx, %edx
        ENTER_KERNEL
+       movl    %eax, %esi
+
+       movl    8(%esp), %eax
+       call    __pthread_disable_asynccancel
 
-       testl   %eax, %eax
+       testl   %esi, %esi
        je,pt   9f
-       cmpl    $-EWOULDBLOCK, %eax
+       cmpl    $-EWOULDBLOCK, %esi
        jne     3f
 
 9:     movl    (%ebx), %eax
@@ -109,14 +130,27 @@ sem_timedwait:
        cmpxchgl %ecx, (%ebx)
        jne,pn  8b
 
-       addl    $8, %esp
+       addl    $12, %esp
+       cfi_adjust_cfa_offset(-12)
        xorl    %eax, %eax
        popl    %ebx
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(3)
        popl    %edi
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(7)
        popl    %esi
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(6)
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(6)
        ret
 
-3:     negl    %eax
+       cfi_adjust_cfa_offset(24)
+       cfi_offset(6, -8)               /* %esi */
+       cfi_offset(7, -12)              /* %edi */
+       cfi_offset(3, -16)              /* %ebx */
+3:     negl    %esi
 6:
 #ifdef PIC
        call    __i686.get_pc_thunk.bx
@@ -128,17 +162,31 @@ sem_timedwait:
 #if USE___THREAD
        movl    %gs:0, %edx
        subl    errno@gottpoff(%ebx), %edx
-       movl    %eax, (%edx)
+       movl    %esi, (%edx)
 #else
-       movl    %eax, %edx
        call    __errno_location@plt
-       movl    %edx, (%eax)
+       movl    %esi, (%eax)
 #endif
 
-       addl    $8, %esp
+       addl    $12, %esp
+       cfi_adjust_cfa_offset(-12)
        orl     $-1, %eax
        popl    %ebx
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(3)
        popl    %edi
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(7)
        popl    %esi
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(6)
        ret
+
+10:    /* Canceled.  */
+       movl    $0xffffffff, %gs:RESULT
+       LOCK
+       orl     $0x10, %gs:CANCELHANDLING
+       movl    %gs:CLEANUP_JMP_BUF, %eax
+       jmp     __pthread_unwind
+       cfi_endproc
        .size   sem_timedwait,.-sem_timedwait
index eb01ca8..ba4f54c 100644 (file)
        .globl  __new_sem_wait
        .type   __new_sem_wait,@function
        .align  16
+       cfi_startproc
 __new_sem_wait:
+       /* First check for cancellation.  */
+       movl    %gs:CANCELHANDLING, %eax
+       andl    $0xfffffff9, %eax
+       cmpl    $8, %eax
+       je      5f
+
        pushl   %ebx
+       cfi_adjust_cfa_offset(4)
        pushl   %esi
+       cfi_adjust_cfa_offset(4)
+       subl    $4, %esp
+       cfi_adjust_cfa_offset(4)
 
-       movl    12(%esp), %ebx
+       movl    16(%esp), %ebx
+       cfi_offset(3, -8)               /* %ebx */
 
+       cfi_offset(6, -12)              /* %esi */
 3:     movl    (%ebx), %eax
 2:     testl   %eax, %eax
        je,pn   1f
@@ -52,21 +65,35 @@ __new_sem_wait:
        jne,pn  2b
        xorl    %eax, %eax
 
-       popl    %esi
-       popl    %ebx
+       movl    4(%esp), %esi
+       cfi_restore(6)
+       movl    8(%esp), %ebx
+       cfi_restore(3)
+       addl    $12, %esp
+       cfi_adjust_cfa_offset(-12)
        ret
 
-1:     xorl    %esi, %esi
+       cfi_adjust_cfa_offset(8)
+       cfi_offset(3, -8)               /* %ebx */
+       cfi_offset(6, -12)              /* %esi */
+1:     call    __pthread_enable_asynccancel
+       movl    %eax, (%esp)
+
+       xorl    %esi, %esi
        movl    $SYS_futex, %eax
        movl    %esi, %ecx
        movl    %esi, %edx
        ENTER_KERNEL
+       movl    %eax, %esi
+
+       movl    (%esp), %eax
+       call    __pthread_disable_asynccancel
 
-       testl   %eax, %eax
+       testl   %esi, %esi
        je      3b
-       cmpl    $-EWOULDBLOCK, %eax
+       cmpl    $-EWOULDBLOCK, %esi
        je      3b
-       negl    %eax
+       negl    %esi
 #ifdef PIC
        call    __i686.get_pc_thunk.bx
 #else
@@ -77,16 +104,27 @@ __new_sem_wait:
 #if USE___THREAD
        movl    %gs:0, %edx
        subl    errno@gottpoff(%ebx), %edx
-       movl    %eax, (%edx)
+       movl    %esi, (%edx)
 #else
-       movl    %eax, %edx
        call    __errno_location@plt
-       movl    %edx, (%eax)
+       movl    %esi, (%eax)
 #endif
        orl     $-1, %eax
-       popl    %esi
-       popl    %ebx
+       movl    4(%esp), %esi
+       cfi_restore(6)
+       movl    8(%esp), %ebx
+       cfi_restore(3)
+       addl    $12, %esp
+       cfi_adjust_cfa_offset(-12)
        ret
+
+5:     /* Canceled.  */
+       movl    $0xffffffff, %gs:RESULT
+       LOCK
+       orl     $0x10, %gs:CANCELHANDLING
+       movl    %gs:CLEANUP_JMP_BUF, %eax
+       jmp     __pthread_unwind
+       cfi_endproc
        .size   __new_sem_wait,.-__new_sem_wait
        versioned_symbol(libpthread, __new_sem_wait, sem_wait, GLIBC_2_1)
 #if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1)
index 8a65ce2..ef897c1 100644 (file)
 #include <internaltypes.h>
 #include <semaphore.h>
 
+#include <pthreadP.h>
 #include <shlib-compat.h>
 
 
 int
 sem_timedwait (sem_t *sem, const struct timespec *abstime)
 {
+  /* First check for cancellation.  */
+  CANCELLATION_P (THREAD_SELF);
+
   int *futex = (int *) sem;
   int val;
   int err;
@@ -71,7 +75,15 @@ sem_timedwait (sem_t *sem, const struct timespec *abstime)
       /* Do wait.  */
       rt.tv_sec = sec;
       rt.tv_nsec = nsec;
+
+      /* Enable asynchronous cancellation.  Required by the standard.  */
+      int oldtype = __pthread_enable_asynccancel ();
+
       err = lll_futex_timed_wait (futex, 0, &rt);
+
+      /* Disable asynchronous cancellation.  */
+      __pthread_disable_asynccancel (oldtype);
+
       if (err != 0 && err != -EWOULDBLOCK)
        goto error_return;
 
index 1d39b7c..36bb158 100644 (file)
 #include <internaltypes.h>
 #include <semaphore.h>
 
+#include <pthreadP.h>
 #include <shlib-compat.h>
 
 
 int
 __new_sem_wait (sem_t *sem)
 {
+  /* First check for cancellation.  */
+  CANCELLATION_P (THREAD_SELF);
+
   int *futex = (int *) sem;
   int val;
   int err;
@@ -43,7 +47,13 @@ __new_sem_wait (sem_t *sem)
            return 0;
        }
 
+      /* Enable asynchronous cancellation.  Required by the standard.  */
+      int oldtype = __pthread_enable_asynccancel ();
+
       err = lll_futex_wait (futex, 0);
+
+      /* Disable asynchronous cancellation.  */
+      __pthread_disable_asynccancel (oldtype);
     }
   while (err == 0 || err == -EWOULDBLOCK);
 
index 29bc1bc..7626d7b 100644 (file)
        .globl  sem_timedwait
        .type   sem_timedwait,@function
        .align  16
+       cfi_startproc
 sem_timedwait:
+       /* First check for cancellation.  */
+       movl    %fs:CANCELHANDLING, %eax
+       andl    $0xfffffff9, %eax
+       cmpl    $8, %eax
+       je      11f
+
        movl    (%rdi), %eax
 2:     testl   %eax, %eax
        je      1f
@@ -53,18 +60,29 @@ sem_timedwait:
 
        /* Check whether the timeout value is valid.  */
 1:     pushq   %r12
+       cfi_adjust_cfa_offset(8)
        pushq   %r13
-       subq    $16, %rsp
+       cfi_adjust_cfa_offset(8)
+       pushq   %r14
+       cfi_adjust_cfa_offset(8)
+       subq    $24, %rsp
+       cfi_adjust_cfa_offset(24)
 
        movq    %rdi, %r12
+       cfi_offset(12, -16)             /* %r12 */
        movq    %rsi, %r13
+       cfi_offset(13, -24)             /* %r13 */
 
        /* Check for invalid nanosecond field.  */
        cmpq    $1000000000, 8(%r13)
-       movl    $EINVAL, %eax
+       movl    $EINVAL, %r14d
+       cfi_offset(14, -24)             /* %r14 */
        jae     6f
 
-7:     xorq    %rsi, %rsi
+7:     call    __pthread_enable_asynccancel
+       movl    %eax, 16(%rsp)
+
+       xorq    %rsi, %rsi
        movq    %rsp, %rdi
        movq    $VSYSCALL_ADDR_vgettimeofday, %rax
        callq   *%rax
@@ -74,14 +92,14 @@ sem_timedwait:
        movq    $1000, %rdi
        mul     %rdi            /* Milli seconds to nano seconds.  */
        movq    (%r13), %rdi
-       movq    8(%r13), %rdi
+       movq    8(%r13), %rsi
        subq    (%rsp), %rdi
-       subq    %rax, %rdi
+       subq    %rax, %rsi
        jns     5f
        addq    $1000000000, %rsi
        decq    %rdi
 5:     testq   %rdi, %rdi
-       movl    $ETIMEDOUT, %eax
+       movl    $ETIMEDOUT, %r14d
        js      6f              /* Time is already up.  */
 
        movq    %rdi, (%rsp)    /* Store relative timeout.  */
@@ -93,38 +111,65 @@ sem_timedwait:
        movq    $SYS_futex, %rax
        xorl    %edx, %edx
        syscall
+       movq    %rax, %r14
 
-       testq   %rax, %rax
+       movl    16(%rsp), %edi
+       call    __pthread_disable_asynccancel
+
+       testq   %r14, %r14
        je      9f
-       cmpq    $-EWOULDBLOCK, %rax
+       cmpq    $-EWOULDBLOCK, %r14
        jne     3f
 
-9:     movl    (%rdi), %eax
+9:     movl    (%r12), %eax
 8:     testl   %eax, %eax
        je      7b
 
        leaq    -1(%rax), %rcx
        LOCK
-       cmpxchgl %ecx, (%rdi)
+       cmpxchgl %ecx, (%r12)
        jne     8b
 
        xorl    %eax, %eax
-10:    addq    $16, %rsp
+10:    addq    $24, %rsp
+       cfi_adjust_cfa_offset(-24)
+       popq    %r14
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(14)
        popq    %r13
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(13)
        popq    %r12
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(12)
        retq
 
-3:     negq    %rax
+       cfi_adjust_cfa_offset(48)
+       cfi_offset(12, -16)             /* %r12 */
+       cfi_offset(13, -24)             /* %r13 */
+       cfi_offset(14, -32)             /* %r14 */
+3:     negq    %r14
 6:
 #if USE___THREAD
        movq    errno@gottpoff(%rip), %rdx
-       movl    %eax, %fs:(%rdx)
+       movl    %r14d, %fs:(%rdx)
 #else
-       movl    %eax, %edx
        callq   __errno_location@plt
-       movl    %edx, (%rax)
+       movl    %r14d, (%rax)
 #endif
 
        orl     $-1, %eax
        jmp     10b
+       cfi_adjust_cfa_offset(-48)
+       cfi_restore(14)
+       cfi_restore(13)
+       cfi_restore(12)
+
+11:    /* Canceled.  */
+       movq    $0xffffffffffffffff, %fs:RESULT
+       LOCK
+       orl     $0x10, %fs:CANCELHANDLING
+       movq    %fs:CLEANUP_JMP_BUF, %rdi
+       jmp     __pthread_unwind
+       cfi_endproc
        .size   sem_timedwait,.-sem_timedwait
index 877ee4c..3274230 100644 (file)
        .globl  sem_wait
        .type   sem_wait,@function
        .align  16
+       cfi_startproc
 sem_wait:
-3:     movl    (%rdi), %eax
+       /* First check for cancellation.  */
+       movl    %fs:CANCELHANDLING, %eax
+       andl    $0xfffffff9, %eax
+       cmpl    $8, %eax
+       je      4f
+
+       pushq   %r12
+       cfi_adjust_cfa_offset(8)
+       cfi_offset(12, -16)
+       pushq   %r13
+       cfi_adjust_cfa_offset(8)
+       movq    %rdi, %r13
+       cfi_offset(13, -24)
+
+3:     movl    (%r13), %eax
 2:     testl   %eax, %eax
        je      1f
 
        leaq    -1(%rax), %rdx
        LOCK
-       cmpxchgl %edx, (%rdi)
+       cmpxchgl %edx, (%r13)
        jne     2b
        xorl    %eax, %eax
 
+       popq    %r13
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(13)
+       popq    %r12
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(12)
+
        retq
 
-1:     xorq    %r10, %r10
+       cfi_adjust_cfa_offset(16)
+       cfi_offset(12, -16)
+       cfi_offset(13, -24)
+1:     call    __pthread_enable_asynccancel
+       movl    %eax, %r8d
+
+       xorq    %r10, %r10
        movq    $SYS_futex, %rax
+       movq    %r13, %rdi
        movq    %r10, %rsi
        movq    %r10, %rdx
        syscall
+       movq    %rax, %r12
+
+       movl    %r8d, %edi
+       call    __pthread_disable_asynccancel
 
-       testq   %rax, %rax
+       testq   %r12, %r12
        je      3b
-       cmpq    $-EWOULDBLOCK, %rax
+       cmpq    $-EWOULDBLOCK, %r12
        je      3b
-       negq    %rax
+       negq    %r12
 #if USE___THREAD
        movq    errno@gottpoff(%rip), %rdx
-       movl    %eax, %fs:(%rdx)
+       movl    %r12d, %fs:(%rdx)
 #else
-       movl    %eax, %edx
        callq   __errno_location@plt
-       movl    %edx, (%rax)
+       movl    %r12d, (%rax)
 #endif
        orl     $-1, %eax
+
+       popq    %r13
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(13)
+       popq    %r12
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(12)
+
        retq
+
+4:     /* Canceled.  */
+       movq    $0xffffffffffffffff, %fs:RESULT
+       LOCK
+       orl     $0x10, %fs:CANCELHANDLING
+       movq    %fs:CLEANUP_JMP_BUF, %rdi
+       jmp     __pthread_unwind
+       cfi_endproc
        .size   sem_wait,.-sem_wait
index e230e3d..dc6e5c4 100644 (file)
@@ -1,7 +1,10 @@
 #include <sysdep.h>
 #include <tls.h>
 
+RESULT                 offsetof (struct pthread, result)
 TID                    offsetof (struct pthread, tid)
+CANCELHANDLING         offsetof (struct pthread, cancelhandling)
+CLEANUP_JMP_BUF                offsetof (struct pthread, cleanup_jmp_buf)
 CLEANUP                        offsetof (struct pthread, cleanup)
 CLEANUP_PREV           offsetof (struct _pthread_cleanup_buffer, __prev)
 MUTEX_FUTEX            offsetof (pthread_mutex_t, __data.__lock)
index 654c8a7..690319d 100644 (file)
@@ -63,6 +63,8 @@ tf (void *arg)
       printf ("setcanceltype failed: %s\n", strerror (err));
       exit (1);
     }
+  /* The following code is not standard compliant: the mutex functions
+     must not be called with asynchronous cancellation enabled.  */
 
   err = pthread_mutex_unlock (&m2);
   if (err != 0)
diff --git a/nptl/tst-cancel12.c b/nptl/tst-cancel12.c
new file mode 100644 (file)
index 0000000..6fdf5cf
--- /dev/null
@@ -0,0 +1,127 @@
+/* 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 <semaphore.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+
+static pthread_barrier_t bar;
+static sem_t sem;
+
+
+static void
+cleanup (void *arg)
+{
+  static int ncall;
+
+  if (++ncall != 1)
+    {
+      puts ("second call to cleanup");
+      exit (1);
+    }
+
+  printf ("cleanup call #%d\n", ncall);
+}
+
+
+static void *
+tf (void *arg)
+{
+  pthread_cleanup_push (cleanup, NULL);
+
+  int e = pthread_barrier_wait (&bar);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("tf: 1st barrier_wait failed");
+      exit (1);
+    }
+
+  /* This call should block and be cancelable.  */
+  sem_wait (&sem);
+
+  pthread_cleanup_pop (0);
+
+  puts ("sem_wait returned");
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_t th;
+
+  if (pthread_barrier_init (&bar, NULL, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      exit (1);
+    }
+
+  if (sem_init (&sem, 0, 1) != 0)
+    {
+      puts ("sem_init failed");
+      exit (1);
+    }
+
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("create failed");
+      exit (1);
+    }
+
+  /* Check whether cancellation is honored even before sem_wait does
+     anything.  */
+  if (pthread_cancel (th) != 0)
+    {
+      puts ("1st cancel failed");
+      exit (1);
+    }
+
+  int e = pthread_barrier_wait (&bar);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("1st barrier_wait failed");
+      exit (1);
+    }
+
+  void *r;
+  if (pthread_join (th, &r) != 0)
+    {
+      puts ("join failed");
+      exit (1);
+    }
+
+  if (r != PTHREAD_CANCELED)
+    {
+      puts ("thread not canceled");
+      exit (1);
+    }
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-cancel13.c b/nptl/tst-cancel13.c
new file mode 100644 (file)
index 0000000..66ab455
--- /dev/null
@@ -0,0 +1,129 @@
+/* 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 <semaphore.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+
+static pthread_barrier_t bar;
+static sem_t sem;
+
+
+static void
+cleanup (void *arg)
+{
+  static int ncall;
+
+  if (++ncall != 1)
+    {
+      puts ("second call to cleanup");
+      exit (1);
+    }
+
+  printf ("cleanup call #%d\n", ncall);
+}
+
+
+static void *
+tf (void *arg)
+{
+  pthread_cleanup_push (cleanup, NULL);
+
+  int e = pthread_barrier_wait (&bar);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("tf: 1st barrier_wait failed");
+      exit (1);
+    }
+
+  /* This call should block and be cancelable.  */
+  sem_wait (&sem);
+
+  pthread_cleanup_pop (0);
+
+  puts ("sem_wait returned");
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_t th;
+
+  if (pthread_barrier_init (&bar, NULL, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      exit (1);
+    }
+
+  if (sem_init (&sem, 0, 0) != 0)
+    {
+      puts ("sem_init failed");
+      exit (1);
+    }
+
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("create failed");
+      exit (1);
+    }
+
+  int e = pthread_barrier_wait (&bar);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("1st barrier_wait failed");
+      exit (1);
+    }
+
+  /* Give the child a chance to go to sleep in sem_wait.  */
+  sleep (1);
+
+  /* Check whether cancellation is honored when waiting in sem_wait.  */
+  if (pthread_cancel (th) != 0)
+    {
+      puts ("1st cancel failed");
+      exit (1);
+    }
+
+  void *r;
+  if (pthread_join (th, &r) != 0)
+    {
+      puts ("join failed");
+      exit (1);
+    }
+
+  if (r != PTHREAD_CANCELED)
+    {
+      puts ("thread not canceled");
+      exit (1);
+    }
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-cancel14.c b/nptl/tst-cancel14.c
new file mode 100644 (file)
index 0000000..bc830dd
--- /dev/null
@@ -0,0 +1,136 @@
+/* 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 <semaphore.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+
+static pthread_barrier_t bar;
+static sem_t sem;
+
+
+static void
+cleanup (void *arg)
+{
+  static int ncall;
+
+  if (++ncall != 1)
+    {
+      puts ("second call to cleanup");
+      exit (1);
+    }
+
+  printf ("cleanup call #%d\n", ncall);
+}
+
+
+static void *
+tf (void *arg)
+{
+  pthread_cleanup_push (cleanup, NULL);
+
+  int e = pthread_barrier_wait (&bar);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("tf: 1st barrier_wait failed");
+      exit (1);
+    }
+
+  struct timeval tv;
+  (void) gettimeofday (&tv, NULL);
+
+  struct timespec ts;
+  TIMEVAL_TO_TIMESPEC (&tv, &ts);
+
+  /* Timeout in 5 seconds.  */
+  ts.tv_sec += 5;
+
+  /* This call should block and be cancelable.  */
+  sem_timedwait (&sem, &ts);
+
+  pthread_cleanup_pop (0);
+
+  puts ("sem_timedwait returned");
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_t th;
+
+  if (pthread_barrier_init (&bar, NULL, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      exit (1);
+    }
+
+  if (sem_init (&sem, 0, 1) != 0)
+    {
+      puts ("sem_init failed");
+      exit (1);
+    }
+
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("create failed");
+      exit (1);
+    }
+
+  /* Check whether cancellation is honored even before sem_timedwait does
+     anything.  */
+  if (pthread_cancel (th) != 0)
+    {
+      puts ("1st cancel failed");
+      exit (1);
+    }
+
+  int e = pthread_barrier_wait (&bar);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("1st barrier_wait failed");
+      exit (1);
+    }
+
+  void *r;
+  if (pthread_join (th, &r) != 0)
+    {
+      puts ("join failed");
+      exit (1);
+    }
+
+  if (r != PTHREAD_CANCELED)
+    {
+      puts ("thread not canceled");
+      exit (1);
+    }
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-cancel15.c b/nptl/tst-cancel15.c
new file mode 100644 (file)
index 0000000..88bacaf
--- /dev/null
@@ -0,0 +1,141 @@
+/* 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 <semaphore.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+
+static pthread_barrier_t bar;
+static sem_t sem;
+
+
+static void
+cleanup (void *arg)
+{
+  static int ncall;
+
+  if (++ncall != 1)
+    {
+      puts ("second call to cleanup");
+      exit (1);
+    }
+
+  printf ("cleanup call #%d\n", ncall);
+}
+
+
+static void *
+tf (void *arg)
+{
+  int e;
+
+  pthread_cleanup_push (cleanup, NULL);
+
+  e = pthread_barrier_wait (&bar);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("tf: 1st barrier_wait failed");
+      exit (1);
+    }
+
+  struct timeval tv;
+  (void) gettimeofday (&tv, NULL);
+
+  struct timespec ts;
+  TIMEVAL_TO_TIMESPEC (&tv, &ts);
+
+  /* Timeout in 5 seconds.  */
+  ts.tv_sec += 5;
+
+  /* This call should block and be cancelable.  */
+  errno = 0;
+  e = sem_timedwait (&sem, &ts);
+
+  pthread_cleanup_pop (0);
+
+  printf ("sem_timedwait returned, e = %d, errno = %d\n", e, errno);
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_t th;
+
+  if (pthread_barrier_init (&bar, NULL, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      exit (1);
+    }
+
+  if (sem_init (&sem, 0, 0) != 0)
+    {
+      puts ("sem_init failed");
+      exit (1);
+    }
+
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("create failed");
+      exit (1);
+    }
+
+  int e = pthread_barrier_wait (&bar);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("1st barrier_wait failed");
+      exit (1);
+    }
+
+  /* Give the child a chance to go to sleep in sem_wait.  */
+  sleep (1);
+
+  /* Check whether cancellation is honored when waiting in sem_timedwait.  */
+  if (pthread_cancel (th) != 0)
+    {
+      puts ("1st cancel failed");
+      exit (1);
+    }
+
+  void *r;
+  if (pthread_join (th, &r) != 0)
+    {
+      puts ("join failed");
+      exit (1);
+    }
+
+  if (r != PTHREAD_CANCELED)
+    {
+      puts ("thread not canceled");
+      exit (1);
+    }
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-cancelx1.c b/nptl/tst-cancelx1.c
new file mode 100644 (file)
index 0000000..594f095
--- /dev/null
@@ -0,0 +1 @@
+#include "tst-cancel1.c"
diff --git a/nptl/tst-cancelx10.c b/nptl/tst-cancelx10.c
new file mode 100644 (file)
index 0000000..e5bbb34
--- /dev/null
@@ -0,0 +1 @@
+#include "tst-cancel10.c"
diff --git a/nptl/tst-cancelx11.c b/nptl/tst-cancelx11.c
new file mode 100644 (file)
index 0000000..ffcc2ee
--- /dev/null
@@ -0,0 +1 @@
+#include "tst-cancel11.c"
diff --git a/nptl/tst-cancelx12.c b/nptl/tst-cancelx12.c
new file mode 100644 (file)
index 0000000..f90ae61
--- /dev/null
@@ -0,0 +1 @@
+#include "tst-cancel12.c"
diff --git a/nptl/tst-cancelx13.c b/nptl/tst-cancelx13.c
new file mode 100644 (file)
index 0000000..37c4c39
--- /dev/null
@@ -0,0 +1 @@
+#include "tst-cancel13.c"
diff --git a/nptl/tst-cancelx14.c b/nptl/tst-cancelx14.c
new file mode 100644 (file)
index 0000000..ba4e775
--- /dev/null
@@ -0,0 +1 @@
+#include "tst-cancel14.c"
diff --git a/nptl/tst-cancelx15.c b/nptl/tst-cancelx15.c
new file mode 100644 (file)
index 0000000..005c1f6
--- /dev/null
@@ -0,0 +1 @@
+#include "tst-cancel15.c"
diff --git a/nptl/tst-cancelx2.c b/nptl/tst-cancelx2.c
new file mode 100644 (file)
index 0000000..95dc8a8
--- /dev/null
@@ -0,0 +1 @@
+#include "tst-cancel2.c"
diff --git a/nptl/tst-cancelx3.c b/nptl/tst-cancelx3.c
new file mode 100644 (file)
index 0000000..3937f10
--- /dev/null
@@ -0,0 +1 @@
+#include "tst-cancel3.c"
diff --git a/nptl/tst-cancelx4.c b/nptl/tst-cancelx4.c
new file mode 100644 (file)
index 0000000..1c879eb
--- /dev/null
@@ -0,0 +1 @@
+#include "tst-cancel4.c"
diff --git a/nptl/tst-cancelx5.c b/nptl/tst-cancelx5.c
new file mode 100644 (file)
index 0000000..c0a1884
--- /dev/null
@@ -0,0 +1 @@
+#include "tst-cancel5.c"
diff --git a/nptl/tst-cancelx6.c b/nptl/tst-cancelx6.c
new file mode 100644 (file)
index 0000000..6926e21
--- /dev/null
@@ -0,0 +1 @@
+#include "tst-cancel6.c"
diff --git a/nptl/tst-cancelx7.c b/nptl/tst-cancelx7.c
new file mode 100644 (file)
index 0000000..4df1a58
--- /dev/null
@@ -0,0 +1 @@
+#include "tst-cancel7.c"
diff --git a/nptl/tst-cancelx8.c b/nptl/tst-cancelx8.c
new file mode 100644 (file)
index 0000000..0555c7c
--- /dev/null
@@ -0,0 +1 @@
+#include "tst-cancel8.c"
diff --git a/nptl/tst-cancelx9.c b/nptl/tst-cancelx9.c
new file mode 100644 (file)
index 0000000..9d84663
--- /dev/null
@@ -0,0 +1 @@
+#include "tst-cancel9.c"
index b6efbf4..a73dee3 100644 (file)
@@ -38,10 +38,20 @@ ch (void *arg)
 }
 
 
+static void
+endfct (void)
+{
+  /* We force exit right here.  */
+  _exit (global);
+}
+
+
 static int
 do_test (void)
 {
-  pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+  atexit (endfct);
+
+  pthread_cancel (pthread_self ());
 
   pthread_cleanup_push (ch, (void *) 1l);
 
@@ -49,7 +59,7 @@ do_test (void)
 
   pthread_cleanup_push (ch, (void *) 3l);
 
-  pthread_cancel (pthread_self ());
+  pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
 
   pthread_cleanup_pop (1);
 
@@ -57,9 +67,10 @@ do_test (void)
 
   pthread_cleanup_pop (1);
 
-  return 0;
+  return 100;
 }
 
 
+#define EXPECTED_STATUS 9
 #define TEST_FUNCTION do_test ()
 #include "../test-skeleton.c"
index a6b6142..2230e0f 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
@@ -41,7 +41,7 @@ ch (void *arg)
 static void *
 tf (void *a)
 {
-  pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+  pthread_cancel (pthread_self ());
 
   pthread_cleanup_push (ch, (void *) 1l);
 
@@ -49,7 +49,7 @@ tf (void *a)
 
   pthread_cleanup_push (ch, (void *) 3l);
 
-  pthread_cancel (pthread_self ());
+  pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
 
   pthread_cleanup_pop (1);
 
diff --git a/nptl/tst-cleanupx0.c b/nptl/tst-cleanupx0.c
new file mode 100644 (file)
index 0000000..0012ab1
--- /dev/null
@@ -0,0 +1 @@
+#include "tst-cleanup0.c"
diff --git a/nptl/tst-cleanupx0.expect b/nptl/tst-cleanupx0.expect
new file mode 100644 (file)
index 0000000..4e3c581
--- /dev/null
@@ -0,0 +1,3 @@
+ch (3)
+ch (2)
+ch (1)
diff --git a/nptl/tst-cleanupx1.c b/nptl/tst-cleanupx1.c
new file mode 100644 (file)
index 0000000..21e9e58
--- /dev/null
@@ -0,0 +1 @@
+#include "tst-cleanup1.c"
diff --git a/nptl/tst-cleanupx2.c b/nptl/tst-cleanupx2.c
new file mode 100644 (file)
index 0000000..8b9e350
--- /dev/null
@@ -0,0 +1 @@
+#include "tst-cleanup2.c"
diff --git a/nptl/tst-cleanupx3.c b/nptl/tst-cleanupx3.c
new file mode 100644 (file)
index 0000000..90baf90
--- /dev/null
@@ -0,0 +1 @@
+#include "tst-cleanup3.c"