comparison nss/lib/util/nssrwlk.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 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 #include "nssrwlk.h"
6 #include "nspr.h"
7
8 PR_BEGIN_EXTERN_C
9
10 /*
11 * Reader-writer lock
12 */
13 struct nssRWLockStr {
14 PZLock * rw_lock;
15 char * rw_name; /* lock name */
16 PRUint32 rw_rank; /* rank of the lock */
17 PRInt32 rw_writer_locks; /* == 0, if unlocked */
18 PRInt32 rw_reader_locks; /* == 0, if unlocked */
19 /* > 0 , # of read locks */
20 PRUint32 rw_waiting_readers; /* number of waiting readers */
21 PRUint32 rw_waiting_writers; /* number of waiting writers */
22 PZCondVar * rw_reader_waitq; /* cvar for readers */
23 PZCondVar * rw_writer_waitq; /* cvar for writers */
24 PRThread * rw_owner; /* lock owner for write-lock */
25 /* Non-null if write lock held. */
26 };
27
28 PR_END_EXTERN_C
29
30 #include <string.h>
31
32 #ifdef DEBUG_RANK_ORDER
33 #define NSS_RWLOCK_RANK_ORDER_DEBUG /* enable deadlock detection using
34 rank-order for locks
35 */
36 #endif
37
38 #ifdef NSS_RWLOCK_RANK_ORDER_DEBUG
39
40 static PRUintn nss_thread_rwlock_initialized;
41 static PRUintn nss_thread_rwlock; /* TPD key for lock stack */
42 static PRUintn nss_thread_rwlock_alloc_failed;
43
44 #define _NSS_RWLOCK_RANK_ORDER_LIMIT 10
45
46 typedef struct thread_rwlock_stack {
47 PRInt32 trs_index; /* top of stack */
48 NSSRWLock *trs_stack[_NSS_RWLOCK_RANK_ORDER_LIMIT]; /* stack of lock
49 pointers */
50 } thread_rwlock_stack;
51
52 /* forward static declarations. */
53 static PRUint32 nssRWLock_GetThreadRank(PRThread *me);
54 static void nssRWLock_SetThreadRank(PRThread *me, NSSRWLock *rwlock);
55 static void nssRWLock_UnsetThreadRank(PRThread *me, NSSRWLock *rwlock);
56 static void nssRWLock_ReleaseLockStack(void *lock_stack);
57
58 #endif
59
60 #define UNTIL(x) while(!(x))
61
62 /*
63 * Reader/Writer Locks
64 */
65
66 /*
67 * NSSRWLock_New
68 * Create a reader-writer lock, with the given lock rank and lock name
69 *
70 */
71
72 NSSRWLock *
73 NSSRWLock_New(PRUint32 lock_rank, const char *lock_name)
74 {
75 NSSRWLock *rwlock;
76
77 rwlock = PR_NEWZAP(NSSRWLock);
78 if (rwlock == NULL)
79 return NULL;
80
81 rwlock->rw_lock = PZ_NewLock(nssILockRWLock);
82 if (rwlock->rw_lock == NULL) {
83 goto loser;
84 }
85 rwlock->rw_reader_waitq = PZ_NewCondVar(rwlock->rw_lock);
86 if (rwlock->rw_reader_waitq == NULL) {
87 goto loser;
88 }
89 rwlock->rw_writer_waitq = PZ_NewCondVar(rwlock->rw_lock);
90 if (rwlock->rw_writer_waitq == NULL) {
91 goto loser;
92 }
93 if (lock_name != NULL) {
94 rwlock->rw_name = (char*) PR_Malloc(strlen(lock_name) + 1);
95 if (rwlock->rw_name == NULL) {
96 goto loser;
97 }
98 strcpy(rwlock->rw_name, lock_name);
99 } else {
100 rwlock->rw_name = NULL;
101 }
102 rwlock->rw_rank = lock_rank;
103 rwlock->rw_waiting_readers = 0;
104 rwlock->rw_waiting_writers = 0;
105 rwlock->rw_reader_locks = 0;
106 rwlock->rw_writer_locks = 0;
107
108 return rwlock;
109
110 loser:
111 NSSRWLock_Destroy(rwlock);
112 return(NULL);
113 }
114
115 /*
116 ** Destroy the given RWLock "lock".
117 */
118 void
119 NSSRWLock_Destroy(NSSRWLock *rwlock)
120 {
121 PR_ASSERT(rwlock != NULL);
122 PR_ASSERT(rwlock->rw_waiting_readers == 0);
123
124 /* XXX Shouldn't we lock the PZLock before destroying this?? */
125
126 if (rwlock->rw_name)
127 PR_Free(rwlock->rw_name);
128 if (rwlock->rw_reader_waitq)
129 PZ_DestroyCondVar(rwlock->rw_reader_waitq);
130 if (rwlock->rw_writer_waitq)
131 PZ_DestroyCondVar(rwlock->rw_writer_waitq);
132 if (rwlock->rw_lock)
133 PZ_DestroyLock(rwlock->rw_lock);
134 PR_DELETE(rwlock);
135 }
136
137 /*
138 ** Read-lock the RWLock.
139 */
140 void
141 NSSRWLock_LockRead(NSSRWLock *rwlock)
142 {
143 PRThread *me = PR_GetCurrentThread();
144
145 PZ_Lock(rwlock->rw_lock);
146 #ifdef NSS_RWLOCK_RANK_ORDER_DEBUG
147
148 /*
149 * assert that rank ordering is not violated; the rank of 'rwlock' should
150 * be equal to or greater than the highest rank of all the locks held by
151 * the thread.
152 */
153 PR_ASSERT((rwlock->rw_rank == NSS_RWLOCK_RANK_NONE) ||
154 (rwlock->rw_rank >= nssRWLock_GetThreadRank(me)));
155 #endif
156 /*
157 * wait if write-locked or if a writer is waiting; preference for writers
158 */
159 UNTIL ( (rwlock->rw_owner == me) || /* I own it, or */
160 ((rwlock->rw_owner == NULL) && /* no-one owns it, and */
161 (rwlock->rw_waiting_writers == 0))) { /* no-one is waiting to own */
162
163 rwlock->rw_waiting_readers++;
164 PZ_WaitCondVar(rwlock->rw_reader_waitq, PR_INTERVAL_NO_TIMEOUT);
165 rwlock->rw_waiting_readers--;
166 }
167 rwlock->rw_reader_locks++; /* Increment read-lock count */
168
169 PZ_Unlock(rwlock->rw_lock);
170
171 #ifdef NSS_RWLOCK_RANK_ORDER_DEBUG
172 nssRWLock_SetThreadRank(me, rwlock);/* update thread's lock rank */
173 #endif
174 }
175
176 /* Unlock a Read lock held on this RW lock.
177 */
178 void
179 NSSRWLock_UnlockRead(NSSRWLock *rwlock)
180 {
181 PZ_Lock(rwlock->rw_lock);
182
183 PR_ASSERT(rwlock->rw_reader_locks > 0); /* lock must be read locked */
184
185 if (( rwlock->rw_reader_locks > 0) && /* caller isn't screwey */
186 (--rwlock->rw_reader_locks == 0) && /* not read locked any more */
187 ( rwlock->rw_owner == NULL) && /* not write locked */
188 ( rwlock->rw_waiting_writers > 0)) { /* someone's waiting. */
189
190 PZ_NotifyCondVar(rwlock->rw_writer_waitq); /* wake him up. */
191 }
192
193 PZ_Unlock(rwlock->rw_lock);
194
195 #ifdef NSS_RWLOCK_RANK_ORDER_DEBUG
196 /*
197 * update thread's lock rank
198 */
199 nssRWLock_UnsetThreadRank(me, rwlock);
200 #endif
201 return;
202 }
203
204 /*
205 ** Write-lock the RWLock.
206 */
207 void
208 NSSRWLock_LockWrite(NSSRWLock *rwlock)
209 {
210 PRThread *me = PR_GetCurrentThread();
211
212 PZ_Lock(rwlock->rw_lock);
213 #ifdef NSS_RWLOCK_RANK_ORDER_DEBUG
214 /*
215 * assert that rank ordering is not violated; the rank of 'rwlock' should
216 * be equal to or greater than the highest rank of all the locks held by
217 * the thread.
218 */
219 PR_ASSERT((rwlock->rw_rank == NSS_RWLOCK_RANK_NONE) ||
220 (rwlock->rw_rank >= nssRWLock_GetThreadRank(me)));
221 #endif
222 /*
223 * wait if read locked or write locked.
224 */
225 PR_ASSERT(rwlock->rw_reader_locks >= 0);
226 PR_ASSERT(me != NULL);
227
228 UNTIL ( (rwlock->rw_owner == me) || /* I own write lock, or */
229 ((rwlock->rw_owner == NULL) && /* no writer and */
230 (rwlock->rw_reader_locks == 0))) { /* no readers, either. */
231
232 rwlock->rw_waiting_writers++;
233 PZ_WaitCondVar(rwlock->rw_writer_waitq, PR_INTERVAL_NO_TIMEOUT);
234 rwlock->rw_waiting_writers--;
235 PR_ASSERT(rwlock->rw_reader_locks >= 0);
236 }
237
238 PR_ASSERT(rwlock->rw_reader_locks == 0);
239 /*
240 * apply write lock
241 */
242 rwlock->rw_owner = me;
243 rwlock->rw_writer_locks++; /* Increment write-lock count */
244
245 PZ_Unlock(rwlock->rw_lock);
246
247 #ifdef NSS_RWLOCK_RANK_ORDER_DEBUG
248 /*
249 * update thread's lock rank
250 */
251 nssRWLock_SetThreadRank(me,rwlock);
252 #endif
253 }
254
255 /* Unlock a Read lock held on this RW lock.
256 */
257 void
258 NSSRWLock_UnlockWrite(NSSRWLock *rwlock)
259 {
260 PRThread *me = PR_GetCurrentThread();
261
262 PZ_Lock(rwlock->rw_lock);
263 PR_ASSERT(rwlock->rw_owner == me); /* lock must be write-locked by me. */
264 PR_ASSERT(rwlock->rw_writer_locks > 0); /* lock must be write locked */
265
266 if ( rwlock->rw_owner == me && /* I own it, and */
267 rwlock->rw_writer_locks > 0 && /* I own it, and */
268 --rwlock->rw_writer_locks == 0) { /* I'm all done with it */
269
270 rwlock->rw_owner = NULL; /* I don't own it any more. */
271
272 /* Give preference to waiting writers. */
273 if (rwlock->rw_waiting_writers > 0) {
274 if (rwlock->rw_reader_locks == 0)
275 PZ_NotifyCondVar(rwlock->rw_writer_waitq);
276 } else if (rwlock->rw_waiting_readers > 0) {
277 PZ_NotifyAllCondVar(rwlock->rw_reader_waitq);
278 }
279 }
280 PZ_Unlock(rwlock->rw_lock);
281
282 #ifdef NSS_RWLOCK_RANK_ORDER_DEBUG
283 /*
284 * update thread's lock rank
285 */
286 nssRWLock_UnsetThreadRank(me, rwlock);
287 #endif
288 return;
289 }
290
291 /* This is primarily for debugging, i.e. for inclusion in ASSERT calls. */
292 PRBool
293 NSSRWLock_HaveWriteLock(NSSRWLock *rwlock) {
294 PRBool ownWriteLock;
295 PRThread *me = PR_GetCurrentThread();
296
297 /* This lock call isn't really necessary.
298 ** If this thread is the owner, that fact cannot change during this call,
299 ** because this thread is in this call.
300 ** If this thread is NOT the owner, the owner could change, but it
301 ** could not become this thread.
302 */
303 #if UNNECESSARY
304 PZ_Lock(rwlock->rw_lock);
305 #endif
306 ownWriteLock = (PRBool)(me == rwlock->rw_owner);
307 #if UNNECESSARY
308 PZ_Unlock(rwlock->rw_lock);
309 #endif
310 return ownWriteLock;
311 }
312
313 #ifdef NSS_RWLOCK_RANK_ORDER_DEBUG
314
315 /*
316 * nssRWLock_SetThreadRank
317 * Set a thread's lock rank, which is the highest of the ranks of all
318 * the locks held by the thread. Pointers to the locks are added to a
319 * per-thread list, which is anchored off a thread-private data key.
320 */
321
322 static void
323 nssRWLock_SetThreadRank(PRThread *me, NSSRWLock *rwlock)
324 {
325 thread_rwlock_stack *lock_stack;
326 PRStatus rv;
327
328 /*
329 * allocated thread-private-data for rwlock list, if not already allocated
330 */
331 if (!nss_thread_rwlock_initialized) {
332 /*
333 * allocate tpd, only if not failed already
334 */
335 if (!nss_thread_rwlock_alloc_failed) {
336 if (PR_NewThreadPrivateIndex(&nss_thread_rwlock,
337 nssRWLock_ReleaseLockStack)
338 == PR_FAILURE) {
339 nss_thread_rwlock_alloc_failed = 1;
340 return;
341 }
342 } else
343 return;
344 }
345 /*
346 * allocate a lock stack
347 */
348 if ((lock_stack = PR_GetThreadPrivate(nss_thread_rwlock)) == NULL) {
349 lock_stack = (thread_rwlock_stack *)
350 PR_CALLOC(1 * sizeof(thread_rwlock_stack));
351 if (lock_stack) {
352 rv = PR_SetThreadPrivate(nss_thread_rwlock, lock_stack);
353 if (rv == PR_FAILURE) {
354 PR_DELETE(lock_stack);
355 nss_thread_rwlock_alloc_failed = 1;
356 return;
357 }
358 } else {
359 nss_thread_rwlock_alloc_failed = 1;
360 return;
361 }
362 }
363 /*
364 * add rwlock to lock stack, if limit is not exceeded
365 */
366 if (lock_stack) {
367 if (lock_stack->trs_index < _NSS_RWLOCK_RANK_ORDER_LIMIT)
368 lock_stack->trs_stack[lock_stack->trs_index++] = rwlock;
369 }
370 nss_thread_rwlock_initialized = 1;
371 }
372
373 static void
374 nssRWLock_ReleaseLockStack(void *lock_stack)
375 {
376 PR_ASSERT(lock_stack);
377 PR_DELETE(lock_stack);
378 }
379
380 /*
381 * nssRWLock_GetThreadRank
382 *
383 * return thread's lock rank. If thread-private-data for the lock
384 * stack is not allocated, return NSS_RWLOCK_RANK_NONE.
385 */
386
387 static PRUint32
388 nssRWLock_GetThreadRank(PRThread *me)
389 {
390 thread_rwlock_stack *lock_stack;
391
392 if (nss_thread_rwlock_initialized) {
393 if ((lock_stack = PR_GetThreadPrivate(nss_thread_rwlock)) == NULL)
394 return (NSS_RWLOCK_RANK_NONE);
395 else
396 return(lock_stack->trs_stack[lock_stack->trs_index - 1]->rw_rank);
397
398 } else
399 return (NSS_RWLOCK_RANK_NONE);
400 }
401
402 /*
403 * nssRWLock_UnsetThreadRank
404 *
405 * remove the rwlock from the lock stack. Since locks may not be
406 * unlocked in a FIFO order, the entire lock stack is searched.
407 */
408
409 static void
410 nssRWLock_UnsetThreadRank(PRThread *me, NSSRWLock *rwlock)
411 {
412 thread_rwlock_stack *lock_stack;
413 int new_index = 0, index, done = 0;
414
415 if (!nss_thread_rwlock_initialized)
416 return;
417
418 lock_stack = PR_GetThreadPrivate(nss_thread_rwlock);
419
420 PR_ASSERT(lock_stack != NULL);
421
422 index = lock_stack->trs_index - 1;
423 while (index-- >= 0) {
424 if ((lock_stack->trs_stack[index] == rwlock) && !done) {
425 /*
426 * reset the slot for rwlock
427 */
428 lock_stack->trs_stack[index] = NULL;
429 done = 1;
430 }
431 /*
432 * search for the lowest-numbered empty slot, above which there are
433 * no non-empty slots
434 */
435 if ((lock_stack->trs_stack[index] != NULL) && !new_index)
436 new_index = index + 1;
437 if (done && new_index)
438 break;
439 }
440 /*
441 * set top of stack to highest numbered empty slot
442 */
443 lock_stack->trs_index = new_index;
444
445 }
446
447 #endif /* NSS_RWLOCK_RANK_ORDER_DEBUG */
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)