2 * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
11 STATE_UNINITIALIZED
= -1, // keep in sync with INIT_ONCE_UNINITIALIZED
12 STATE_INITIALIZING
= -2,
14 STATE_INITIALIZED
= -4 // keep in sync with INIT_ONCE_INITIALIZED
19 __init_once(int32
* control
, status_t (*initRoutine
)(void*), void* data
)
22 // The control variable goes through at most four states:
23 // STATE_UNINITIALIZED: The initial uninitialized state.
24 // STATE_INITIALIZING: Set by the first thread entering the function. It
25 // will call initRoutine.
26 // semaphore/STATE_SPINNING: Set by the second thread entering the function,
27 // when the first thread is still executing initRoutine. The normal case is
28 // that the thread manages to create a semaphore. This thread (and all
29 // following threads) will block on the semaphore until the first thread is
31 // STATE_INITIALIZED: Set by the first thread when it returns from
32 // initRoutine. All following threads will return right away.
34 int32 value
= atomic_test_and_set(control
, STATE_INITIALIZING
,
37 if (value
== STATE_INITIALIZED
)
40 if (value
== STATE_UNINITIALIZED
) {
41 // we're the first -- perform the initialization
44 value
= atomic_get_and_set(control
, STATE_INITIALIZED
);
46 // If someone else is waiting, we need to delete the semaphore.
53 if (value
== STATE_INITIALIZING
) {
54 // someone is initializing -- we need to create a semaphore we can wait
56 sem_id semaphore
= create_sem(0, "pthread once");
58 // successfully created -- set it
59 value
= atomic_test_and_set(control
, semaphore
, STATE_INITIALIZING
);
60 if (value
== STATE_INITIALIZING
)
63 delete_sem(semaphore
);
65 // Failed to create the semaphore. Can only happen when the system
66 // runs out of semaphores, but we can still handle the situation
67 // gracefully by spinning.
68 value
= atomic_test_and_set(control
, STATE_SPINNING
,
70 if (value
== STATE_INITIALIZING
)
71 value
= STATE_SPINNING
;
76 // wait on the semaphore
77 while (acquire_sem(value
) == B_INTERRUPTED
);
80 } else if (value
== STATE_SPINNING
) {
81 // out of semaphores -- spin
82 while (atomic_get(control
) == STATE_SPINNING
);