2 * Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
12 STATE_UNINITIALIZED
= -1, // keep in sync with PTHREAD_ONCE_INIT
13 STATE_INITIALIZING
= -2,
15 STATE_INITIALIZED
= -4
19 /*! Called when the thread performing the initialization function was canceled.
21 \param data Pointer to the \c pthread_once_t structure in question.
24 init_function_canceled(void* data
)
26 pthread_once_t
* onceControl
= (pthread_once_t
*)data
;
28 // reset the control state to uninitialized
29 int32 value
= atomic_get_and_set((int32
*)&onceControl
->state
,
32 // If someone has set a semaphore, delete it.
42 pthread_once(pthread_once_t
* onceControl
, void (*initRoutine
)(void))
45 // The state goes through at most four states:
46 // STATE_UNINITIALIZED: The initial uninitialized state.
47 // STATE_INITIALIZING: Set by the first thread entering the function. It
48 // will call initRoutine.
49 // semaphore/STATE_SPINNING: Set by the second thread entering the function,
50 // when the first thread is still executing initRoutine. The normal case is
51 // that the thread manages to create a semaphore. This thread (and all
52 // following threads) will block on the semaphore until the first thread is
54 // STATE_INITIALIZED: Set by the first thread when it returns from
55 // initRoutine. All following threads will return right away.
58 int32 value
= atomic_test_and_set((int32
*)&onceControl
->state
,
59 STATE_INITIALIZING
, STATE_UNINITIALIZED
);
61 if (value
== STATE_INITIALIZED
)
64 if (value
== STATE_UNINITIALIZED
) {
65 // we're the first -- perform the initialization
66 pthread_cleanup_push(&init_function_canceled
, onceControl
);
68 pthread_cleanup_pop(false);
70 value
= atomic_get_and_set((int32
*)&onceControl
->state
,
73 // If someone else is waiting, we need to delete the semaphore.
80 if (value
== STATE_INITIALIZING
) {
81 // someone is initializing -- we need to create a semaphore we can
83 sem_id semaphore
= create_sem(0, "pthread once");
85 // successfully created -- set it
86 value
= atomic_test_and_set((int32
*)&onceControl
->state
,
87 semaphore
, STATE_INITIALIZING
);
88 if (value
== STATE_INITIALIZING
)
91 delete_sem(semaphore
);
93 // Failed to create the semaphore. Can only happen when the
94 // system runs out of semaphores, but we can still handle the
95 // situation gracefully by spinning.
96 value
= atomic_test_and_set((int32
*)&onceControl
->state
,
97 STATE_SPINNING
, STATE_INITIALIZING
);
98 if (value
== STATE_INITIALIZING
)
99 value
= STATE_SPINNING
;
104 // wait on the semaphore
105 while (acquire_sem(value
) == B_INTERRUPTED
);
108 } else if (value
== STATE_SPINNING
) {
109 // out of semaphores -- spin
110 while (atomic_get((int32
*)&onceControl
->state
) == STATE_SPINNING
);