diff options
Diffstat (limited to 'nptl')
-rw-r--r-- | nptl/Makefile | 4 | ||||
-rw-r--r-- | nptl/pthreadP.h | 61 | ||||
-rw-r--r-- | nptl/pthread_once.c | 4 | ||||
-rw-r--r-- | nptl/tst-once5.cc | 4 |
4 files changed, 64 insertions, 9 deletions
diff --git a/nptl/Makefile b/nptl/Makefile index 5f85dd7..33766ea 100644 --- a/nptl/Makefile +++ b/nptl/Makefile @@ -386,10 +386,6 @@ xtests += tst-eintr1 test-srcs = tst-oddstacklimit -# Test expected to fail on most targets (except x86_64) due to bug -# 18435 - pthread_once hangs when init routine throws an exception. -test-xfail-tst-once5 = yes - gen-as-const-headers = unwindbuf.sym \ pthread-pi-defines.sym diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h index d2fd082..93f3cef 100644 --- a/nptl/pthreadP.h +++ b/nptl/pthreadP.h @@ -604,6 +604,67 @@ extern void __pthread_cleanup_pop (struct _pthread_cleanup_buffer *buffer, # undef pthread_cleanup_pop # define pthread_cleanup_pop(execute) \ __pthread_cleanup_pop (&_buffer, (execute)); } + +# if defined __EXCEPTIONS && !defined __cplusplus +/* Structure to hold the cleanup handler information. */ +struct __pthread_cleanup_combined_frame +{ + void (*__cancel_routine) (void *); + void *__cancel_arg; + int __do_it; + struct _pthread_cleanup_buffer __buffer; +}; + +/* Special cleanup macros which register cleanup both using + __pthread_cleanup_{push,pop} and using cleanup attribute. This is needed + for pthread_once, so that it supports both throwing exceptions from the + pthread_once callback (only cleanup attribute works there) and cancellation + of the thread running the callback if the callback or some routines it + calls don't have unwind information. */ + +static __always_inline void +__pthread_cleanup_combined_routine (struct __pthread_cleanup_combined_frame + *__frame) +{ + if (__frame->__do_it) + { + __frame->__cancel_routine (__frame->__cancel_arg); + __frame->__do_it = 0; + __pthread_cleanup_pop (&__frame->__buffer, 0); + } +} + +static inline void +__pthread_cleanup_combined_routine_voidptr (void *__arg) +{ + struct __pthread_cleanup_combined_frame *__frame + = (struct __pthread_cleanup_combined_frame *) __arg; + if (__frame->__do_it) + { + __frame->__cancel_routine (__frame->__cancel_arg); + __frame->__do_it = 0; + } +} + +# define pthread_cleanup_combined_push(routine, arg) \ + do { \ + void (*__cancel_routine) (void *) = (routine); \ + struct __pthread_cleanup_combined_frame __clframe \ + __attribute__ ((__cleanup__ (__pthread_cleanup_combined_routine))) \ + = { .__cancel_routine = __cancel_routine, .__cancel_arg = (arg), \ + .__do_it = 1 }; \ + __pthread_cleanup_push (&__clframe.__buffer, \ + __pthread_cleanup_combined_routine_voidptr, \ + &__clframe); + +# define pthread_cleanup_combined_pop(execute) \ + __pthread_cleanup_pop (&__clframe.__buffer, 0); \ + __clframe.__do_it = 0; \ + if (execute) \ + __cancel_routine (__clframe.__cancel_arg); \ + } while (0) + +# endif #endif extern void __pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *buffer, diff --git a/nptl/pthread_once.c b/nptl/pthread_once.c index 28d9709..7645da2 100644 --- a/nptl/pthread_once.c +++ b/nptl/pthread_once.c @@ -111,11 +111,11 @@ __pthread_once_slow (pthread_once_t *once_control, void (*init_routine) (void)) /* This thread is the first here. Do the initialization. Register a cleanup handler so that in case the thread gets interrupted the initialization can be restarted. */ - pthread_cleanup_push (clear_once_control, once_control); + pthread_cleanup_combined_push (clear_once_control, once_control); init_routine (); - pthread_cleanup_pop (0); + pthread_cleanup_combined_pop (0); /* Mark *once_control as having finished the initialization. We need diff --git a/nptl/tst-once5.cc b/nptl/tst-once5.cc index b797ab3..60fe1ef 100644 --- a/nptl/tst-once5.cc +++ b/nptl/tst-once5.cc @@ -59,7 +59,7 @@ do_test (void) " throwing an exception", stderr); } catch (OnceException) { - if (1 < niter) + if (niter > 1) fputs ("pthread_once unexpectedly threw", stderr); result = 0; } @@ -75,7 +75,5 @@ do_test (void) return result; } -// The test currently hangs and is XFAILed. Reduce the timeout. -#define TIMEOUT 1 #define TEST_FUNCTION do_test () #include "../test-skeleton.c" |