xref: /haiku/src/system/libroot/os/locks/mutex.cpp (revision 6490c5b6211c94ec48c03c12b90e8603fe268d1b)
1 /*
2  * Copyright 2009, Michael Lotz, mmlr@mlotz.ch.
3  * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
4  * Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
5  * Distributed under the terms of the MIT License.
6  *
7  * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
8  * Distributed under the terms of the NewOS License.
9  */
10 
11 
12 #include <locks.h>
13 
14 #include <OS.h>
15 
16 
17 // #pragma mark - mutex
18 
19 
20 status_t
21 mutex_init(mutex *lock, const char *name)
22 {
23 	if (lock == NULL || name == NULL)
24 		return B_BAD_VALUE;
25 
26 	lock->benaphore = 0;
27 	lock->semaphore = create_sem(0, name);
28 	if (lock->semaphore < 0)
29 		return lock->semaphore;
30 
31 	return B_OK;
32 }
33 
34 
35 void
36 mutex_destroy(mutex *lock)
37 {
38 	delete_sem(lock->semaphore);
39 }
40 
41 
42 status_t
43 mutex_lock(mutex *lock)
44 {
45 	if (atomic_add(&lock->benaphore, 1) == 0)
46 		return B_OK;
47 
48 	status_t result;
49 	do {
50 		result = acquire_sem(lock->semaphore);
51 	} while (result == B_INTERRUPTED);
52 
53 	return result;
54 }
55 
56 
57 void
58 mutex_unlock(mutex *lock)
59 {
60 	if (atomic_add(&lock->benaphore, -1) != 1)
61 		release_sem(lock->semaphore);
62 }
63 
64 
65 // #pragma mark - lazy mutex
66 
67 
68 enum {
69 	STATE_UNINITIALIZED	= -1,
70 	STATE_INITIALIZING	= -2,
71 	STATE_SPIN_LOCKED	= -3,
72 	STATE_SPIN_UNLOCKED	= -4
73 };
74 
75 
76 static inline bool
77 lazy_mutex_ensure_init(lazy_mutex *lock)
78 {
79 	int32 value = atomic_test_and_set((vint32*)&lock->semaphore,
80 		STATE_INITIALIZING, STATE_UNINITIALIZED);
81 
82 	if (value >= 0)
83 		return true;
84 
85 	if (value == STATE_UNINITIALIZED) {
86 		// we're the first -- perform the initialization
87 		sem_id semaphore = create_sem(0, lock->name);
88 		if (semaphore < 0)
89 			semaphore = STATE_SPIN_UNLOCKED;
90 		atomic_set((vint32*)&lock->semaphore, semaphore);
91 		return semaphore >= 0;
92 	}
93 
94 	if (value == STATE_INITIALIZING) {
95 		// someone else is initializing -- spin until that is done
96 		while (atomic_get((vint32*)&lock->semaphore) == STATE_INITIALIZING) {
97 		}
98 	}
99 
100 	return lock->semaphore >= 0;
101 }
102 
103 
104 status_t
105 lazy_mutex_init(lazy_mutex *lock, const char *name)
106 {
107 	if (lock == NULL || name == NULL)
108 		return B_BAD_VALUE;
109 
110 	lock->benaphore = 0;
111 	lock->semaphore = STATE_UNINITIALIZED;
112 	lock->name = name;
113 
114 	return B_OK;
115 }
116 
117 
118 void
119 lazy_mutex_destroy(lazy_mutex *lock)
120 {
121 	if (lock->semaphore >= 0)
122 		delete_sem(lock->semaphore);
123 }
124 
125 
126 status_t
127 lazy_mutex_lock(lazy_mutex *lock)
128 {
129 	if (atomic_add(&lock->benaphore, 1) == 0)
130 		return B_OK;
131 
132 	if (lazy_mutex_ensure_init(lock)) {
133 		// acquire the semaphore
134 		status_t result;
135 		do {
136 			result = acquire_sem(lock->semaphore);
137 		} while (result == B_INTERRUPTED);
138 
139 		return result;
140 	} else {
141 		// the semaphore creation failed -- so we use it like a spinlock instead
142 		while (atomic_test_and_set((vint32*)&lock->semaphore,
143 				STATE_SPIN_LOCKED, STATE_SPIN_UNLOCKED)
144 					!= STATE_SPIN_UNLOCKED) {
145 		}
146 		return B_OK;
147 	}
148 }
149 
150 
151 void
152 lazy_mutex_unlock(lazy_mutex *lock)
153 {
154 	if (atomic_add(&lock->benaphore, -1) == 1)
155 		return;
156 
157 	if (lazy_mutex_ensure_init(lock)) {
158 		// release the semaphore
159 		release_sem(lock->semaphore);
160 	} else {
161 		// the semaphore creation failed -- so we use it like a spinlock instead
162 		atomic_set((vint32*)&lock->semaphore, STATE_SPIN_UNLOCKED);
163 	}
164 }
165