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