windows-track-lock-tid-20061002
[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
20 /* atomicity-providing critical sections */
21 CRITICAL_SECTION osi_baseAtomicCS[OSI_MUTEXHASHSIZE];
22
23 void osi_BaseInit(void)
24 {
25         int i;
26
27         for(i=0; i<OSI_MUTEXHASHSIZE; i++)
28                 InitializeCriticalSection(&osi_baseAtomicCS[i]);
29 }
30
31 void lock_ObtainWrite(osi_rwlock_t *lockp)
32 {
33         long i;
34         CRITICAL_SECTION *csp;
35
36         if ((i=lockp->type) != 0) {
37             if (i >= 0 && i < OSI_NLOCKTYPES)
38                 (osi_lockOps[i]->ObtainWriteProc)(lockp);
39             return;
40         }
41
42         /* otherwise we're the fast base type */
43         csp = &osi_baseAtomicCS[lockp->atomicIndex];
44         EnterCriticalSection(csp);
45
46         /* here we have the fast lock, so see if we can obtain the real lock */
47         if (lockp->waiters > 0 || (lockp->flags & OSI_LOCKFLAG_EXCL)
48                 || (lockp->readers > 0)) {
49                 lockp->waiters++;
50                 osi_TWait(&lockp->d.turn, OSI_SLEEPINFO_W4WRITE, &lockp->flags, csp);
51                 lockp->waiters--;
52                 osi_assert(lockp->readers == 0 && (lockp->flags & OSI_LOCKFLAG_EXCL));
53         }
54         else {
55                 /* if we're here, all clear to set the lock */
56                 lockp->flags |= OSI_LOCKFLAG_EXCL;
57         }
58
59         lockp->tid = thrd_Current();
60
61         LeaveCriticalSection(csp);
62 }
63
64 void lock_ObtainRead(osi_rwlock_t *lockp)
65 {
66         long i;
67         CRITICAL_SECTION *csp;
68
69         if ((i=lockp->type) != 0) {
70             if (i >= 0 && i < OSI_NLOCKTYPES)
71                 (osi_lockOps[i]->ObtainReadProc)(lockp);
72                 return;
73         }
74
75         /* otherwise we're the fast base type */
76         csp = &osi_baseAtomicCS[lockp->atomicIndex];
77         EnterCriticalSection(csp);
78
79         /* here we have the fast lock, so see if we can obtain the real lock */
80         if (lockp->waiters > 0 || (lockp->flags & OSI_LOCKFLAG_EXCL)) {
81                 lockp->waiters++;
82                 osi_TWait(&lockp->d.turn, OSI_SLEEPINFO_W4READ, &lockp->readers, csp);
83                 lockp->waiters--;
84                 osi_assert(!(lockp->flags & OSI_LOCKFLAG_EXCL) && lockp->readers > 0);
85         }
86         else {
87                 /* if we're here, all clear to set the lock */
88                 lockp->readers++;
89         }
90
91         LeaveCriticalSection(csp);
92 }
93
94 void lock_ReleaseRead(osi_rwlock_t *lockp)
95 {
96         long i;
97         CRITICAL_SECTION *csp;
98
99         if ((i = lockp->type) != 0) {
100             if (i >= 0 && i < OSI_NLOCKTYPES)
101                 (osi_lockOps[i]->ReleaseReadProc)(lockp);
102                 return;
103         }
104
105         /* otherwise we're the fast base type */
106         csp = &osi_baseAtomicCS[lockp->atomicIndex];
107         EnterCriticalSection(csp);
108
109         osi_assertx(lockp->readers > 0, "read lock not held");
110         
111         /* releasing a read lock can allow readers or writers */
112         if (--lockp->readers == 0 && !osi_TEmpty(&lockp->d.turn)) {
113                 osi_TSignalForMLs(&lockp->d.turn, 0, csp);
114         }
115         else {
116                 /* and finally release the big lock */
117                 LeaveCriticalSection(csp);
118         }
119 }
120
121 void lock_ReleaseWrite(osi_rwlock_t *lockp)
122 {
123         long i;
124         CRITICAL_SECTION *csp;
125
126         if ((i = lockp->type) != 0) {
127             if (i >= 0 && i < OSI_NLOCKTYPES)
128                 (osi_lockOps[i]->ReleaseWriteProc)(lockp);
129                 return;
130         }
131
132         /* otherwise we're the fast base type */
133         csp = &osi_baseAtomicCS[lockp->atomicIndex];
134         EnterCriticalSection(csp);
135
136         osi_assertx(lockp->flags & OSI_LOCKFLAG_EXCL, "write lock not held");
137         
138         lockp->tid = 0;
139
140         lockp->flags &= ~OSI_LOCKFLAG_EXCL;
141         if (!osi_TEmpty(&lockp->d.turn)) {
142                 osi_TSignalForMLs(&lockp->d.turn, 0, csp);
143         }
144         else {
145                 /* and finally release the big lock */
146                 LeaveCriticalSection(csp);
147         }
148 }
149
150 void lock_ConvertWToR(osi_rwlock_t *lockp)
151 {
152         long i;
153         CRITICAL_SECTION *csp;
154
155         if ((i = lockp->type) != 0) {
156             if (i >= 0 && i < OSI_NLOCKTYPES)
157                 (osi_lockOps[i]->ConvertWToRProc)(lockp);
158                 return;
159         }
160
161         /* otherwise we're the fast base type */
162         csp = &osi_baseAtomicCS[lockp->atomicIndex];
163         EnterCriticalSection(csp);
164
165         osi_assertx(lockp->flags & OSI_LOCKFLAG_EXCL, "write lock not held");
166         
167         /* convert write lock to read lock */
168         lockp->flags &= ~OSI_LOCKFLAG_EXCL;
169         lockp->readers++;
170
171         lockp->tid = 0;
172
173         if (!osi_TEmpty(&lockp->d.turn)) {
174                 osi_TSignalForMLs(&lockp->d.turn, /* still have readers */ 1, csp);
175         }
176         else {
177                 /* and finally release the big lock */
178                 LeaveCriticalSection(csp);
179         }
180 }
181
182 void lock_ObtainMutex(struct osi_mutex *lockp)
183 {
184         long i;
185         CRITICAL_SECTION *csp;
186
187         if ((i=lockp->type) != 0) {
188             if (i >= 0 && i < OSI_NLOCKTYPES)
189                 (osi_lockOps[i]->ObtainMutexProc)(lockp);
190                 return;
191         }
192
193         /* otherwise we're the fast base type */
194         csp = &osi_baseAtomicCS[lockp->atomicIndex];
195         EnterCriticalSection(csp);
196
197         /* here we have the fast lock, so see if we can obtain the real lock */
198         if (lockp->waiters > 0 || (lockp->flags & OSI_LOCKFLAG_EXCL)) {
199                 lockp->waiters++;
200                 osi_TWait(&lockp->d.turn, OSI_SLEEPINFO_W4WRITE, &lockp->flags, csp);
201                 lockp->waiters--;
202                 osi_assert(lockp->flags & OSI_LOCKFLAG_EXCL);
203         }
204         else {
205                 /* if we're here, all clear to set the lock */
206                 lockp->flags |= OSI_LOCKFLAG_EXCL;
207         }
208         lockp->tid = thrd_Current();
209         LeaveCriticalSection(csp);
210 }
211
212 void lock_ReleaseMutex(struct osi_mutex *lockp)
213 {
214         long i;
215         CRITICAL_SECTION *csp;
216
217         if ((i = lockp->type) != 0) {
218             if (i >= 0 && i < OSI_NLOCKTYPES)
219                 (osi_lockOps[i]->ReleaseMutexProc)(lockp);
220                 return;
221         }
222
223         /* otherwise we're the fast base type */
224         csp = &osi_baseAtomicCS[lockp->atomicIndex];
225         EnterCriticalSection(csp);
226
227         osi_assertx(lockp->flags & OSI_LOCKFLAG_EXCL, "mutex not held");
228         
229         lockp->flags &= ~OSI_LOCKFLAG_EXCL;
230         lockp->tid = 0;
231         if (!osi_TEmpty(&lockp->d.turn)) {
232                 osi_TSignalForMLs(&lockp->d.turn, 0, csp);
233         }
234         else {
235                 /* and finally release the big lock */
236                 LeaveCriticalSection(csp);
237         }
238 }
239
240 int lock_TryRead(struct osi_rwlock *lockp)
241 {
242         long i;
243         CRITICAL_SECTION *csp;
244
245         if ((i=lockp->type) != 0)
246             if (i >= 0 && i < OSI_NLOCKTYPES)
247                 return (osi_lockOps[i]->TryReadProc)(lockp);
248
249         /* otherwise we're the fast base type */
250         csp = &osi_baseAtomicCS[lockp->atomicIndex];
251         EnterCriticalSection(csp);
252
253         /* here we have the fast lock, so see if we can obtain the real lock */
254         if (lockp->waiters > 0 || (lockp->flags & OSI_LOCKFLAG_EXCL)) {
255                 i = 0;
256         }
257         else {
258                 /* if we're here, all clear to set the lock */
259                 lockp->readers++;
260                 i = 1;
261         }
262
263         LeaveCriticalSection(csp);
264
265         return i;
266 }
267
268
269 int lock_TryWrite(struct osi_rwlock *lockp)
270 {
271         long i;
272         CRITICAL_SECTION *csp;
273
274         if ((i=lockp->type) != 0)
275             if (i >= 0 && i < OSI_NLOCKTYPES)
276                 return (osi_lockOps[i]->TryWriteProc)(lockp);
277
278         /* otherwise we're the fast base type */
279         csp = &osi_baseAtomicCS[lockp->atomicIndex];
280         EnterCriticalSection(csp);
281
282         /* here we have the fast lock, so see if we can obtain the real lock */
283         if (lockp->waiters > 0 || (lockp->flags & OSI_LOCKFLAG_EXCL)
284                 || (lockp->readers > 0)) {
285                 i = 0;
286         }
287         else {
288                 /* if we're here, all clear to set the lock */
289                 lockp->flags |= OSI_LOCKFLAG_EXCL;
290                 i = 1;
291         }
292
293         if (i)
294             lockp->tid = thrd_Current();
295
296         LeaveCriticalSection(csp);
297
298         return i;
299 }
300
301
302 int lock_TryMutex(struct osi_mutex *lockp) {
303         long i;
304         CRITICAL_SECTION *csp;
305
306         if ((i=lockp->type) != 0)
307             if (i >= 0 && i < OSI_NLOCKTYPES)
308                 return (osi_lockOps[i]->TryMutexProc)(lockp);
309
310         /* otherwise we're the fast base type */
311         csp = &osi_baseAtomicCS[lockp->atomicIndex];
312         EnterCriticalSection(csp);
313
314         /* here we have the fast lock, so see if we can obtain the real lock */
315         if (lockp->waiters > 0 || (lockp->flags & OSI_LOCKFLAG_EXCL)) {
316                 i = 0;
317         }
318         else {
319                 /* if we're here, all clear to set the lock */
320                 lockp->flags |= OSI_LOCKFLAG_EXCL;
321                 i = 1;
322         }
323
324         if (i)
325             lockp->tid = thrd_Current();
326
327         LeaveCriticalSection(csp);
328
329         return i;
330 }
331
332 void osi_SleepR(LONG_PTR sleepVal, struct osi_rwlock *lockp)
333 {
334         long i;
335         CRITICAL_SECTION *csp;
336
337         if ((i = lockp->type) != 0) {
338             if (i >= 0 && i < OSI_NLOCKTYPES)
339                 (osi_lockOps[i]->SleepRProc)(sleepVal, lockp);
340                 return;
341         }
342
343         /* otherwise we're the fast base type */
344         csp = &osi_baseAtomicCS[lockp->atomicIndex];
345         EnterCriticalSection(csp);
346
347         osi_assertx(lockp->readers > 0, "osi_SleepR: not held");
348         
349         /* XXX better to get the list of things to wakeup from TSignalForMLs, and
350          * then do the wakeup after SleepSpin releases the low-level mutex.
351          */
352         if (--lockp->readers == 0 && !osi_TEmpty(&lockp->d.turn)) {
353                 osi_TSignalForMLs(&lockp->d.turn, 0, NULL);
354         }
355
356         /* now call into scheduler to sleep atomically with releasing spin lock */
357         osi_SleepSpin(sleepVal, csp);
358 }
359
360 void osi_SleepW(LONG_PTR sleepVal, struct osi_rwlock *lockp)
361 {
362         long i;
363         CRITICAL_SECTION *csp;
364
365         if ((i = lockp->type) != 0) {
366             if (i >= 0 && i < OSI_NLOCKTYPES)
367                 (osi_lockOps[i]->SleepWProc)(sleepVal, lockp);
368                 return;
369         }
370
371         /* otherwise we're the fast base type */
372         csp = &osi_baseAtomicCS[lockp->atomicIndex];
373         EnterCriticalSection(csp);
374
375         osi_assertx(lockp->flags & OSI_LOCKFLAG_EXCL, "osi_SleepW: not held");
376         
377         lockp->flags &= ~OSI_LOCKFLAG_EXCL;
378         if (!osi_TEmpty(&lockp->d.turn)) {
379                 osi_TSignalForMLs(&lockp->d.turn, 0, NULL);
380         }
381
382         /* and finally release the big lock */
383         osi_SleepSpin(sleepVal, csp);
384 }
385
386 void osi_SleepM(LONG_PTR sleepVal, struct osi_mutex *lockp)
387 {
388         long i;
389         CRITICAL_SECTION *csp;
390
391         if ((i = lockp->type) != 0) {
392             if (i >= 0 && i < OSI_NLOCKTYPES)
393                 (osi_lockOps[i]->SleepMProc)(sleepVal, lockp);
394                 return;
395         }
396
397         /* otherwise we're the fast base type */
398         csp = &osi_baseAtomicCS[lockp->atomicIndex];
399         EnterCriticalSection(csp);
400
401         osi_assertx(lockp->flags & OSI_LOCKFLAG_EXCL, "osi_SleepM not held");
402         
403         lockp->flags &= ~OSI_LOCKFLAG_EXCL;
404         if (!osi_TEmpty(&lockp->d.turn)) {
405                 osi_TSignalForMLs(&lockp->d.turn, 0, NULL);
406         }
407
408         /* and finally release the big lock */
409         osi_SleepSpin(sleepVal, csp);
410 }
411
412 void lock_FinalizeRWLock(osi_rwlock_t *lockp)
413 {
414         long i;
415
416         if ((i=lockp->type) != 0)
417             if (i >= 0 && i < OSI_NLOCKTYPES)
418                 (osi_lockOps[i]->FinalizeRWLockProc)(lockp);
419 }
420
421 void lock_FinalizeMutex(osi_mutex_t *lockp)
422 {
423         long i;
424
425         if ((i=lockp->type) != 0)
426             if (i >= 0 && i < OSI_NLOCKTYPES)
427                 (osi_lockOps[i]->FinalizeMutexProc)(lockp);
428 }
429
430 void lock_InitializeMutex(osi_mutex_t *mp, char *namep)
431 {
432         int i;
433
434         if ((i = osi_lockTypeDefault) > 0) {
435             if (i >= 0 && i < OSI_NLOCKTYPES)
436                 (osi_lockOps[i]->InitializeMutexProc)(mp, namep);
437                 return;
438         }
439
440         /* otherwise we have the base case, which requires no special
441          * initialization.
442          */
443         mp->type = 0;
444         mp->flags = 0;
445         mp->tid = 0;
446         mp->atomicIndex = osi_MUTEXHASH(mp);
447         osi_TInit(&mp->d.turn);
448         return;
449 }
450
451 void lock_InitializeRWLock(osi_rwlock_t *mp, char *namep)
452 {
453         int i;
454
455         if ((i = osi_lockTypeDefault) > 0) {
456             if (i >= 0 && i < OSI_NLOCKTYPES)
457                 (osi_lockOps[i]->InitializeRWLockProc)(mp, namep);
458                 return;
459         }
460         
461         /* otherwise we have the base case, which requires no special
462          * initialization.
463          */
464         mp->type = 0;
465         mp->flags = 0;
466         mp->atomicIndex = osi_MUTEXHASH(mp);
467         mp->readers = 0;
468         mp->tid = 0;
469         osi_TInit(&mp->d.turn);
470         return;
471 }
472
473 int lock_GetRWLockState(osi_rwlock_t *lp)
474 {
475         long i;
476         CRITICAL_SECTION *csp;
477
478         if ((i=lp->type) != 0)
479             if (i >= 0 && i < OSI_NLOCKTYPES)
480                 return (osi_lockOps[i]->GetRWLockState)(lp);
481
482         /* otherwise we're the fast base type */
483         csp = &osi_baseAtomicCS[lp->atomicIndex];
484         EnterCriticalSection(csp);
485
486         /* here we have the fast lock, so see if we can obtain the real lock */
487         if (lp->flags & OSI_LOCKFLAG_EXCL) i = OSI_RWLOCK_WRITEHELD;
488         else i = 0;
489         if (lp->readers > 0) i |= OSI_RWLOCK_READHELD;
490
491         LeaveCriticalSection(csp);
492
493         return i;
494 }
495
496 int lock_GetMutexState(struct osi_mutex *mp) {
497         long i;
498         CRITICAL_SECTION *csp;
499
500         if ((i=mp->type) != 0)
501             if (i >= 0 && i < OSI_NLOCKTYPES)
502                 return (osi_lockOps[i]->GetMutexState)(mp);
503
504         /* otherwise we're the fast base type */
505         csp = &osi_baseAtomicCS[mp->atomicIndex];
506         EnterCriticalSection(csp);
507
508         if (mp->flags & OSI_LOCKFLAG_EXCL)
509                 i = OSI_MUTEX_HELD;
510         else
511                 i = 0;
512
513         LeaveCriticalSection(csp);
514
515         return i;
516 }