Windows: LockOrderValidation memory usage optimization
[openafs.git] / src / WINNT / client_osi / osibasel.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /* Copyright (C) 1994 Cazamar Systems, Inc. */
11
12
13 #include <afs/param.h>
14 #include <afs/stds.h>
15
16 #include <windows.h>
17 #include "osi.h"
18 #include <assert.h>
19 #include <stdio.h>
20
21 /* atomicity-providing critical sections */
22 CRITICAL_SECTION osi_baseAtomicCS[OSI_MUTEXHASHSIZE];
23 static long     atomicIndexCounter = 0;
24
25 /* Thread local storage index for lock tracking */
26 static DWORD tls_LockRefH = 0;
27 static DWORD tls_LockRefT = 0;
28 static BOOLEAN lockOrderValidation = 0;
29 static osi_lock_ref_t * lock_ref_FreeListp = NULL;
30 static osi_lock_ref_t * lock_ref_FreeListEndp = NULL;
31 CRITICAL_SECTION lock_ref_CS;
32
33 void osi_BaseInit(void)
34 {
35     int i;
36
37     for(i=0; i<OSI_MUTEXHASHSIZE; i++)
38         InitializeCriticalSection(&osi_baseAtomicCS[i]);
39
40     if ((tls_LockRefH = TlsAlloc()) == TLS_OUT_OF_INDEXES)
41         osi_panic("TlsAlloc(tls_LockRefH) failure", __FILE__, __LINE__);
42
43     if ((tls_LockRefT = TlsAlloc()) == TLS_OUT_OF_INDEXES)
44         osi_panic("TlsAlloc(tls_LockRefT) failure", __FILE__, __LINE__);
45
46     InitializeCriticalSection(&lock_ref_CS);
47 }
48
49 void
50 osi_SetLockOrderValidation(int on)
51 {
52     lockOrderValidation = (BOOLEAN)on;
53 }
54
55 static osi_lock_ref_t *
56 lock_GetLockRef(void * lockp, char type)
57 {
58     osi_lock_ref_t * lockRefp = NULL;
59
60     EnterCriticalSection(&lock_ref_CS);
61     if (lock_ref_FreeListp) {
62         lockRefp = lock_ref_FreeListp;
63         osi_QRemoveHT( (osi_queue_t **) &lock_ref_FreeListp,
64                        (osi_queue_t **) &lock_ref_FreeListEndp,
65                        &lockRefp->q);
66     }
67     LeaveCriticalSection(&lock_ref_CS);
68
69     if (lockRefp == NULL)
70         lockRefp = (osi_lock_ref_t *)malloc(sizeof(osi_lock_ref_t));
71
72     memset(lockRefp, 0, sizeof(osi_lock_ref_t));
73     lockRefp->type = type;
74     switch (type) {
75     case OSI_LOCK_MUTEX:
76         lockRefp->mx = lockp;
77         break;
78     case OSI_LOCK_RW:
79         lockRefp->rw = lockp;
80         break;
81     default:
82         osi_panic("Invalid Lock Type", __FILE__, __LINE__);
83     }
84
85     return lockRefp;
86 }
87
88 static void
89 lock_FreeLockRef(osi_lock_ref_t * lockRefp)
90 {
91     EnterCriticalSection(&lock_ref_CS);
92     osi_QAddH( (osi_queue_t **) &lock_ref_FreeListp,
93                (osi_queue_t **) &lock_ref_FreeListEndp,
94                &lockRefp->q);
95     LeaveCriticalSection(&lock_ref_CS);
96 }
97
98 void lock_VerifyOrderRW(osi_queue_t *lockRefH, osi_queue_t *lockRefT, osi_rwlock_t *lockp)
99 {
100     char msg[512];
101     osi_lock_ref_t * lockRefp;
102
103     for (lockRefp = (osi_lock_ref_t *)lockRefH ; lockRefp; lockRefp = (osi_lock_ref_t *)osi_QNext(&lockRefp->q)) {
104         if (lockRefp->type == OSI_LOCK_RW) {
105             if (lockRefp->rw == lockp) {
106                 sprintf(msg, "RW Lock 0x%p level %d already held", lockp, lockp->level);
107                 osi_panic(msg, __FILE__, __LINE__);
108             }
109             if (lockRefp->rw->level > lockp->level) {
110                 sprintf(msg, "Lock hierarchy violation Held lock 0x%p level %d > Requested lock 0x%p level %d",
111                          lockRefp->rw, lockRefp->rw->level, lockp, lockp->level);
112                 osi_panic(msg, __FILE__, __LINE__);
113             }
114         } else {
115             if (lockRefp->mx->level > lockp->level) {
116                 sprintf(msg, "Lock hierarchy violation Held lock 0x%p level %d > Requested lock 0x%p level %d",
117                          lockRefp->mx, lockRefp->mx->level, lockp, lockp->level);
118                 osi_panic(msg, __FILE__, __LINE__);
119             }
120             osi_assertx(lockRefp->mx->level <= lockp->level, "Lock hierarchy violation");
121         }
122     }
123 }
124
125 void lock_VerifyOrderMX(osi_queue_t *lockRefH, osi_queue_t *lockRefT, osi_mutex_t *lockp)
126 {
127     char msg[512];
128     osi_lock_ref_t * lockRefp;
129
130     for (lockRefp = (osi_lock_ref_t *)lockRefH ; lockRefp; lockRefp = (osi_lock_ref_t *)osi_QNext(&lockRefp->q)) {
131         if (lockRefp->type == OSI_LOCK_MUTEX) {
132             if (lockRefp->mx == lockp) {
133                 sprintf(msg, "MX Lock 0x%p level %d already held", lockp, lockp->level);
134                 osi_panic(msg, __FILE__, __LINE__);
135             }
136             if (lockRefp->mx->level > lockp->level) {
137                 sprintf(msg, "Lock hierarchy violation Held lock 0x%p level %d > Requested lock 0x%p level %d",
138                          lockRefp->mx, lockRefp->mx->level, lockp, lockp->level);
139                 osi_panic(msg, __FILE__, __LINE__);
140             }
141         } else {
142             if (lockRefp->rw->level > lockp->level) {
143                 sprintf(msg, "Lock hierarchy violation Held lock 0x%p level %d > Requested lock 0x%p level %d",
144                          lockRefp->rw, lockRefp->rw->level, lockp, lockp->level);
145                 osi_panic(msg, __FILE__, __LINE__);
146             }
147         }
148     }
149 }
150
151 void lock_ObtainWrite(osi_rwlock_t *lockp)
152 {
153     long i;
154     CRITICAL_SECTION *csp;
155     osi_queue_t * lockRefH, *lockRefT;
156     osi_lock_ref_t *lockRefp;
157
158     if ((i=lockp->type) != 0) {
159         if (i >= 0 && i < OSI_NLOCKTYPES)
160             (osi_lockOps[i]->ObtainWriteProc)(lockp);
161         return;
162     }
163
164     if (lockOrderValidation) {
165         lockRefH = (osi_queue_t *)TlsGetValue(tls_LockRefH);
166         lockRefT = (osi_queue_t *)TlsGetValue(tls_LockRefT);
167
168         if (lockp->level != 0)
169             lock_VerifyOrderRW(lockRefH, lockRefT, lockp);
170     }
171
172     /* otherwise we're the fast base type */
173     csp = &osi_baseAtomicCS[lockp->atomicIndex];
174     EnterCriticalSection(csp);
175
176     /* here we have the fast lock, so see if we can obtain the real lock */
177     if (lockp->waiters > 0 || (lockp->flags & OSI_LOCKFLAG_EXCL) ||
178         (lockp->readers > 0)) {
179         lockp->waiters++;
180         osi_TWait(&lockp->d.turn, OSI_SLEEPINFO_W4WRITE, &lockp->flags, csp);
181         lockp->waiters--;
182         osi_assert(lockp->readers == 0 && (lockp->flags & OSI_LOCKFLAG_EXCL));
183     }
184     else {
185         /* if we're here, all clear to set the lock */
186         lockp->flags |= OSI_LOCKFLAG_EXCL;
187     }
188
189     lockp->tid = thrd_Current();
190
191     LeaveCriticalSection(csp);
192
193     if (lockOrderValidation) {
194         lockRefp = lock_GetLockRef(lockp, OSI_LOCK_RW);
195         osi_QAddH(&lockRefH, &lockRefT, &lockRefp->q);
196         TlsSetValue(tls_LockRefH, lockRefH);
197         TlsSetValue(tls_LockRefT, lockRefT);
198     }
199 }
200
201 void lock_ObtainRead(osi_rwlock_t *lockp)
202 {
203     long i;
204     CRITICAL_SECTION *csp;
205     osi_queue_t * lockRefH, *lockRefT;
206     osi_lock_ref_t *lockRefp;
207
208     if ((i=lockp->type) != 0) {
209         if (i >= 0 && i < OSI_NLOCKTYPES)
210             (osi_lockOps[i]->ObtainReadProc)(lockp);
211         return;
212     }
213
214     if (lockOrderValidation) {
215         lockRefH = (osi_queue_t *)TlsGetValue(tls_LockRefH);
216         lockRefT = (osi_queue_t *)TlsGetValue(tls_LockRefT);
217
218         if (lockp->level != 0)
219             lock_VerifyOrderRW(lockRefH, lockRefT, lockp);
220     }
221
222     /* otherwise we're the fast base type */
223     csp = &osi_baseAtomicCS[lockp->atomicIndex];
224     EnterCriticalSection(csp);
225
226     /* here we have the fast lock, so see if we can obtain the real lock */
227     if (lockp->waiters > 0 || (lockp->flags & OSI_LOCKFLAG_EXCL)) {
228         lockp->waiters++;
229         osi_TWait(&lockp->d.turn, OSI_SLEEPINFO_W4READ, &lockp->readers, csp);
230         lockp->waiters--;
231         osi_assert(!(lockp->flags & OSI_LOCKFLAG_EXCL) && lockp->readers > 0);
232     }
233     else {
234         /* if we're here, all clear to set the lock */
235         lockp->readers++;
236     }
237
238     LeaveCriticalSection(csp);
239
240     if (lockOrderValidation) {
241         lockRefp = lock_GetLockRef(lockp, OSI_LOCK_RW);
242         osi_QAddH(&lockRefH, &lockRefT, &lockRefp->q);
243         TlsSetValue(tls_LockRefH, lockRefH);
244         TlsSetValue(tls_LockRefT, lockRefT);
245     }
246 }
247
248 void lock_ReleaseRead(osi_rwlock_t *lockp)
249 {
250     long i;
251     CRITICAL_SECTION *csp;
252     osi_queue_t * lockRefH, *lockRefT;
253     osi_lock_ref_t *lockRefp;
254
255     if ((i = lockp->type) != 0) {
256         if (i >= 0 && i < OSI_NLOCKTYPES)
257             (osi_lockOps[i]->ReleaseReadProc)(lockp);
258         return;
259     }
260
261     if (lockOrderValidation && lockp->level != 0) {
262         int found = 0;
263         lockRefH = (osi_queue_t *)TlsGetValue(tls_LockRefH);
264         lockRefT = (osi_queue_t *)TlsGetValue(tls_LockRefT);
265
266         for (lockRefp = (osi_lock_ref_t *)lockRefH ; lockRefp; lockRefp = (osi_lock_ref_t *)osi_QNext(&lockRefp->q)) {
267             if (lockRefp->type == OSI_LOCK_RW && lockRefp->rw == lockp) {
268                 osi_QRemoveHT(&lockRefH, &lockRefT, &lockRefp->q);
269                 lock_FreeLockRef(lockRefp);
270                 found = 1;
271                 break;
272             }
273         }
274         osi_assertx(found, "read lock not found in TLS queue");
275
276         TlsSetValue(tls_LockRefH, lockRefH);
277         TlsSetValue(tls_LockRefT, lockRefT);
278     }
279
280     /* otherwise we're the fast base type */
281     csp = &osi_baseAtomicCS[lockp->atomicIndex];
282     EnterCriticalSection(csp);
283
284     osi_assertx(lockp->readers > 0, "read lock not held");
285
286     /* releasing a read lock can allow readers or writers */
287     if (--lockp->readers == 0 && !osi_TEmpty(&lockp->d.turn)) {
288         osi_TSignalForMLs(&lockp->d.turn, 0, csp);
289     }
290     else {
291         /* and finally release the big lock */
292         LeaveCriticalSection(csp);
293     }
294 }
295
296 void lock_ReleaseWrite(osi_rwlock_t *lockp)
297 {
298     long i;
299     CRITICAL_SECTION *csp;
300     osi_queue_t * lockRefH, *lockRefT;
301     osi_lock_ref_t *lockRefp;
302
303     if ((i = lockp->type) != 0) {
304         if (i >= 0 && i < OSI_NLOCKTYPES)
305             (osi_lockOps[i]->ReleaseWriteProc)(lockp);
306         return;
307     }
308
309     if (lockOrderValidation && lockp->level != 0) {
310         int found = 0;
311         lockRefH = (osi_queue_t *)TlsGetValue(tls_LockRefH);
312         lockRefT = (osi_queue_t *)TlsGetValue(tls_LockRefT);
313
314         for (lockRefp = (osi_lock_ref_t *)lockRefH ; lockRefp; lockRefp = (osi_lock_ref_t *)osi_QNext(&lockRefp->q)) {
315             if (lockRefp->type == OSI_LOCK_RW && lockRefp->rw == lockp) {
316                 osi_QRemoveHT(&lockRefH, &lockRefT, &lockRefp->q);
317                 lock_FreeLockRef(lockRefp);
318                 found = 1;
319                 break;
320             }
321         }
322         osi_assertx(found, "write lock not found in TLS queue");
323
324         TlsSetValue(tls_LockRefH, lockRefH);
325         TlsSetValue(tls_LockRefT, lockRefT);
326     }
327
328     /* otherwise we're the fast base type */
329     csp = &osi_baseAtomicCS[lockp->atomicIndex];
330     EnterCriticalSection(csp);
331
332     osi_assertx(lockp->flags & OSI_LOCKFLAG_EXCL, "write lock not held");
333     osi_assertx(lockp->tid == thrd_Current(), "write lock not held by current thread");
334
335     lockp->tid = 0;
336
337     lockp->flags &= ~OSI_LOCKFLAG_EXCL;
338     if (!osi_TEmpty(&lockp->d.turn)) {
339         osi_TSignalForMLs(&lockp->d.turn, 0, csp);
340     }
341     else {
342         /* and finally release the big lock */
343         LeaveCriticalSection(csp);
344     }
345 }
346
347 void lock_ConvertWToR(osi_rwlock_t *lockp)
348 {
349     long i;
350     CRITICAL_SECTION *csp;
351
352     if ((i = lockp->type) != 0) {
353         if (i >= 0 && i < OSI_NLOCKTYPES)
354             (osi_lockOps[i]->ConvertWToRProc)(lockp);
355         return;
356     }
357
358     /* otherwise we're the fast base type */
359     csp = &osi_baseAtomicCS[lockp->atomicIndex];
360     EnterCriticalSection(csp);
361
362     osi_assertx(lockp->flags & OSI_LOCKFLAG_EXCL, "write lock not held");
363     osi_assertx(lockp->tid == thrd_Current(), "write lock not held by current thread");
364
365     /* convert write lock to read lock */
366     lockp->flags &= ~OSI_LOCKFLAG_EXCL;
367     lockp->readers++;
368
369     lockp->tid = 0;
370
371     if (!osi_TEmpty(&lockp->d.turn)) {
372         osi_TSignalForMLs(&lockp->d.turn, /* still have readers */ 1, csp);
373     }
374     else {
375         /* and finally release the big lock */
376         LeaveCriticalSection(csp);
377     }
378 }
379
380 void lock_ConvertRToW(osi_rwlock_t *lockp)
381 {
382     long i;
383     CRITICAL_SECTION *csp;
384
385     if ((i = lockp->type) != 0) {
386         if (i >= 0 && i < OSI_NLOCKTYPES)
387             (osi_lockOps[i]->ConvertRToWProc)(lockp);
388         return;
389     }
390
391     /* otherwise we're the fast base type */
392     csp = &osi_baseAtomicCS[lockp->atomicIndex];
393     EnterCriticalSection(csp);
394
395     osi_assertx(!(lockp->flags & OSI_LOCKFLAG_EXCL), "write lock held");
396     osi_assertx(lockp->readers > 0, "read lock not held");
397
398     if (--lockp->readers == 0) {
399         /* convert read lock to write lock */
400         lockp->flags |= OSI_LOCKFLAG_EXCL;
401     } else {
402         lockp->waiters++;
403         osi_TWait(&lockp->d.turn, OSI_SLEEPINFO_W4WRITE, &lockp->flags, csp);
404         lockp->waiters--;
405         osi_assert(lockp->readers == 0 && (lockp->flags & OSI_LOCKFLAG_EXCL));
406     }
407
408     lockp->tid = thrd_Current();
409     LeaveCriticalSection(csp);
410 }
411
412 void lock_ObtainMutex(struct osi_mutex *lockp)
413 {
414     long i;
415     CRITICAL_SECTION *csp;
416     osi_queue_t * lockRefH, *lockRefT;
417     osi_lock_ref_t *lockRefp;
418
419     if ((i=lockp->type) != 0) {
420         if (i >= 0 && i < OSI_NLOCKTYPES)
421             (osi_lockOps[i]->ObtainMutexProc)(lockp);
422         return;
423     }
424
425     if (lockOrderValidation) {
426         lockRefH = (osi_queue_t *)TlsGetValue(tls_LockRefH);
427         lockRefT = (osi_queue_t *)TlsGetValue(tls_LockRefT);
428
429         if (lockp->level != 0)
430             lock_VerifyOrderMX(lockRefH, lockRefT, lockp);
431     }
432
433     /* otherwise we're the fast base type */
434     csp = &osi_baseAtomicCS[lockp->atomicIndex];
435     EnterCriticalSection(csp);
436
437     /* here we have the fast lock, so see if we can obtain the real lock */
438     if (lockp->waiters > 0 || (lockp->flags & OSI_LOCKFLAG_EXCL)) {
439         lockp->waiters++;
440         osi_TWait(&lockp->d.turn, OSI_SLEEPINFO_W4WRITE, &lockp->flags, csp);
441         lockp->waiters--;
442         osi_assert(lockp->flags & OSI_LOCKFLAG_EXCL);
443     }
444     else {
445         /* if we're here, all clear to set the lock */
446         lockp->flags |= OSI_LOCKFLAG_EXCL;
447     }
448     lockp->tid = thrd_Current();
449     LeaveCriticalSection(csp);
450
451     if (lockOrderValidation) {
452         lockRefp = lock_GetLockRef(lockp, OSI_LOCK_MUTEX);
453         osi_QAddH(&lockRefH, &lockRefT, &lockRefp->q);
454         TlsSetValue(tls_LockRefH, lockRefH);
455         TlsSetValue(tls_LockRefT, lockRefT);
456     }
457 }
458
459 void lock_ReleaseMutex(struct osi_mutex *lockp)
460 {
461     long i;
462     CRITICAL_SECTION *csp;
463     osi_queue_t * lockRefH, *lockRefT;
464     osi_lock_ref_t *lockRefp;
465
466     if ((i = lockp->type) != 0) {
467         if (i >= 0 && i < OSI_NLOCKTYPES)
468             (osi_lockOps[i]->ReleaseMutexProc)(lockp);
469         return;
470     }
471
472     if (lockOrderValidation && lockp->level != 0) {
473         int found = 0;
474         lockRefH = (osi_queue_t *)TlsGetValue(tls_LockRefH);
475         lockRefT = (osi_queue_t *)TlsGetValue(tls_LockRefT);
476
477         for (lockRefp = (osi_lock_ref_t *)lockRefH ; lockRefp; lockRefp = (osi_lock_ref_t *)osi_QNext(&lockRefp->q)) {
478             if (lockRefp->type == OSI_LOCK_MUTEX && lockRefp->mx == lockp) {
479                 osi_QRemoveHT(&lockRefH, &lockRefT, &lockRefp->q);
480                 lock_FreeLockRef(lockRefp);
481                 found = 1;
482                 break;
483             }
484         }
485
486         osi_assertx(found, "mutex lock not found in TLS queue");
487         TlsSetValue(tls_LockRefH, lockRefH);
488         TlsSetValue(tls_LockRefT, lockRefT);
489     }
490
491     /* otherwise we're the fast base type */
492     csp = &osi_baseAtomicCS[lockp->atomicIndex];
493     EnterCriticalSection(csp);
494
495     osi_assertx(lockp->flags & OSI_LOCKFLAG_EXCL, "mutex not held");
496     osi_assertx(lockp->tid == thrd_Current(), "mutex not held by current thread");
497
498     lockp->flags &= ~OSI_LOCKFLAG_EXCL;
499     lockp->tid = 0;
500     if (!osi_TEmpty(&lockp->d.turn)) {
501         osi_TSignalForMLs(&lockp->d.turn, 0, csp);
502     }
503     else {
504         /* and finally release the big lock */
505         LeaveCriticalSection(csp);
506     }
507 }
508
509 int lock_TryRead(struct osi_rwlock *lockp)
510 {
511     long i;
512     CRITICAL_SECTION *csp;
513     osi_queue_t * lockRefH, *lockRefT;
514     osi_lock_ref_t *lockRefp;
515
516     if ((i=lockp->type) != 0)
517         if (i >= 0 && i < OSI_NLOCKTYPES)
518             return (osi_lockOps[i]->TryReadProc)(lockp);
519
520     if (lockOrderValidation) {
521         lockRefH = (osi_queue_t *)TlsGetValue(tls_LockRefH);
522         lockRefT = (osi_queue_t *)TlsGetValue(tls_LockRefT);
523
524         if (lockp->level != 0) {
525             for (lockRefp = (osi_lock_ref_t *)lockRefH ; lockRefp; lockRefp = (osi_lock_ref_t *)osi_QNext(&lockRefp->q)) {
526                 if (lockRefp->type == OSI_LOCK_RW) {
527                     osi_assertx(lockRefp->rw != lockp, "RW Lock already held");
528                 }
529             }
530         }
531     }
532
533     /* otherwise we're the fast base type */
534     csp = &osi_baseAtomicCS[lockp->atomicIndex];
535     EnterCriticalSection(csp);
536
537     /* here we have the fast lock, so see if we can obtain the real lock */
538     if (lockp->waiters > 0 || (lockp->flags & OSI_LOCKFLAG_EXCL)) {
539         i = 0;
540     }
541     else {
542         /* if we're here, all clear to set the lock */
543         lockp->readers++;
544         i = 1;
545     }
546
547     LeaveCriticalSection(csp);
548
549     if (lockOrderValidation && i) {
550         lockRefp = lock_GetLockRef(lockp, OSI_LOCK_RW);
551         osi_QAddH(&lockRefH, &lockRefT, &lockRefp->q);
552         TlsSetValue(tls_LockRefH, lockRefH);
553         TlsSetValue(tls_LockRefT, lockRefT);
554     }
555
556     return i;
557 }
558
559
560 int lock_TryWrite(struct osi_rwlock *lockp)
561 {
562     long i;
563     CRITICAL_SECTION *csp;
564     osi_queue_t * lockRefH, *lockRefT;
565     osi_lock_ref_t *lockRefp;
566
567     if ((i=lockp->type) != 0)
568         if (i >= 0 && i < OSI_NLOCKTYPES)
569             return (osi_lockOps[i]->TryWriteProc)(lockp);
570
571     if (lockOrderValidation) {
572         lockRefH = (osi_queue_t *)TlsGetValue(tls_LockRefH);
573         lockRefT = (osi_queue_t *)TlsGetValue(tls_LockRefT);
574
575         if (lockp->level != 0) {
576             for (lockRefp = (osi_lock_ref_t *)lockRefH ; lockRefp; lockRefp = (osi_lock_ref_t *)osi_QNext(&lockRefp->q)) {
577                 if (lockRefp->type == OSI_LOCK_RW) {
578                     osi_assertx(lockRefp->rw != lockp, "RW Lock already held");
579                 }
580             }
581         }
582     }
583
584     /* otherwise we're the fast base type */
585     csp = &osi_baseAtomicCS[lockp->atomicIndex];
586     EnterCriticalSection(csp);
587
588     /* here we have the fast lock, so see if we can obtain the real lock */
589     if (lockp->waiters > 0 || (lockp->flags & OSI_LOCKFLAG_EXCL)
590          || (lockp->readers > 0)) {
591         i = 0;
592     }
593     else {
594         /* if we're here, all clear to set the lock */
595         lockp->flags |= OSI_LOCKFLAG_EXCL;
596         i = 1;
597     }
598
599     if (i)
600         lockp->tid = thrd_Current();
601
602     LeaveCriticalSection(csp);
603
604     if (lockOrderValidation && i) {
605         lockRefp = lock_GetLockRef(lockp, OSI_LOCK_RW);
606         osi_QAddH(&lockRefH, &lockRefT, &lockRefp->q);
607         TlsSetValue(tls_LockRefH, lockRefH);
608         TlsSetValue(tls_LockRefT, lockRefT);
609     }
610
611     return i;
612 }
613
614
615 int lock_TryMutex(struct osi_mutex *lockp) {
616     long i;
617     CRITICAL_SECTION *csp;
618     osi_queue_t * lockRefH, *lockRefT;
619     osi_lock_ref_t *lockRefp;
620
621     if ((i=lockp->type) != 0)
622         if (i >= 0 && i < OSI_NLOCKTYPES)
623             return (osi_lockOps[i]->TryMutexProc)(lockp);
624
625     if (lockOrderValidation) {
626         lockRefH = (osi_queue_t *)TlsGetValue(tls_LockRefH);
627         lockRefT = (osi_queue_t *)TlsGetValue(tls_LockRefT);
628
629         if (lockp->level != 0) {
630             for (lockRefp = (osi_lock_ref_t *)lockRefH ; lockRefp; lockRefp = (osi_lock_ref_t *)osi_QNext(&lockRefp->q)) {
631                 if (lockRefp->type == OSI_LOCK_MUTEX) {
632                     osi_assertx(lockRefp->mx != lockp, "Mutex already held");
633                 }
634             }
635         }
636     }
637
638     /* otherwise we're the fast base type */
639     csp = &osi_baseAtomicCS[lockp->atomicIndex];
640     EnterCriticalSection(csp);
641
642     /* here we have the fast lock, so see if we can obtain the real lock */
643     if (lockp->waiters > 0 || (lockp->flags & OSI_LOCKFLAG_EXCL)) {
644         i = 0;
645     }
646     else {
647         /* if we're here, all clear to set the lock */
648         lockp->flags |= OSI_LOCKFLAG_EXCL;
649         i = 1;
650     }
651
652     if (i)
653         lockp->tid = thrd_Current();
654
655     LeaveCriticalSection(csp);
656
657     if (lockOrderValidation && i) {
658         lockRefp = lock_GetLockRef(lockp, OSI_LOCK_MUTEX);
659         osi_QAddH(&lockRefH, &lockRefT, &lockRefp->q);
660         TlsSetValue(tls_LockRefH, lockRefH);
661         TlsSetValue(tls_LockRefT, lockRefT);
662     }
663     return i;
664 }
665
666 void osi_SleepR(LONG_PTR sleepVal, struct osi_rwlock *lockp)
667 {
668     long i;
669     CRITICAL_SECTION *csp;
670     osi_queue_t * lockRefH, *lockRefT;
671     osi_lock_ref_t *lockRefp;
672
673     if ((i = lockp->type) != 0) {
674         if (i >= 0 && i < OSI_NLOCKTYPES)
675             (osi_lockOps[i]->SleepRProc)(sleepVal, lockp);
676         return;
677     }
678
679     if (lockOrderValidation && lockp->level != 0) {
680         lockRefH = (osi_queue_t *)TlsGetValue(tls_LockRefH);
681         lockRefT = (osi_queue_t *)TlsGetValue(tls_LockRefT);
682
683         for (lockRefp = (osi_lock_ref_t *)lockRefH ; lockRefp; lockRefp = (osi_lock_ref_t *)osi_QNext(&lockRefp->q)) {
684             if (lockRefp->type == OSI_LOCK_RW && lockRefp->rw == lockp) {
685                 osi_QRemoveHT(&lockRefH, &lockRefT, &lockRefp->q);
686                 lock_FreeLockRef(lockRefp);
687                 break;
688             }
689         }
690
691         TlsSetValue(tls_LockRefH, lockRefH);
692         TlsSetValue(tls_LockRefT, lockRefT);
693     }
694
695     /* otherwise we're the fast base type */
696     csp = &osi_baseAtomicCS[lockp->atomicIndex];
697     EnterCriticalSection(csp);
698
699     osi_assertx(lockp->readers > 0, "osi_SleepR: not held");
700
701     /* XXX better to get the list of things to wakeup from TSignalForMLs, and
702      * then do the wakeup after SleepSpin releases the low-level mutex.
703      */
704     if (--lockp->readers == 0 && !osi_TEmpty(&lockp->d.turn)) {
705         osi_TSignalForMLs(&lockp->d.turn, 0, NULL);
706     }
707
708     /* now call into scheduler to sleep atomically with releasing spin lock */
709     osi_SleepSpin(sleepVal, csp);
710 }
711
712 void osi_SleepW(LONG_PTR sleepVal, struct osi_rwlock *lockp)
713 {
714     long i;
715     CRITICAL_SECTION *csp;
716     osi_queue_t * lockRefH, *lockRefT;
717     osi_lock_ref_t *lockRefp;
718
719     if ((i = lockp->type) != 0) {
720         if (i >= 0 && i < OSI_NLOCKTYPES)
721             (osi_lockOps[i]->SleepWProc)(sleepVal, lockp);
722         return;
723     }
724
725     if (lockOrderValidation && lockp->level != 0) {
726         lockRefH = (osi_queue_t *)TlsGetValue(tls_LockRefH);
727         lockRefT = (osi_queue_t *)TlsGetValue(tls_LockRefT);
728
729         for (lockRefp = (osi_lock_ref_t *)lockRefH ; lockRefp; lockRefp = (osi_lock_ref_t *)osi_QNext(&lockRefp->q)) {
730             if (lockRefp->type == OSI_LOCK_RW && lockRefp->rw == lockp) {
731                 osi_QRemoveHT(&lockRefH, &lockRefT, &lockRefp->q);
732                 lock_FreeLockRef(lockRefp);
733                 break;
734             }
735         }
736
737         TlsSetValue(tls_LockRefH, lockRefH);
738         TlsSetValue(tls_LockRefT, lockRefT);
739     }
740
741     /* otherwise we're the fast base type */
742     csp = &osi_baseAtomicCS[lockp->atomicIndex];
743     EnterCriticalSection(csp);
744
745     osi_assertx(lockp->flags & OSI_LOCKFLAG_EXCL, "osi_SleepW: not held");
746
747     lockp->flags &= ~OSI_LOCKFLAG_EXCL;
748     if (!osi_TEmpty(&lockp->d.turn)) {
749         osi_TSignalForMLs(&lockp->d.turn, 0, NULL);
750     }
751
752     /* and finally release the big lock */
753     osi_SleepSpin(sleepVal, csp);
754 }
755
756 void osi_SleepM(LONG_PTR sleepVal, struct osi_mutex *lockp)
757 {
758     long i;
759     CRITICAL_SECTION *csp;
760     osi_queue_t * lockRefH, *lockRefT;
761     osi_lock_ref_t *lockRefp;
762
763     if ((i = lockp->type) != 0) {
764         if (i >= 0 && i < OSI_NLOCKTYPES)
765             (osi_lockOps[i]->SleepMProc)(sleepVal, lockp);
766         return;
767     }
768
769     if (lockOrderValidation && lockp->level != 0) {
770         lockRefH = (osi_queue_t *)TlsGetValue(tls_LockRefH);
771         lockRefT = (osi_queue_t *)TlsGetValue(tls_LockRefT);
772
773         for (lockRefp = (osi_lock_ref_t *)lockRefH ; lockRefp; lockRefp = (osi_lock_ref_t *)osi_QNext(&lockRefp->q)) {
774             if (lockRefp->type == OSI_LOCK_MUTEX && lockRefp->mx == lockp) {
775                 osi_QRemoveHT(&lockRefH, &lockRefT, &lockRefp->q);
776                 lock_FreeLockRef(lockRefp);
777                 break;
778             }
779         }
780
781         TlsSetValue(tls_LockRefH, lockRefH);
782         TlsSetValue(tls_LockRefT, lockRefT);
783     }
784
785     /* otherwise we're the fast base type */
786     csp = &osi_baseAtomicCS[lockp->atomicIndex];
787     EnterCriticalSection(csp);
788
789     osi_assertx(lockp->flags & OSI_LOCKFLAG_EXCL, "osi_SleepM not held");
790
791     lockp->flags &= ~OSI_LOCKFLAG_EXCL;
792     if (!osi_TEmpty(&lockp->d.turn)) {
793         osi_TSignalForMLs(&lockp->d.turn, 0, NULL);
794     }
795
796     /* and finally release the big lock */
797     osi_SleepSpin(sleepVal, csp);
798 }
799
800 void lock_FinalizeRWLock(osi_rwlock_t *lockp)
801 {
802     long i;
803
804     if ((i=lockp->type) != 0)
805         if (i >= 0 && i < OSI_NLOCKTYPES)
806             (osi_lockOps[i]->FinalizeRWLockProc)(lockp);
807 }
808
809 void lock_FinalizeMutex(osi_mutex_t *lockp)
810 {
811     long i;
812
813     if ((i=lockp->type) != 0)
814         if (i >= 0 && i < OSI_NLOCKTYPES)
815             (osi_lockOps[i]->FinalizeMutexProc)(lockp);
816 }
817
818 void lock_InitializeMutex(osi_mutex_t *mp, char *namep, unsigned short level)
819 {
820     int i;
821
822     if ((i = osi_lockTypeDefault) > 0) {
823         if (i >= 0 && i < OSI_NLOCKTYPES)
824             (osi_lockOps[i]->InitializeMutexProc)(mp, namep, level);
825         return;
826     }
827
828     /* otherwise we have the base case, which requires no special
829      * initialization.
830      */
831     mp->type = 0;
832     mp->flags = 0;
833     mp->tid = 0;
834     mp->atomicIndex = (unsigned short)(InterlockedIncrement(&atomicIndexCounter) % OSI_MUTEXHASHSIZE);
835     mp->level = level;
836     osi_TInit(&mp->d.turn);
837     return;
838 }
839
840 void lock_InitializeRWLock(osi_rwlock_t *mp, char *namep, unsigned short level)
841 {
842     int i;
843
844     if ((i = osi_lockTypeDefault) > 0) {
845         if (i >= 0 && i < OSI_NLOCKTYPES)
846             (osi_lockOps[i]->InitializeRWLockProc)(mp, namep, level);
847         return;
848     }
849
850     /* otherwise we have the base case, which requires no special
851      * initialization.
852      */
853     mp->type = 0;
854     mp->flags = 0;
855     mp->atomicIndex = (unsigned short)(InterlockedIncrement(&atomicIndexCounter) % OSI_MUTEXHASHSIZE);
856     mp->readers = 0;
857     mp->tid = 0;
858     mp->level = level;
859     osi_TInit(&mp->d.turn);
860     return;
861 }
862
863 int lock_GetRWLockState(osi_rwlock_t *lp)
864 {
865     long i;
866     CRITICAL_SECTION *csp;
867
868     if ((i=lp->type) != 0)
869         if (i >= 0 && i < OSI_NLOCKTYPES)
870             return (osi_lockOps[i]->GetRWLockState)(lp);
871
872     /* otherwise we're the fast base type */
873     csp = &osi_baseAtomicCS[lp->atomicIndex];
874     EnterCriticalSection(csp);
875
876     /* here we have the fast lock, so see if we can obtain the real lock */
877     if (lp->flags & OSI_LOCKFLAG_EXCL)
878         i = OSI_RWLOCK_WRITEHELD;
879     else
880         i = 0;
881     if (lp->readers > 0)
882         i |= OSI_RWLOCK_READHELD;
883
884     LeaveCriticalSection(csp);
885
886     return i;
887 }
888
889 int lock_GetMutexState(struct osi_mutex *mp)
890 {
891     long i;
892     CRITICAL_SECTION *csp;
893
894     if ((i=mp->type) != 0)
895         if (i >= 0 && i < OSI_NLOCKTYPES)
896             return (osi_lockOps[i]->GetMutexState)(mp);
897
898     /* otherwise we're the fast base type */
899     csp = &osi_baseAtomicCS[mp->atomicIndex];
900     EnterCriticalSection(csp);
901
902     if (mp->flags & OSI_LOCKFLAG_EXCL)
903         i = OSI_MUTEX_HELD;
904     else
905         i = 0;
906
907     LeaveCriticalSection(csp);
908
909     return i;
910 }