2 * Copyright 2000, International Business Machines Corporation and others.
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
10 /* Copyright (C) 1994 Cazamar Systems, Inc. */
13 #include <afs/param.h>
20 /* atomicity-providing critical sections */
21 CRITICAL_SECTION osi_baseAtomicCS[OSI_MUTEXHASHSIZE];
22 static long atomicIndexCounter = 0;
24 void osi_BaseInit(void)
28 for(i=0; i<OSI_MUTEXHASHSIZE; i++)
29 InitializeCriticalSection(&osi_baseAtomicCS[i]);
32 void lock_ObtainWrite(osi_rwlock_t *lockp)
35 CRITICAL_SECTION *csp;
37 if ((i=lockp->type) != 0) {
38 if (i >= 0 && i < OSI_NLOCKTYPES)
39 (osi_lockOps[i]->ObtainWriteProc)(lockp);
43 /* otherwise we're the fast base type */
44 csp = &osi_baseAtomicCS[lockp->atomicIndex];
45 EnterCriticalSection(csp);
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)) {
51 osi_TWait(&lockp->d.turn, OSI_SLEEPINFO_W4WRITE, &lockp->flags, csp);
53 osi_assert(lockp->readers == 0 && (lockp->flags & OSI_LOCKFLAG_EXCL));
56 /* if we're here, all clear to set the lock */
57 lockp->flags |= OSI_LOCKFLAG_EXCL;
60 lockp->tid = thrd_Current();
62 LeaveCriticalSection(csp);
65 void lock_ObtainRead(osi_rwlock_t *lockp)
68 CRITICAL_SECTION *csp;
70 if ((i=lockp->type) != 0) {
71 if (i >= 0 && i < OSI_NLOCKTYPES)
72 (osi_lockOps[i]->ObtainReadProc)(lockp);
76 /* otherwise we're the fast base type */
77 csp = &osi_baseAtomicCS[lockp->atomicIndex];
78 EnterCriticalSection(csp);
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)) {
83 osi_TWait(&lockp->d.turn, OSI_SLEEPINFO_W4READ, &lockp->readers, csp);
85 osi_assert(!(lockp->flags & OSI_LOCKFLAG_EXCL) && lockp->readers > 0);
88 /* if we're here, all clear to set the lock */
92 LeaveCriticalSection(csp);
95 void lock_ReleaseRead(osi_rwlock_t *lockp)
98 CRITICAL_SECTION *csp;
100 if ((i = lockp->type) != 0) {
101 if (i >= 0 && i < OSI_NLOCKTYPES)
102 (osi_lockOps[i]->ReleaseReadProc)(lockp);
106 /* otherwise we're the fast base type */
107 csp = &osi_baseAtomicCS[lockp->atomicIndex];
108 EnterCriticalSection(csp);
110 osi_assertx(lockp->readers > 0, "read lock not held");
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);
117 /* and finally release the big lock */
118 LeaveCriticalSection(csp);
122 void lock_ReleaseWrite(osi_rwlock_t *lockp)
125 CRITICAL_SECTION *csp;
127 if ((i = lockp->type) != 0) {
128 if (i >= 0 && i < OSI_NLOCKTYPES)
129 (osi_lockOps[i]->ReleaseWriteProc)(lockp);
133 /* otherwise we're the fast base type */
134 csp = &osi_baseAtomicCS[lockp->atomicIndex];
135 EnterCriticalSection(csp);
137 osi_assertx(lockp->flags & OSI_LOCKFLAG_EXCL, "write lock not held");
141 lockp->flags &= ~OSI_LOCKFLAG_EXCL;
142 if (!osi_TEmpty(&lockp->d.turn)) {
143 osi_TSignalForMLs(&lockp->d.turn, 0, csp);
146 /* and finally release the big lock */
147 LeaveCriticalSection(csp);
151 void lock_ConvertWToR(osi_rwlock_t *lockp)
154 CRITICAL_SECTION *csp;
156 if ((i = lockp->type) != 0) {
157 if (i >= 0 && i < OSI_NLOCKTYPES)
158 (osi_lockOps[i]->ConvertWToRProc)(lockp);
162 /* otherwise we're the fast base type */
163 csp = &osi_baseAtomicCS[lockp->atomicIndex];
164 EnterCriticalSection(csp);
166 osi_assertx(lockp->flags & OSI_LOCKFLAG_EXCL, "write lock not held");
168 /* convert write lock to read lock */
169 lockp->flags &= ~OSI_LOCKFLAG_EXCL;
174 if (!osi_TEmpty(&lockp->d.turn)) {
175 osi_TSignalForMLs(&lockp->d.turn, /* still have readers */ 1, csp);
178 /* and finally release the big lock */
179 LeaveCriticalSection(csp);
183 void lock_ConvertRToW(osi_rwlock_t *lockp)
186 CRITICAL_SECTION *csp;
188 if ((i = lockp->type) != 0) {
189 if (i >= 0 && i < OSI_NLOCKTYPES)
190 (osi_lockOps[i]->ConvertRToWProc)(lockp);
194 /* otherwise we're the fast base type */
195 csp = &osi_baseAtomicCS[lockp->atomicIndex];
196 EnterCriticalSection(csp);
198 osi_assertx(!(lockp->flags & OSI_LOCKFLAG_EXCL), "write lock held");
199 osi_assertx(lockp->readers > 0, "read lock not held");
201 if (--lockp->readers == 0) {
202 /* convert read lock to write lock */
203 lockp->flags |= OSI_LOCKFLAG_EXCL;
206 osi_TWait(&lockp->d.turn, OSI_SLEEPINFO_W4WRITE, &lockp->flags, csp);
208 osi_assert(lockp->readers == 0 && (lockp->flags & OSI_LOCKFLAG_EXCL));
211 lockp->tid = thrd_Current();
212 LeaveCriticalSection(csp);
215 void lock_ObtainMutex(struct osi_mutex *lockp)
218 CRITICAL_SECTION *csp;
220 if ((i=lockp->type) != 0) {
221 if (i >= 0 && i < OSI_NLOCKTYPES)
222 (osi_lockOps[i]->ObtainMutexProc)(lockp);
226 /* otherwise we're the fast base type */
227 csp = &osi_baseAtomicCS[lockp->atomicIndex];
228 EnterCriticalSection(csp);
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)) {
233 osi_TWait(&lockp->d.turn, OSI_SLEEPINFO_W4WRITE, &lockp->flags, csp);
235 osi_assert(lockp->flags & OSI_LOCKFLAG_EXCL);
238 /* if we're here, all clear to set the lock */
239 lockp->flags |= OSI_LOCKFLAG_EXCL;
241 lockp->tid = thrd_Current();
242 LeaveCriticalSection(csp);
245 void lock_ReleaseMutex(struct osi_mutex *lockp)
248 CRITICAL_SECTION *csp;
250 if ((i = lockp->type) != 0) {
251 if (i >= 0 && i < OSI_NLOCKTYPES)
252 (osi_lockOps[i]->ReleaseMutexProc)(lockp);
256 /* otherwise we're the fast base type */
257 csp = &osi_baseAtomicCS[lockp->atomicIndex];
258 EnterCriticalSection(csp);
260 osi_assertx(lockp->flags & OSI_LOCKFLAG_EXCL, "mutex not held");
262 lockp->flags &= ~OSI_LOCKFLAG_EXCL;
264 if (!osi_TEmpty(&lockp->d.turn)) {
265 osi_TSignalForMLs(&lockp->d.turn, 0, csp);
268 /* and finally release the big lock */
269 LeaveCriticalSection(csp);
273 int lock_TryRead(struct osi_rwlock *lockp)
276 CRITICAL_SECTION *csp;
278 if ((i=lockp->type) != 0)
279 if (i >= 0 && i < OSI_NLOCKTYPES)
280 return (osi_lockOps[i]->TryReadProc)(lockp);
282 /* otherwise we're the fast base type */
283 csp = &osi_baseAtomicCS[lockp->atomicIndex];
284 EnterCriticalSection(csp);
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)) {
291 /* if we're here, all clear to set the lock */
296 LeaveCriticalSection(csp);
302 int lock_TryWrite(struct osi_rwlock *lockp)
305 CRITICAL_SECTION *csp;
307 if ((i=lockp->type) != 0)
308 if (i >= 0 && i < OSI_NLOCKTYPES)
309 return (osi_lockOps[i]->TryWriteProc)(lockp);
311 /* otherwise we're the fast base type */
312 csp = &osi_baseAtomicCS[lockp->atomicIndex];
313 EnterCriticalSection(csp);
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)) {
321 /* if we're here, all clear to set the lock */
322 lockp->flags |= OSI_LOCKFLAG_EXCL;
327 lockp->tid = thrd_Current();
329 LeaveCriticalSection(csp);
335 int lock_TryMutex(struct osi_mutex *lockp) {
337 CRITICAL_SECTION *csp;
339 if ((i=lockp->type) != 0)
340 if (i >= 0 && i < OSI_NLOCKTYPES)
341 return (osi_lockOps[i]->TryMutexProc)(lockp);
343 /* otherwise we're the fast base type */
344 csp = &osi_baseAtomicCS[lockp->atomicIndex];
345 EnterCriticalSection(csp);
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)) {
352 /* if we're here, all clear to set the lock */
353 lockp->flags |= OSI_LOCKFLAG_EXCL;
358 lockp->tid = thrd_Current();
360 LeaveCriticalSection(csp);
365 void osi_SleepR(LONG_PTR sleepVal, struct osi_rwlock *lockp)
368 CRITICAL_SECTION *csp;
370 if ((i = lockp->type) != 0) {
371 if (i >= 0 && i < OSI_NLOCKTYPES)
372 (osi_lockOps[i]->SleepRProc)(sleepVal, lockp);
376 /* otherwise we're the fast base type */
377 csp = &osi_baseAtomicCS[lockp->atomicIndex];
378 EnterCriticalSection(csp);
380 osi_assertx(lockp->readers > 0, "osi_SleepR: not held");
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.
385 if (--lockp->readers == 0 && !osi_TEmpty(&lockp->d.turn)) {
386 osi_TSignalForMLs(&lockp->d.turn, 0, NULL);
389 /* now call into scheduler to sleep atomically with releasing spin lock */
390 osi_SleepSpin(sleepVal, csp);
393 void osi_SleepW(LONG_PTR sleepVal, struct osi_rwlock *lockp)
396 CRITICAL_SECTION *csp;
398 if ((i = lockp->type) != 0) {
399 if (i >= 0 && i < OSI_NLOCKTYPES)
400 (osi_lockOps[i]->SleepWProc)(sleepVal, lockp);
404 /* otherwise we're the fast base type */
405 csp = &osi_baseAtomicCS[lockp->atomicIndex];
406 EnterCriticalSection(csp);
408 osi_assertx(lockp->flags & OSI_LOCKFLAG_EXCL, "osi_SleepW: not held");
410 lockp->flags &= ~OSI_LOCKFLAG_EXCL;
411 if (!osi_TEmpty(&lockp->d.turn)) {
412 osi_TSignalForMLs(&lockp->d.turn, 0, NULL);
415 /* and finally release the big lock */
416 osi_SleepSpin(sleepVal, csp);
419 void osi_SleepM(LONG_PTR sleepVal, struct osi_mutex *lockp)
422 CRITICAL_SECTION *csp;
424 if ((i = lockp->type) != 0) {
425 if (i >= 0 && i < OSI_NLOCKTYPES)
426 (osi_lockOps[i]->SleepMProc)(sleepVal, lockp);
430 /* otherwise we're the fast base type */
431 csp = &osi_baseAtomicCS[lockp->atomicIndex];
432 EnterCriticalSection(csp);
434 osi_assertx(lockp->flags & OSI_LOCKFLAG_EXCL, "osi_SleepM not held");
436 lockp->flags &= ~OSI_LOCKFLAG_EXCL;
437 if (!osi_TEmpty(&lockp->d.turn)) {
438 osi_TSignalForMLs(&lockp->d.turn, 0, NULL);
441 /* and finally release the big lock */
442 osi_SleepSpin(sleepVal, csp);
445 void lock_FinalizeRWLock(osi_rwlock_t *lockp)
449 if ((i=lockp->type) != 0)
450 if (i >= 0 && i < OSI_NLOCKTYPES)
451 (osi_lockOps[i]->FinalizeRWLockProc)(lockp);
454 void lock_FinalizeMutex(osi_mutex_t *lockp)
458 if ((i=lockp->type) != 0)
459 if (i >= 0 && i < OSI_NLOCKTYPES)
460 (osi_lockOps[i]->FinalizeMutexProc)(lockp);
463 void lock_InitializeMutex(osi_mutex_t *mp, char *namep)
467 if ((i = osi_lockTypeDefault) > 0) {
468 if (i >= 0 && i < OSI_NLOCKTYPES)
469 (osi_lockOps[i]->InitializeMutexProc)(mp, namep);
473 /* otherwise we have the base case, which requires no special
479 mp->atomicIndex = (unsigned short)(InterlockedIncrement(&atomicIndexCounter) % OSI_MUTEXHASHSIZE);
480 osi_TInit(&mp->d.turn);
484 void lock_InitializeRWLock(osi_rwlock_t *mp, char *namep)
488 if ((i = osi_lockTypeDefault) > 0) {
489 if (i >= 0 && i < OSI_NLOCKTYPES)
490 (osi_lockOps[i]->InitializeRWLockProc)(mp, namep);
494 /* otherwise we have the base case, which requires no special
499 mp->atomicIndex = (unsigned short)(InterlockedIncrement(&atomicIndexCounter) % OSI_MUTEXHASHSIZE);
502 osi_TInit(&mp->d.turn);
506 int lock_GetRWLockState(osi_rwlock_t *lp)
509 CRITICAL_SECTION *csp;
511 if ((i=lp->type) != 0)
512 if (i >= 0 && i < OSI_NLOCKTYPES)
513 return (osi_lockOps[i]->GetRWLockState)(lp);
515 /* otherwise we're the fast base type */
516 csp = &osi_baseAtomicCS[lp->atomicIndex];
517 EnterCriticalSection(csp);
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;
522 if (lp->readers > 0) i |= OSI_RWLOCK_READHELD;
524 LeaveCriticalSection(csp);
529 int lock_GetMutexState(struct osi_mutex *mp) {
531 CRITICAL_SECTION *csp;
533 if ((i=mp->type) != 0)
534 if (i >= 0 && i < OSI_NLOCKTYPES)
535 return (osi_lockOps[i]->GetMutexState)(mp);
537 /* otherwise we're the fast base type */
538 csp = &osi_baseAtomicCS[mp->atomicIndex];
539 EnterCriticalSection(csp);
541 if (mp->flags & OSI_LOCKFLAG_EXCL)
546 LeaveCriticalSection(csp);