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