xref: /haiku/src/system/libroot/posix/glibc/include/bits/libc-lock.h (revision 3cb015b1ee509d69c643506e8ff573808c86dcfc)
1 /* libc-internal interface for mutex locks.  BeOS version.
2    Copyright (C)  1998 Be Inc.
3 */
4 
5 #ifndef _BITS_LIBC_LOCK_H
6 #define _BITS_LIBC_LOCK_H 1
7 
8 #include <Errors.h>
9 #include <OS.h>
10 #include <SupportDefs.h>
11 
12 
13 /* Helper definitions and prototypes.  */
14 
15 /* Atomic operations.  */
16 
17 extern char	_single_threaded;
18 
19 static inline int
20 __compare_and_swap (volatile int32 *p, int oldval, int newval)
21 {
22 	int32 readval = atomic_test_and_set(p, newval, oldval);
23 	return (readval == oldval ? 1 : 0);
24 }
25 
26 
27 /* Mutex type.  */
28 typedef struct __libc_lock_t {
29 	volatile int32	count;
30 	sem_id			sem;
31 	thread_id		owner;
32 	int				owner_count;
33 } __libc_lock_t;
34 
35 #define __LIBC_LOCK_INITIALIZER { 0, 0, 0, 0 }
36 #define _LIBC_LOCK_RECURSIVE_INITIALIZER { 0, 0, 0, 0 }
37 
38 /* Type for object to ensure once-only execution.  */
39 typedef struct {
40 	int __initialized;
41 	__libc_lock_t __lock;
42 } __libc_once_t;
43 
44 /* Define a lock variable NAME with storage class CLASS.  The lock must be
45    initialized with __libc_lock_init before it can be used (or define it
46    with __libc_lock_define_initialized, below).  Use `extern' for CLASS to
47    declare a lock defined in another module.  In public structure
48    definitions you must use a pointer to the lock structure (i.e., NAME
49    begins with a `*'), because its storage size will not be known outside
50    of libc.  */
51 #define __libc_lock_define(CLASS,NAME) \
52 	CLASS __libc_lock_t NAME;
53 
54 #define __libc_lock_define_recursive(CLASS, NAME) \
55 	CLASS __libc_lock_t NAME;
56 
57 /* Define an initialized lock variable NAME with storage class CLASS.  */
58 #define __libc_lock_define_initialized(CLASS,NAME) \
59 	CLASS __libc_lock_t NAME = __LIBC_LOCK_INITIALIZER;
60 
61 /* Define an initialized recursive lock variable NAME with storage
62    class CLASS.  */
63 #define __libc_lock_define_initialized_recursive(CLASS,NAME) \
64   __libc_lock_define_initialized (CLASS, NAME)
65 
66 /* Initialize the named lock variable, leaving it in a consistent, unlocked
67    state.  */
68 #define __libc_lock_init(NAME) \
69     (NAME).count = (NAME).sem = (NAME).owner_count = (NAME).owner = 0  \
70 
71 /* Same as last but this time we initialize a recursive mutex.  */
72 #define __libc_lock_init_recursive(NAME) \
73   __libc_lock_init(NAME)
74 
75 /* Finalize the named lock variable, which must be locked.  It cannot be
76    used again until __libc_lock_init is called again on it.  This must be
77    called on a lock variable before the containing storage is reused.  */
78 #define __libc_lock_fini(NAME) \
79   do { \
80     if ((NAME).sem) \
81       delete_sem((NAME).sem); \
82   } while(0)
83 
84 /* Finalize recursive named lock.  */
85 #define __libc_lock_fini_recursive(NAME) __libc_lock_fini(NAME)
86 
87 /* Lock the named lock variable.  */
88 #define __libc_lock_lock(NAME) \
89   do { \
90 	if (!_single_threaded) { \
91     	long err; \
92     	long old = atomic_add(&(NAME).count, 1); \
93     	if (old > 0) { \
94 			if ((NAME).sem == 0) { \
95 				sem_id __new_sem = create_sem (0, "libc:" #NAME);	      \
96 				if (!__compare_and_swap ((volatile int32 *)&(NAME).sem, 0, __new_sem))		      \
97 				/* We do not need the semaphore.  */				      \
98 					delete_sem (__new_sem);					      \
99 			} \
100     	    do { \
101     	      err = acquire_sem((NAME).sem); \
102 		    } while (err == B_INTERRUPTED); \
103     	} \
104 	} \
105   } while (0)
106 
107 
108 /* Lock the recursive named lock variable.  */
109 #define __libc_lock_lock_recursive(NAME) \
110   do { \
111 	if (!_single_threaded) { \
112     	thread_id owner = find_thread(NULL); \
113     	long old, err = B_OK; \
114     	if (owner == (NAME).owner) { \
115     	  (NAME).owner_count++; \
116     	  break; \
117     	} \
118     	old = atomic_add(&(NAME).count, 1); \
119     	if (old > 0) { \
120     	    if ((NAME).sem == 0) { \
121 				sem_id __new_sem = create_sem (0, "libc:" #NAME);	      \
122 				if (!__compare_and_swap ((volatile int32 *)&(NAME).sem, 0, __new_sem))		      \
123 				/* We do not need the semaphore.  */				      \
124 					delete_sem (__new_sem);					      \
125 			} \
126     	    do { \
127     	      err = acquire_sem((NAME).sem); \
128 		    } while (err == B_INTERRUPTED); \
129 		} \
130     	if (err == B_OK) { \
131     	  (NAME).owner = owner; \
132     	  (NAME).owner_count = 1; \
133 		} \
134 	} \
135   } while (0)
136 
137 #if 0
138 /* Try to lock the named lock variable.  */
139 #define __libc_lock_trylock(NAME) \
140 	({									      \
141 		int __result = EBUSY;						      \
142 		status_t err; \
143 		if (!(NAME).sem) {							      \
144 			__libc_sem_id __new_sem = create_sem (1, "libc:" #NAME);	      \
145 			if (!__compare_and_swap (&(NAME).sem, 0, __new_sem))		      \
146 			/* We do not need the semaphore.  */				      \
147 				delete_sem (__new_sem);					      \
148 		}									      \
149 		do { \
150     		err = acquire_sem_etc ((NAME).sem, 1, B_TIMEOUT, 0); \
151 			if (err == B_OK) { \
152 				NAME.__count = 1;						      \
153 				__result = 0;							      \
154 			}									      \
155 		} while (err == B_INTERRUPTED); \
156 	__result; })
157 #endif
158 
159 #if 0
160 /* Try to lock the recursive named lock variable.  */
161 #define __libc_lock_trylock_recursive(NAME) \
162 	({									      \
163 		__libc_thread_id __me = find_thread (NULL);				      \
164 		int __result = EBUSY;						      \
165 		status_t err;							 \
166 		if (!(NAME).sem) {							      \
167 			__libc_sem_id __new_sem = create_sem (1, "libc:" #NAME);	      \
168 			if (!__compare_and_swap (&(NAME).sem, 0, __new_sem))		      \
169 			/* We do not need the semaphore.  */				      \
170 				delete_sem (__new_sem);					      \
171 		}									      \
172 		if ((NAME).__owner == __me) {\
173 			++(NAME).__count;							      \
174 			__result = 0;							      \
175 		} else \
176 			do { \
177 				err = acquire_sem_etc ((NAME).sem, 1, B_TIMEOUT, 0); \
178 				if (err == B_OK) {						  \
179 					(NAME).__owner = __me;					      \
180 					(NAME).__count = 1;						      \
181 					__result = 0;							      \
182 				}								      \
183 			} while (err == B_INTERRUPTED); \
184     __result; })
185 #endif
186 
187 /* Unlock the named lock variable.  */
188 #define __libc_lock_unlock(NAME) \
189   do { \
190 	if (!_single_threaded) { \
191     	if (atomic_add(&(NAME).count, -1) > 1) { \
192     	    if ((NAME).sem == 0) { \
193 				sem_id __new_sem = create_sem (0, "libc:" #NAME);	      \
194 				if (!__compare_and_swap ((volatile int32 *)&(NAME).sem, 0, __new_sem))		      \
195 				/* We do not need the semaphore.  */				      \
196 					delete_sem (__new_sem);					      \
197 			} \
198 			release_sem((NAME).sem); \
199 		} \
200 	} \
201   } while(0)
202 
203 /* Unlock the recursive named lock variable.  */
204 #define __libc_lock_unlock_recursive(NAME) \
205   do { \
206 	if (!_single_threaded) { \
207     	(NAME).owner_count--; \
208     	if ((NAME).owner_count == 0) { \
209     	  (NAME).owner = 0; \
210     	  if (atomic_add(&(NAME).count, -1) > 1) { \
211     	    if ((NAME).sem == 0) { \
212 				sem_id __new_sem = create_sem (0, "libc:" #NAME);	      \
213 				if (!__compare_and_swap ((volatile int32 *)&(NAME).sem, 0, __new_sem))		      \
214 				/* We do not need the semaphore.  */				      \
215 					delete_sem (__new_sem);					      \
216 			} \
217     	    release_sem((NAME).sem); \
218 		  } \
219 		} \
220 	} \
221   } while(0)
222 
223 
224 /* Define once control variable.  */
225 #define __libc_once_define(CLASS, NAME) \
226   CLASS __libc_once_t NAME = { 0, __LIBC_LOCK_INITIALIZER }
227 
228 /* Call handler iff the first call.  */
229 #define __libc_once(ONCE_CONTROL, INIT_FUNCTION) \
230   do {									      \
231     if (! ONCE_CONTROL.__initialized)					      \
232       {									      \
233 	__libc_lock_lock (ONCE_CONTROL.__lock);				      \
234 	if (! ONCE_CONTROL.__initialized)				      \
235 	  {								      \
236 	    /* Still not initialized, then call the function.  */	      \
237 	    INIT_FUNCTION ();						      \
238 	    ONCE_CONTROL.__initialized = 1;				      \
239 	  }								      \
240 	__libc_lock_unlock (ONCE_CONTROL.__lock);			      \
241       }									      \
242   } while (0)
243 
244 
245 /* Start critical region with cleanup.  */
246 #define __libc_cleanup_region_start(DOIT, FCT, ARG) \
247 
248 /* End critical region with cleanup.  */
249 #define __libc_cleanup_region_end(DOIT) \
250 
251 /* Sometimes we have to exit the block in the middle.  */
252 #define __libc_cleanup_end(DOIT) \
253 
254 /* Create thread-specific key.  */
255 #define __libc_key_create(KEY, DESTRUCTOR) \
256   1
257 
258 /* Get thread-specific data.  */
259 #define __libc_getspecific(KEY) \
260   0
261 
262 /* Set thread-specific data.  */
263 #define __libc_setspecific(KEY, VALUE) \
264   0
265 
266 
267 /* Register handlers to execute before and after `fork'.  */
268 #define __libc_atfork(PREPARE, PARENT, CHILD) \
269   0
270 
271 #endif	/* bits/libc-lock.h */
272