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:
@ -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]
|
||||||
|
@ -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. */
|
||||||
|
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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));
|
||||||
|
Reference in New Issue
Block a user