Mercurial > trustbridge > nss-cmake-static
comparison nspr/pr/src/threads/combined/prulock.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 #if defined(WIN95) | |
9 /* | |
10 ** Some local variables report warnings on Win95 because the code paths | |
11 ** using them are conditioned on HAVE_CUSTOME_USER_THREADS. | |
12 ** The pragma suppresses the warning. | |
13 ** | |
14 */ | |
15 #pragma warning(disable : 4101) | |
16 #endif | |
17 | |
18 | |
19 void _PR_InitLocks(void) | |
20 { | |
21 _PR_MD_INIT_LOCKS(); | |
22 } | |
23 | |
24 /* | |
25 ** Deal with delayed interrupts/requested reschedule during interrupt | |
26 ** re-enables. | |
27 */ | |
28 void _PR_IntsOn(_PRCPU *cpu) | |
29 { | |
30 PRUintn missed, pri, i; | |
31 _PRInterruptTable *it; | |
32 PRThread *me; | |
33 | |
34 PR_ASSERT(cpu); /* Global threads don't have CPUs */ | |
35 PR_ASSERT(_PR_MD_GET_INTSOFF() > 0); | |
36 me = _PR_MD_CURRENT_THREAD(); | |
37 PR_ASSERT(!(me->flags & _PR_IDLE_THREAD)); | |
38 | |
39 /* | |
40 ** Process delayed interrupts. This logic is kinda scary because we | |
41 ** need to avoid losing an interrupt (it's ok to delay an interrupt | |
42 ** until later). | |
43 ** | |
44 ** There are two missed state words. _pr_ints.where indicates to the | |
45 ** interrupt handler which state word is currently safe for | |
46 ** modification. | |
47 ** | |
48 ** This code scans both interrupt state words, using the where flag | |
49 ** to indicate to the interrupt which state word is safe for writing. | |
50 ** If an interrupt comes in during a scan the other word will be | |
51 ** modified. This modification will be noticed during the next | |
52 ** iteration of the loop or during the next call to this routine. | |
53 */ | |
54 for (i = 0; i < 2; i++) { | |
55 cpu->where = (1 - i); | |
56 missed = cpu->u.missed[i]; | |
57 if (missed != 0) { | |
58 cpu->u.missed[i] = 0; | |
59 for (it = _pr_interruptTable; it->name; it++) { | |
60 if (missed & it->missed_bit) { | |
61 PR_LOG(_pr_sched_lm, PR_LOG_MIN, | |
62 ("IntsOn[0]: %s intr", it->name)); | |
63 (*it->handler)(); | |
64 } | |
65 } | |
66 } | |
67 } | |
68 | |
69 if (cpu->u.missed[3] != 0) { | |
70 _PRCPU *cpu; | |
71 | |
72 _PR_THREAD_LOCK(me); | |
73 me->state = _PR_RUNNABLE; | |
74 pri = me->priority; | |
75 | |
76 cpu = me->cpu; | |
77 _PR_RUNQ_LOCK(cpu); | |
78 _PR_ADD_RUNQ(me, cpu, pri); | |
79 _PR_RUNQ_UNLOCK(cpu); | |
80 _PR_THREAD_UNLOCK(me); | |
81 _PR_MD_SWITCH_CONTEXT(me); | |
82 } | |
83 } | |
84 | |
85 /* | |
86 ** Unblock the first runnable waiting thread. Skip over | |
87 ** threads that are trying to be suspended | |
88 ** Note: Caller must hold _PR_LOCK_LOCK() | |
89 */ | |
90 void _PR_UnblockLockWaiter(PRLock *lock) | |
91 { | |
92 PRThread *t = NULL; | |
93 PRThread *me; | |
94 PRCList *q; | |
95 | |
96 q = lock->waitQ.next; | |
97 PR_ASSERT(q != &lock->waitQ); | |
98 while (q != &lock->waitQ) { | |
99 /* Unblock first waiter */ | |
100 t = _PR_THREAD_CONDQ_PTR(q); | |
101 | |
102 /* | |
103 ** We are about to change the thread's state to runnable and for local | |
104 ** threads, we are going to assign a cpu to it. So, protect thread's | |
105 ** data structure. | |
106 */ | |
107 _PR_THREAD_LOCK(t); | |
108 | |
109 if (t->flags & _PR_SUSPENDING) { | |
110 q = q->next; | |
111 _PR_THREAD_UNLOCK(t); | |
112 continue; | |
113 } | |
114 | |
115 /* Found a runnable thread */ | |
116 PR_ASSERT(t->state == _PR_LOCK_WAIT); | |
117 PR_ASSERT(t->wait.lock == lock); | |
118 t->wait.lock = 0; | |
119 PR_REMOVE_LINK(&t->waitQLinks); /* take it off lock's waitQ */ | |
120 | |
121 /* | |
122 ** If this is a native thread, nothing else to do except to wake it | |
123 ** up by calling the machine dependent wakeup routine. | |
124 ** | |
125 ** If this is a local thread, we need to assign it a cpu and | |
126 ** put the thread on that cpu's run queue. There are two cases to | |
127 ** take care of. If the currently running thread is also a local | |
128 ** thread, we just assign our own cpu to that thread and put it on | |
129 ** the cpu's run queue. If the the currently running thread is a | |
130 ** native thread, we assign the primordial cpu to it (on NT, | |
131 ** MD_WAKEUP handles the cpu assignment). | |
132 */ | |
133 | |
134 if ( !_PR_IS_NATIVE_THREAD(t) ) { | |
135 | |
136 t->state = _PR_RUNNABLE; | |
137 | |
138 me = _PR_MD_CURRENT_THREAD(); | |
139 | |
140 _PR_AddThreadToRunQ(me, t); | |
141 _PR_THREAD_UNLOCK(t); | |
142 } else { | |
143 t->state = _PR_RUNNING; | |
144 _PR_THREAD_UNLOCK(t); | |
145 } | |
146 _PR_MD_WAKEUP_WAITER(t); | |
147 break; | |
148 } | |
149 return; | |
150 } | |
151 | |
152 /************************************************************************/ | |
153 | |
154 | |
155 PR_IMPLEMENT(PRLock*) PR_NewLock(void) | |
156 { | |
157 PRLock *lock; | |
158 | |
159 if (!_pr_initialized) _PR_ImplicitInitialization(); | |
160 | |
161 lock = PR_NEWZAP(PRLock); | |
162 if (lock) { | |
163 if (_PR_InitLock(lock) != PR_SUCCESS) { | |
164 PR_DELETE(lock); | |
165 return NULL; | |
166 } | |
167 } | |
168 return lock; | |
169 } | |
170 | |
171 PRStatus _PR_InitLock(PRLock *lock) | |
172 { | |
173 if (_PR_MD_NEW_LOCK(&lock->ilock) != PR_SUCCESS) { | |
174 return PR_FAILURE; | |
175 } | |
176 PR_INIT_CLIST(&lock->links); | |
177 PR_INIT_CLIST(&lock->waitQ); | |
178 return PR_SUCCESS; | |
179 } | |
180 | |
181 /* | |
182 ** Destroy the given lock "lock". There is no point in making this race | |
183 ** free because if some other thread has the pointer to this lock all | |
184 ** bets are off. | |
185 */ | |
186 PR_IMPLEMENT(void) PR_DestroyLock(PRLock *lock) | |
187 { | |
188 _PR_FreeLock(lock); | |
189 PR_DELETE(lock); | |
190 } | |
191 | |
192 void _PR_FreeLock(PRLock *lock) | |
193 { | |
194 PR_ASSERT(lock->owner == 0); | |
195 _PR_MD_FREE_LOCK(&lock->ilock); | |
196 } | |
197 | |
198 extern PRThread *suspendAllThread; | |
199 /* | |
200 ** Lock the lock. | |
201 */ | |
202 PR_IMPLEMENT(void) PR_Lock(PRLock *lock) | |
203 { | |
204 PRThread *me = _PR_MD_CURRENT_THREAD(); | |
205 PRIntn is; | |
206 PRThread *t; | |
207 PRCList *q; | |
208 | |
209 PR_ASSERT(me != suspendAllThread); | |
210 PR_ASSERT(!(me->flags & _PR_IDLE_THREAD)); | |
211 PR_ASSERT(lock != NULL); | |
212 #ifdef _PR_GLOBAL_THREADS_ONLY | |
213 _PR_MD_LOCK(&lock->ilock); | |
214 PR_ASSERT(lock->owner == 0); | |
215 lock->owner = me; | |
216 return; | |
217 #else /* _PR_GLOBAL_THREADS_ONLY */ | |
218 | |
219 if (_native_threads_only) { | |
220 _PR_MD_LOCK(&lock->ilock); | |
221 PR_ASSERT(lock->owner == 0); | |
222 lock->owner = me; | |
223 return; | |
224 } | |
225 | |
226 if (!_PR_IS_NATIVE_THREAD(me)) | |
227 _PR_INTSOFF(is); | |
228 | |
229 PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || _PR_MD_GET_INTSOFF() != 0); | |
230 | |
231 retry: | |
232 _PR_LOCK_LOCK(lock); | |
233 if (lock->owner == 0) { | |
234 /* Just got the lock */ | |
235 lock->owner = me; | |
236 lock->priority = me->priority; | |
237 /* Add the granted lock to this owning thread's lock list */ | |
238 PR_APPEND_LINK(&lock->links, &me->lockList); | |
239 _PR_LOCK_UNLOCK(lock); | |
240 if (!_PR_IS_NATIVE_THREAD(me)) | |
241 _PR_FAST_INTSON(is); | |
242 return; | |
243 } | |
244 | |
245 /* If this thread already owns this lock, then it is a deadlock */ | |
246 PR_ASSERT(lock->owner != me); | |
247 | |
248 PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || _PR_MD_GET_INTSOFF() != 0); | |
249 | |
250 #if 0 | |
251 if (me->priority > lock->owner->priority) { | |
252 /* | |
253 ** Give the lock owner a priority boost until we get the | |
254 ** lock. Record the priority we boosted it to. | |
255 */ | |
256 lock->boostPriority = me->priority; | |
257 _PR_SetThreadPriority(lock->owner, me->priority); | |
258 } | |
259 #endif | |
260 | |
261 /* | |
262 Add this thread to the asked for lock's list of waiting threads. We | |
263 add this thread thread in the right priority order so when the unlock | |
264 occurs, the thread with the higher priority will get the lock. | |
265 */ | |
266 q = lock->waitQ.next; | |
267 if (q == &lock->waitQ || _PR_THREAD_CONDQ_PTR(q)->priority == | |
268 _PR_THREAD_CONDQ_PTR(lock->waitQ.prev)->priority) { | |
269 /* | |
270 * If all the threads in the lock waitQ have the same priority, | |
271 * then avoid scanning the list: insert the element at the end. | |
272 */ | |
273 q = &lock->waitQ; | |
274 } else { | |
275 /* Sort thread into lock's waitQ at appropriate point */ | |
276 /* Now scan the list for where to insert this entry */ | |
277 while (q != &lock->waitQ) { | |
278 t = _PR_THREAD_CONDQ_PTR(lock->waitQ.next); | |
279 if (me->priority > t->priority) { | |
280 /* Found a lower priority thread to insert in front of */ | |
281 break; | |
282 } | |
283 q = q->next; | |
284 } | |
285 } | |
286 PR_INSERT_BEFORE(&me->waitQLinks, q); | |
287 | |
288 /* | |
289 Now grab the threadLock since we are about to change the state. We have | |
290 to do this since a PR_Suspend or PR_SetThreadPriority type call that takes | |
291 a PRThread* as an argument could be changing the state of this thread from | |
292 a thread running on a different cpu. | |
293 */ | |
294 | |
295 _PR_THREAD_LOCK(me); | |
296 me->state = _PR_LOCK_WAIT; | |
297 me->wait.lock = lock; | |
298 _PR_THREAD_UNLOCK(me); | |
299 | |
300 _PR_LOCK_UNLOCK(lock); | |
301 | |
302 _PR_MD_WAIT(me, PR_INTERVAL_NO_TIMEOUT); | |
303 goto retry; | |
304 | |
305 #endif /* _PR_GLOBAL_THREADS_ONLY */ | |
306 } | |
307 | |
308 /* | |
309 ** Unlock the lock. | |
310 */ | |
311 PR_IMPLEMENT(PRStatus) PR_Unlock(PRLock *lock) | |
312 { | |
313 PRCList *q; | |
314 PRThreadPriority pri, boost; | |
315 PRIntn is; | |
316 PRThread *me = _PR_MD_CURRENT_THREAD(); | |
317 | |
318 PR_ASSERT(lock != NULL); | |
319 PR_ASSERT(lock->owner == me); | |
320 PR_ASSERT(me != suspendAllThread); | |
321 PR_ASSERT(!(me->flags & _PR_IDLE_THREAD)); | |
322 if (lock->owner != me) { | |
323 return PR_FAILURE; | |
324 } | |
325 | |
326 #ifdef _PR_GLOBAL_THREADS_ONLY | |
327 lock->owner = 0; | |
328 _PR_MD_UNLOCK(&lock->ilock); | |
329 return PR_SUCCESS; | |
330 #else /* _PR_GLOBAL_THREADS_ONLY */ | |
331 | |
332 if (_native_threads_only) { | |
333 lock->owner = 0; | |
334 _PR_MD_UNLOCK(&lock->ilock); | |
335 return PR_SUCCESS; | |
336 } | |
337 | |
338 if (!_PR_IS_NATIVE_THREAD(me)) | |
339 _PR_INTSOFF(is); | |
340 _PR_LOCK_LOCK(lock); | |
341 | |
342 /* Remove the lock from the owning thread's lock list */ | |
343 PR_REMOVE_LINK(&lock->links); | |
344 pri = lock->priority; | |
345 boost = lock->boostPriority; | |
346 if (boost > pri) { | |
347 /* | |
348 ** We received a priority boost during the time we held the lock. | |
349 ** We need to figure out what priority to move to by scanning | |
350 ** down our list of lock's that we are still holding and using | |
351 ** the highest boosted priority found. | |
352 */ | |
353 q = me->lockList.next; | |
354 while (q != &me->lockList) { | |
355 PRLock *ll = _PR_LOCK_PTR(q); | |
356 if (ll->boostPriority > pri) { | |
357 pri = ll->boostPriority; | |
358 } | |
359 q = q->next; | |
360 } | |
361 if (pri != me->priority) { | |
362 _PR_SetThreadPriority(me, pri); | |
363 } | |
364 } | |
365 | |
366 /* Unblock the first waiting thread */ | |
367 q = lock->waitQ.next; | |
368 if (q != &lock->waitQ) | |
369 _PR_UnblockLockWaiter(lock); | |
370 lock->boostPriority = PR_PRIORITY_LOW; | |
371 lock->owner = 0; | |
372 _PR_LOCK_UNLOCK(lock); | |
373 if (!_PR_IS_NATIVE_THREAD(me)) | |
374 _PR_INTSON(is); | |
375 return PR_SUCCESS; | |
376 #endif /* _PR_GLOBAL_THREADS_ONLY */ | |
377 } | |
378 | |
379 /* | |
380 ** If the current thread owns |lock|, this assertion is guaranteed to | |
381 ** succeed. Otherwise, the behavior of this function is undefined. | |
382 */ | |
383 PR_IMPLEMENT(void) PR_AssertCurrentThreadOwnsLock(PRLock *lock) | |
384 { | |
385 PRThread *me = _PR_MD_CURRENT_THREAD(); | |
386 PR_ASSERT(lock->owner == me); | |
387 } | |
388 | |
389 /* | |
390 ** Test and then lock the lock if it's not already locked by some other | |
391 ** thread. Return PR_FALSE if some other thread owned the lock at the | |
392 ** time of the call. | |
393 */ | |
394 PR_IMPLEMENT(PRBool) PR_TestAndLock(PRLock *lock) | |
395 { | |
396 PRThread *me = _PR_MD_CURRENT_THREAD(); | |
397 PRBool rv = PR_FALSE; | |
398 PRIntn is; | |
399 | |
400 #ifdef _PR_GLOBAL_THREADS_ONLY | |
401 is = _PR_MD_TEST_AND_LOCK(&lock->ilock); | |
402 if (is == 0) { | |
403 lock->owner = me; | |
404 return PR_TRUE; | |
405 } | |
406 return PR_FALSE; | |
407 #else /* _PR_GLOBAL_THREADS_ONLY */ | |
408 | |
409 #ifndef _PR_LOCAL_THREADS_ONLY | |
410 if (_native_threads_only) { | |
411 is = _PR_MD_TEST_AND_LOCK(&lock->ilock); | |
412 if (is == 0) { | |
413 lock->owner = me; | |
414 return PR_TRUE; | |
415 } | |
416 return PR_FALSE; | |
417 } | |
418 #endif | |
419 | |
420 if (!_PR_IS_NATIVE_THREAD(me)) | |
421 _PR_INTSOFF(is); | |
422 | |
423 _PR_LOCK_LOCK(lock); | |
424 if (lock->owner == 0) { | |
425 /* Just got the lock */ | |
426 lock->owner = me; | |
427 lock->priority = me->priority; | |
428 /* Add the granted lock to this owning thread's lock list */ | |
429 PR_APPEND_LINK(&lock->links, &me->lockList); | |
430 rv = PR_TRUE; | |
431 } | |
432 _PR_LOCK_UNLOCK(lock); | |
433 | |
434 if (!_PR_IS_NATIVE_THREAD(me)) | |
435 _PR_INTSON(is); | |
436 return rv; | |
437 #endif /* _PR_GLOBAL_THREADS_ONLY */ | |
438 } | |
439 | |
440 /************************************************************************/ | |
441 /************************************************************************/ | |
442 /***********************ROUTINES FOR DCE EMULATION***********************/ | |
443 /************************************************************************/ | |
444 /************************************************************************/ | |
445 PR_IMPLEMENT(PRStatus) PRP_TryLock(PRLock *lock) | |
446 { return (PR_TestAndLock(lock)) ? PR_SUCCESS : PR_FAILURE; } |