diff options
-rw-r--r-- | ChangeLog | 9 | ||||
-rw-r--r-- | nptl/pthreadP.h | 6 | ||||
-rw-r--r-- | nptl/pthread_once.c | 21 | ||||
-rw-r--r-- | sysdeps/nptl/fork.c | 3 |
4 files changed, 29 insertions, 10 deletions
diff --git a/ChangeLog b/ChangeLog index 19bef8aeff..8e3373cc06 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2014-10-20 Torvald Riegel <triegel@redhat.com> + + [BZ #15215] + * nptl/pthreadP.h (__PTHREAD_ONCE_INPROGRESS, __PTHREAD_ONCE_DONE, + __PTHREAD_ONCE_FORK_GEN_INCR): New. + * sysdeps/nptl/fork.c (__libc_fork): Use them. + * nptl/pthread_once.c (__pthread_once): Likewise. + Update comments. + 2014-10-20 Joseph Myers <joseph@codesourcery.com> [BZ #14138] diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h index d4415ba933..3aa24c283b 100644 --- a/nptl/pthreadP.h +++ b/nptl/pthreadP.h @@ -161,6 +161,12 @@ enum #define FUTEX_TID_MASK 0x3fffffff +/* pthread_once definitions. See __pthread_once for how these are used. */ +#define __PTHREAD_ONCE_INPROGRESS 1 +#define __PTHREAD_ONCE_DONE 2 +#define __PTHREAD_ONCE_FORK_GEN_INCR 4 + + /* Internal variables. */ diff --git a/nptl/pthread_once.c b/nptl/pthread_once.c index 10c01d6023..595bd7e298 100644 --- a/nptl/pthread_once.c +++ b/nptl/pthread_once.c @@ -40,8 +40,11 @@ clear_once_control (void *arg) /* This is similar to a lock implementation, but we distinguish between three - states: not yet initialized (0), initialization finished (2), and - initialization in progress (__fork_generation | 1). If in the first state, + states: not yet initialized (0), initialization in progress + (__fork_generation | __PTHREAD_ONCE_INPROGRESS), and initialization + finished (__PTHREAD_ONCE_DONE); __fork_generation does not use the bits + that are used for __PTHREAD_ONCE_INPROGRESS and __PTHREAD_ONCE_DONE (which + is what __PTHREAD_ONCE_FORK_GEN_INCR is used for). If in the first state, threads will try to run the initialization by moving to the second state; the first thread to do so via a CAS on once_control runs init_routine, other threads block. @@ -66,14 +69,14 @@ __pthread_once (once_control, init_routine) int oldval, val, newval; /* We need acquire memory order for this load because if the value - signals that initialization has finished, we need to be see any + signals that initialization has finished, we need to see any data modifications done during initialization. */ val = *once_control; atomic_read_barrier(); do { /* Check if the initialization has already been done. */ - if (__glibc_likely ((val & 2) != 0)) + if (__glibc_likely ((val & __PTHREAD_ONCE_DONE) != 0)) return 0; oldval = val; @@ -82,7 +85,7 @@ __pthread_once (once_control, init_routine) generation because it's immutable in a particular process, and forked child processes start with a single thread that modified the generation. */ - newval = __fork_generation | 1; + newval = __fork_generation | __PTHREAD_ONCE_INPROGRESS; /* We need acquire memory order here for the same reason as for the load from once_control above. */ val = atomic_compare_and_exchange_val_acq (once_control, newval, @@ -91,11 +94,11 @@ __pthread_once (once_control, init_routine) while (__glibc_unlikely (val != oldval)); /* Check if another thread already runs the initializer. */ - if ((oldval & 1) != 0) + if ((oldval & __PTHREAD_ONCE_INPROGRESS) != 0) { /* Check whether the initializer execution was interrupted by a - fork. We know that for both values, bit 0 is set and bit 1 is - not. */ + fork. We know that for both values, __PTHREAD_ONCE_INPROGRESS + is set and __PTHREAD_ONCE_DONE is not. */ if (oldval == newval) { /* Same generation, some other thread was faster. Wait. */ @@ -118,7 +121,7 @@ __pthread_once (once_control, init_routine) release memory order here because we need to synchronize with other threads that want to use the initialized data. */ atomic_write_barrier(); - *once_control = 2; + *once_control = __PTHREAD_ONCE_DONE; /* Wake up all other threads. */ lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE); diff --git a/sysdeps/nptl/fork.c b/sysdeps/nptl/fork.c index 511533aa60..a7dafa82ab 100644 --- a/sysdeps/nptl/fork.c +++ b/sysdeps/nptl/fork.c @@ -141,8 +141,9 @@ __libc_fork (void) assert (THREAD_GETMEM (self, tid) != ppid); + /* See __pthread_once. */ if (__fork_generation_pointer != NULL) - *__fork_generation_pointer += 4; + *__fork_generation_pointer += __PTHREAD_ONCE_FORK_GEN_INCR; /* Adjust the PID field for the new process. */ THREAD_SETMEM (self, pid, THREAD_GETMEM (self, tid)); |