vfs: check userland buffers before reading them.
[haiku.git] / src / system / libroot / os / locks / init_once.cpp
blobce3ad1804100faaa22443c6aca89fa0a2d48ae70
1 /*
2 * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include <locks.h>
10 enum {
11 STATE_UNINITIALIZED = -1, // keep in sync with INIT_ONCE_UNINITIALIZED
12 STATE_INITIALIZING = -2,
13 STATE_SPINNING = -3,
14 STATE_INITIALIZED = -4 // keep in sync with INIT_ONCE_INITIALIZED
18 status_t
19 __init_once(int32* control, status_t (*initRoutine)(void*), void* data)
21 // Algorithm:
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
30 // done.
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,
35 STATE_UNINITIALIZED);
37 if (value == STATE_INITIALIZED)
38 return 0;
40 if (value == STATE_UNINITIALIZED) {
41 // we're the first -- perform the initialization
42 initRoutine(data);
44 value = atomic_get_and_set(control, STATE_INITIALIZED);
46 // If someone else is waiting, we need to delete the semaphore.
47 if (value >= 0)
48 delete_sem(value);
50 return 0;
53 if (value == STATE_INITIALIZING) {
54 // someone is initializing -- we need to create a semaphore we can wait
55 // on
56 sem_id semaphore = create_sem(0, "pthread once");
57 if (semaphore >= 0) {
58 // successfully created -- set it
59 value = atomic_test_and_set(control, semaphore, STATE_INITIALIZING);
60 if (value == STATE_INITIALIZING)
61 value = semaphore;
62 else
63 delete_sem(semaphore);
64 } else {
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,
69 STATE_INITIALIZING);
70 if (value == STATE_INITIALIZING)
71 value = STATE_SPINNING;
75 if (value >= 0) {
76 // wait on the semaphore
77 while (acquire_sem(value) == B_INTERRUPTED);
79 return 0;
80 } else if (value == STATE_SPINNING) {
81 // out of semaphores -- spin
82 while (atomic_get(control) == STATE_SPINNING);
85 return 0;