Mercurial > trustbridge > nss-cmake-static
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 */ |