In the pthread_once(), if the initializer has already run, then the
calling thread is supposed to see accesses issued by the initializer. This means that the read of the once_control->state variable should have an acquire semantic. Use atomic_thread_fence_acq() when the value read is ONCE_DONE, instead of straightforward atomic_load_acq(), to only put a barrier when needed (*). On the other hand, the updates of the once_control->state with the intermediate progress state do not need to synchronize with other state accesses, remove _acq suffix. Reviewed by: alc (previous version) Suggested by: alc (*) Sponsored by: The FreeBSD Foundation MFC after: 1 week
This commit is contained in:
parent
599acbbcd8
commit
3e7e67c08d
@ -68,13 +68,15 @@ _pthread_once(pthread_once_t *once_control, void (*init_routine) (void))
|
||||
|
||||
for (;;) {
|
||||
state = once_control->state;
|
||||
if (state == ONCE_DONE)
|
||||
if (state == ONCE_DONE) {
|
||||
atomic_thread_fence_acq();
|
||||
return (0);
|
||||
}
|
||||
if (state == ONCE_NEVER_DONE) {
|
||||
if (atomic_cmpset_acq_int(&once_control->state, state, ONCE_IN_PROGRESS))
|
||||
if (atomic_cmpset_int(&once_control->state, state, ONCE_IN_PROGRESS))
|
||||
break;
|
||||
} else if (state == ONCE_IN_PROGRESS) {
|
||||
if (atomic_cmpset_acq_int(&once_control->state, state, ONCE_WAIT))
|
||||
if (atomic_cmpset_int(&once_control->state, state, ONCE_WAIT))
|
||||
_thr_umtx_wait_uint(&once_control->state, ONCE_WAIT, NULL, 0);
|
||||
} else if (state == ONCE_WAIT) {
|
||||
_thr_umtx_wait_uint(&once_control->state, state, NULL, 0);
|
||||
|
Loading…
x
Reference in New Issue
Block a user