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