comparison nspr/pr/src/threads/prrwlock.c @ 0:1e5118fa0cb1

This is NSS with a Cmake Buildsyste To compile a static NSS library for Windows we've used the Chromium-NSS fork and added a Cmake buildsystem to compile it statically for Windows. See README.chromium for chromium changes and README.trustbridge for our modifications.
author Andre Heinecke <andre.heinecke@intevation.de>
date Mon, 28 Jul 2014 10:47:06 +0200
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:1e5118fa0cb1
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "primpl.h"
7
8 #include <string.h>
9
10 #if defined(HPUX) && defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)
11
12 #include <pthread.h>
13 #define HAVE_UNIX98_RWLOCK
14 #define RWLOCK_T pthread_rwlock_t
15 #define RWLOCK_INIT(lock) pthread_rwlock_init(lock, NULL)
16 #define RWLOCK_DESTROY(lock) pthread_rwlock_destroy(lock)
17 #define RWLOCK_RDLOCK(lock) pthread_rwlock_rdlock(lock)
18 #define RWLOCK_WRLOCK(lock) pthread_rwlock_wrlock(lock)
19 #define RWLOCK_UNLOCK(lock) pthread_rwlock_unlock(lock)
20
21 #elif defined(SOLARIS) && (defined(_PR_PTHREADS) \
22 || defined(_PR_GLOBAL_THREADS_ONLY))
23
24 #include <synch.h>
25 #define HAVE_UI_RWLOCK
26 #define RWLOCK_T rwlock_t
27 #define RWLOCK_INIT(lock) rwlock_init(lock, USYNC_THREAD, NULL)
28 #define RWLOCK_DESTROY(lock) rwlock_destroy(lock)
29 #define RWLOCK_RDLOCK(lock) rw_rdlock(lock)
30 #define RWLOCK_WRLOCK(lock) rw_wrlock(lock)
31 #define RWLOCK_UNLOCK(lock) rw_unlock(lock)
32
33 #endif
34
35 /*
36 * Reader-writer lock
37 */
38 struct PRRWLock {
39 char *rw_name; /* lock name */
40 PRUint32 rw_rank; /* rank of the lock */
41
42 #if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
43 RWLOCK_T rw_lock;
44 #else
45 PRLock *rw_lock;
46 PRInt32 rw_lock_cnt; /* == 0, if unlocked */
47 /* == -1, if write-locked */
48 /* > 0 , # of read locks */
49 PRUint32 rw_reader_cnt; /* number of waiting readers */
50 PRUint32 rw_writer_cnt; /* number of waiting writers */
51 PRCondVar *rw_reader_waitq; /* cvar for readers */
52 PRCondVar *rw_writer_waitq; /* cvar for writers */
53 #ifdef DEBUG
54 PRThread *rw_owner; /* lock owner for write-lock */
55 #endif
56 #endif
57 };
58
59 #ifdef DEBUG
60 #define _PR_RWLOCK_RANK_ORDER_DEBUG /* enable deadlock detection using
61 rank-order for locks
62 */
63 #endif
64
65 #ifdef _PR_RWLOCK_RANK_ORDER_DEBUG
66
67 static PRUintn pr_thread_rwlock_key; /* TPD key for lock stack */
68 static PRUintn pr_thread_rwlock_alloc_failed;
69
70 #define _PR_RWLOCK_RANK_ORDER_LIMIT 10
71
72 typedef struct thread_rwlock_stack {
73 PRInt32 trs_index; /* top of stack */
74 PRRWLock *trs_stack[_PR_RWLOCK_RANK_ORDER_LIMIT]; /* stack of lock
75 pointers */
76
77 } thread_rwlock_stack;
78
79 static void _PR_SET_THREAD_RWLOCK_RANK(PRRWLock *rwlock);
80 static PRUint32 _PR_GET_THREAD_RWLOCK_RANK(void);
81 static void _PR_UNSET_THREAD_RWLOCK_RANK(PRRWLock *rwlock);
82 static void _PR_RELEASE_LOCK_STACK(void *lock_stack);
83
84 #endif
85
86 /*
87 * Reader/Writer Locks
88 */
89
90 /*
91 * PR_NewRWLock
92 * Create a reader-writer lock, with the given lock rank and lock name
93 *
94 */
95
96 PR_IMPLEMENT(PRRWLock *)
97 PR_NewRWLock(PRUint32 lock_rank, const char *lock_name)
98 {
99 PRRWLock *rwlock;
100 #if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
101 int err;
102 #endif
103
104 if (!_pr_initialized) _PR_ImplicitInitialization();
105
106 rwlock = PR_NEWZAP(PRRWLock);
107 if (rwlock == NULL)
108 return NULL;
109
110 rwlock->rw_rank = lock_rank;
111 if (lock_name != NULL) {
112 rwlock->rw_name = (char*) PR_Malloc(strlen(lock_name) + 1);
113 if (rwlock->rw_name == NULL) {
114 PR_DELETE(rwlock);
115 return(NULL);
116 }
117 strcpy(rwlock->rw_name, lock_name);
118 } else {
119 rwlock->rw_name = NULL;
120 }
121
122 #if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
123 err = RWLOCK_INIT(&rwlock->rw_lock);
124 if (err != 0) {
125 PR_SetError(PR_UNKNOWN_ERROR, err);
126 PR_Free(rwlock->rw_name);
127 PR_DELETE(rwlock);
128 return NULL;
129 }
130 return rwlock;
131 #else
132 rwlock->rw_lock = PR_NewLock();
133 if (rwlock->rw_lock == NULL) {
134 goto failed;
135 }
136 rwlock->rw_reader_waitq = PR_NewCondVar(rwlock->rw_lock);
137 if (rwlock->rw_reader_waitq == NULL) {
138 goto failed;
139 }
140 rwlock->rw_writer_waitq = PR_NewCondVar(rwlock->rw_lock);
141 if (rwlock->rw_writer_waitq == NULL) {
142 goto failed;
143 }
144 rwlock->rw_reader_cnt = 0;
145 rwlock->rw_writer_cnt = 0;
146 rwlock->rw_lock_cnt = 0;
147 return rwlock;
148
149 failed:
150 if (rwlock->rw_reader_waitq != NULL) {
151 PR_DestroyCondVar(rwlock->rw_reader_waitq);
152 }
153 if (rwlock->rw_lock != NULL) {
154 PR_DestroyLock(rwlock->rw_lock);
155 }
156 PR_Free(rwlock->rw_name);
157 PR_DELETE(rwlock);
158 return NULL;
159 #endif
160 }
161
162 /*
163 ** Destroy the given RWLock "lock".
164 */
165 PR_IMPLEMENT(void)
166 PR_DestroyRWLock(PRRWLock *rwlock)
167 {
168 #if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
169 int err;
170 err = RWLOCK_DESTROY(&rwlock->rw_lock);
171 PR_ASSERT(err == 0);
172 #else
173 PR_ASSERT(rwlock->rw_reader_cnt == 0);
174 PR_DestroyCondVar(rwlock->rw_reader_waitq);
175 PR_DestroyCondVar(rwlock->rw_writer_waitq);
176 PR_DestroyLock(rwlock->rw_lock);
177 #endif
178 if (rwlock->rw_name != NULL)
179 PR_Free(rwlock->rw_name);
180 PR_DELETE(rwlock);
181 }
182
183 /*
184 ** Read-lock the RWLock.
185 */
186 PR_IMPLEMENT(void)
187 PR_RWLock_Rlock(PRRWLock *rwlock)
188 {
189 #if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
190 int err;
191 #endif
192
193 #ifdef _PR_RWLOCK_RANK_ORDER_DEBUG
194 /*
195 * assert that rank ordering is not violated; the rank of 'rwlock' should
196 * be equal to or greater than the highest rank of all the locks held by
197 * the thread.
198 */
199 PR_ASSERT((rwlock->rw_rank == PR_RWLOCK_RANK_NONE) ||
200 (rwlock->rw_rank >= _PR_GET_THREAD_RWLOCK_RANK()));
201 #endif
202
203 #if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
204 err = RWLOCK_RDLOCK(&rwlock->rw_lock);
205 PR_ASSERT(err == 0);
206 #else
207 PR_Lock(rwlock->rw_lock);
208 /*
209 * wait if write-locked or if a writer is waiting; preference for writers
210 */
211 while ((rwlock->rw_lock_cnt < 0) ||
212 (rwlock->rw_writer_cnt > 0)) {
213 rwlock->rw_reader_cnt++;
214 PR_WaitCondVar(rwlock->rw_reader_waitq, PR_INTERVAL_NO_TIMEOUT);
215 rwlock->rw_reader_cnt--;
216 }
217 /*
218 * Increment read-lock count
219 */
220 rwlock->rw_lock_cnt++;
221
222 PR_Unlock(rwlock->rw_lock);
223 #endif
224
225 #ifdef _PR_RWLOCK_RANK_ORDER_DEBUG
226 /*
227 * update thread's lock rank
228 */
229 if (rwlock->rw_rank != PR_RWLOCK_RANK_NONE)
230 _PR_SET_THREAD_RWLOCK_RANK(rwlock);
231 #endif
232 }
233
234 /*
235 ** Write-lock the RWLock.
236 */
237 PR_IMPLEMENT(void)
238 PR_RWLock_Wlock(PRRWLock *rwlock)
239 {
240 #if defined(DEBUG)
241 PRThread *me = PR_GetCurrentThread();
242 #endif
243 #if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
244 int err;
245 #endif
246
247 #ifdef _PR_RWLOCK_RANK_ORDER_DEBUG
248 /*
249 * assert that rank ordering is not violated; the rank of 'rwlock' should
250 * be equal to or greater than the highest rank of all the locks held by
251 * the thread.
252 */
253 PR_ASSERT((rwlock->rw_rank == PR_RWLOCK_RANK_NONE) ||
254 (rwlock->rw_rank >= _PR_GET_THREAD_RWLOCK_RANK()));
255 #endif
256
257 #if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
258 err = RWLOCK_WRLOCK(&rwlock->rw_lock);
259 PR_ASSERT(err == 0);
260 #else
261 PR_Lock(rwlock->rw_lock);
262 /*
263 * wait if read locked
264 */
265 while (rwlock->rw_lock_cnt != 0) {
266 rwlock->rw_writer_cnt++;
267 PR_WaitCondVar(rwlock->rw_writer_waitq, PR_INTERVAL_NO_TIMEOUT);
268 rwlock->rw_writer_cnt--;
269 }
270 /*
271 * apply write lock
272 */
273 rwlock->rw_lock_cnt--;
274 PR_ASSERT(rwlock->rw_lock_cnt == -1);
275 #ifdef DEBUG
276 PR_ASSERT(me != NULL);
277 rwlock->rw_owner = me;
278 #endif
279 PR_Unlock(rwlock->rw_lock);
280 #endif
281
282 #ifdef _PR_RWLOCK_RANK_ORDER_DEBUG
283 /*
284 * update thread's lock rank
285 */
286 if (rwlock->rw_rank != PR_RWLOCK_RANK_NONE)
287 _PR_SET_THREAD_RWLOCK_RANK(rwlock);
288 #endif
289 }
290
291 /*
292 ** Unlock the RW lock.
293 */
294 PR_IMPLEMENT(void)
295 PR_RWLock_Unlock(PRRWLock *rwlock)
296 {
297 #if defined(DEBUG)
298 PRThread *me = PR_GetCurrentThread();
299 #endif
300 #if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
301 int err;
302 #endif
303
304 #if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
305 err = RWLOCK_UNLOCK(&rwlock->rw_lock);
306 PR_ASSERT(err == 0);
307 #else
308 PR_Lock(rwlock->rw_lock);
309 /*
310 * lock must be read or write-locked
311 */
312 PR_ASSERT(rwlock->rw_lock_cnt != 0);
313 if (rwlock->rw_lock_cnt > 0) {
314
315 /*
316 * decrement read-lock count
317 */
318 rwlock->rw_lock_cnt--;
319 if (rwlock->rw_lock_cnt == 0) {
320 /*
321 * lock is not read-locked anymore; wakeup a waiting writer
322 */
323 if (rwlock->rw_writer_cnt > 0)
324 PR_NotifyCondVar(rwlock->rw_writer_waitq);
325 }
326 } else {
327 PR_ASSERT(rwlock->rw_lock_cnt == -1);
328
329 rwlock->rw_lock_cnt = 0;
330 #ifdef DEBUG
331 PR_ASSERT(rwlock->rw_owner == me);
332 rwlock->rw_owner = NULL;
333 #endif
334 /*
335 * wakeup a writer, if present; preference for writers
336 */
337 if (rwlock->rw_writer_cnt > 0)
338 PR_NotifyCondVar(rwlock->rw_writer_waitq);
339 /*
340 * else, wakeup all readers, if any
341 */
342 else if (rwlock->rw_reader_cnt > 0)
343 PR_NotifyAllCondVar(rwlock->rw_reader_waitq);
344 }
345 PR_Unlock(rwlock->rw_lock);
346 #endif
347
348 #ifdef _PR_RWLOCK_RANK_ORDER_DEBUG
349 /*
350 * update thread's lock rank
351 */
352 if (rwlock->rw_rank != PR_RWLOCK_RANK_NONE)
353 _PR_UNSET_THREAD_RWLOCK_RANK(rwlock);
354 #endif
355 return;
356 }
357
358 #ifndef _PR_RWLOCK_RANK_ORDER_DEBUG
359
360 void _PR_InitRWLocks(void) { }
361
362 #else
363
364 void _PR_InitRWLocks(void)
365 {
366 /*
367 * allocated thread-private-data index for rwlock list
368 */
369 if (PR_NewThreadPrivateIndex(&pr_thread_rwlock_key,
370 _PR_RELEASE_LOCK_STACK) == PR_FAILURE) {
371 pr_thread_rwlock_alloc_failed = 1;
372 return;
373 }
374 }
375
376 /*
377 * _PR_SET_THREAD_RWLOCK_RANK
378 * Set a thread's lock rank, which is the highest of the ranks of all
379 * the locks held by the thread. Pointers to the locks are added to a
380 * per-thread list, which is anchored off a thread-private data key.
381 */
382
383 static void
384 _PR_SET_THREAD_RWLOCK_RANK(PRRWLock *rwlock)
385 {
386 thread_rwlock_stack *lock_stack;
387 PRStatus rv;
388
389 /*
390 * allocate a lock stack
391 */
392 if ((lock_stack = PR_GetThreadPrivate(pr_thread_rwlock_key)) == NULL) {
393 lock_stack = (thread_rwlock_stack *)
394 PR_CALLOC(1 * sizeof(thread_rwlock_stack));
395 if (lock_stack) {
396 rv = PR_SetThreadPrivate(pr_thread_rwlock_key, lock_stack);
397 if (rv == PR_FAILURE) {
398 PR_DELETE(lock_stack);
399 pr_thread_rwlock_alloc_failed = 1;
400 return;
401 }
402 } else {
403 pr_thread_rwlock_alloc_failed = 1;
404 return;
405 }
406 }
407 /*
408 * add rwlock to lock stack, if limit is not exceeded
409 */
410 if (lock_stack) {
411 if (lock_stack->trs_index < _PR_RWLOCK_RANK_ORDER_LIMIT)
412 lock_stack->trs_stack[lock_stack->trs_index++] = rwlock;
413 }
414 }
415
416 static void
417 _PR_RELEASE_LOCK_STACK(void *lock_stack)
418 {
419 PR_ASSERT(lock_stack);
420 PR_DELETE(lock_stack);
421 }
422
423 /*
424 * _PR_GET_THREAD_RWLOCK_RANK
425 *
426 * return thread's lock rank. If thread-private-data for the lock
427 * stack is not allocated, return PR_RWLOCK_RANK_NONE.
428 */
429
430 static PRUint32
431 _PR_GET_THREAD_RWLOCK_RANK(void)
432 {
433 thread_rwlock_stack *lock_stack;
434
435 lock_stack = PR_GetThreadPrivate(pr_thread_rwlock_key);
436 if (lock_stack == NULL || lock_stack->trs_index == 0)
437 return (PR_RWLOCK_RANK_NONE);
438 else
439 return(lock_stack->trs_stack[lock_stack->trs_index - 1]->rw_rank);
440 }
441
442 /*
443 * _PR_UNSET_THREAD_RWLOCK_RANK
444 *
445 * remove the rwlock from the lock stack. Since locks may not be
446 * unlocked in a FIFO order, the entire lock stack is searched.
447 */
448
449 static void
450 _PR_UNSET_THREAD_RWLOCK_RANK(PRRWLock *rwlock)
451 {
452 thread_rwlock_stack *lock_stack;
453 int new_index = 0, index, done = 0;
454
455 lock_stack = PR_GetThreadPrivate(pr_thread_rwlock_key);
456
457 PR_ASSERT(lock_stack != NULL);
458
459 for (index = lock_stack->trs_index - 1; index >= 0; index--) {
460 if (!done && (lock_stack->trs_stack[index] == rwlock)) {
461 /*
462 * reset the slot for rwlock
463 */
464 lock_stack->trs_stack[index] = NULL;
465 done = 1;
466 }
467 /*
468 * search for the lowest-numbered empty slot, above which there are
469 * no non-empty slots
470 */
471 if (!new_index && (lock_stack->trs_stack[index] != NULL))
472 new_index = index + 1;
473 if (done && new_index)
474 break;
475 }
476 /*
477 * set top of stack to highest numbered empty slot
478 */
479 lock_stack->trs_index = new_index;
480
481 }
482
483 #endif /* _PR_RWLOCK_RANK_ORDER_DEBUG */
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)