1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-07-30 22:43:12 +03:00

pthread_once: Clean up constants.

[BZ #15215] This just gives a name to the integer constants being used.
This commit is contained in:
Torvald Riegel
2013-10-11 18:58:04 +03:00
parent 42b7f5d485
commit 63668b7084
4 changed files with 29 additions and 10 deletions

View File

@ -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> 2014-10-20 Joseph Myers <joseph@codesourcery.com>
[BZ #14138] [BZ #14138]

View File

@ -161,6 +161,12 @@ enum
#define FUTEX_TID_MASK 0x3fffffff #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. */ /* Internal variables. */

View File

@ -40,8 +40,11 @@ clear_once_control (void *arg)
/* This is similar to a lock implementation, but we distinguish between three /* This is similar to a lock implementation, but we distinguish between three
states: not yet initialized (0), initialization finished (2), and states: not yet initialized (0), initialization in progress
initialization in progress (__fork_generation | 1). If in the first state, (__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; 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, the first thread to do so via a CAS on once_control runs init_routine,
other threads block. other threads block.
@ -66,14 +69,14 @@ __pthread_once (once_control, init_routine)
int oldval, val, newval; int oldval, val, newval;
/* We need acquire memory order for this load because if the value /* 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. */ data modifications done during initialization. */
val = *once_control; val = *once_control;
atomic_read_barrier(); atomic_read_barrier();
do do
{ {
/* Check if the initialization has already been done. */ /* Check if the initialization has already been done. */
if (__glibc_likely ((val & 2) != 0)) if (__glibc_likely ((val & __PTHREAD_ONCE_DONE) != 0))
return 0; return 0;
oldval = val; oldval = val;
@ -82,7 +85,7 @@ __pthread_once (once_control, init_routine)
generation because it's immutable in a particular process, and generation because it's immutable in a particular process, and
forked child processes start with a single thread that modified forked child processes start with a single thread that modified
the generation. */ 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 /* We need acquire memory order here for the same reason as for the
load from once_control above. */ load from once_control above. */
val = atomic_compare_and_exchange_val_acq (once_control, newval, 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)); while (__glibc_unlikely (val != oldval));
/* Check if another thread already runs the initializer. */ /* 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 /* Check whether the initializer execution was interrupted by a
fork. We know that for both values, bit 0 is set and bit 1 is fork. We know that for both values, __PTHREAD_ONCE_INPROGRESS
not. */ is set and __PTHREAD_ONCE_DONE is not. */
if (oldval == newval) if (oldval == newval)
{ {
/* Same generation, some other thread was faster. Wait. */ /* 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 release memory order here because we need to synchronize with other
threads that want to use the initialized data. */ threads that want to use the initialized data. */
atomic_write_barrier(); atomic_write_barrier();
*once_control = 2; *once_control = __PTHREAD_ONCE_DONE;
/* Wake up all other threads. */ /* Wake up all other threads. */
lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE); lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);

View File

@ -141,8 +141,9 @@ __libc_fork (void)
assert (THREAD_GETMEM (self, tid) != ppid); assert (THREAD_GETMEM (self, tid) != ppid);
/* See __pthread_once. */
if (__fork_generation_pointer != NULL) 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. */ /* Adjust the PID field for the new process. */
THREAD_SETMEM (self, pid, THREAD_GETMEM (self, tid)); THREAD_SETMEM (self, pid, THREAD_GETMEM (self, tid));