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];
23 void osi_BaseInit(void)
27 for(i=0; i<OSI_MUTEXHASHSIZE; i++)
28 InitializeCriticalSection(&osi_baseAtomicCS[i]);
31 void lock_ObtainWrite(osi_rwlock_t *lockp)
34 CRITICAL_SECTION *csp;
36 if ((i=lockp->type) != 0) {
37 (osi_lockOps[i]->ObtainWriteProc)(lockp);
41 /* otherwise we're the fast base type */
42 csp = &osi_baseAtomicCS[lockp->atomicIndex];
43 EnterCriticalSection(csp);
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)) {
49 osi_TWait(&lockp->d.turn, OSI_SLEEPINFO_W4WRITE, &lockp->flags, csp);
51 osi_assert(lockp->readers == 0 && (lockp->flags & OSI_LOCKFLAG_EXCL));
54 /* if we're here, all clear to set the lock */
55 lockp->flags |= OSI_LOCKFLAG_EXCL;
58 LeaveCriticalSection(csp);
61 void lock_ObtainRead(osi_rwlock_t *lockp)
64 CRITICAL_SECTION *csp;
66 if ((i=lockp->type) != 0) {
67 (osi_lockOps[i]->ObtainReadProc)(lockp);
71 /* otherwise we're the fast base type */
72 csp = &osi_baseAtomicCS[lockp->atomicIndex];
73 EnterCriticalSection(csp);
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)) {
78 osi_TWait(&lockp->d.turn, OSI_SLEEPINFO_W4READ, &lockp->readers, csp);
80 osi_assert(!(lockp->flags & OSI_LOCKFLAG_EXCL) && lockp->readers > 0);
83 /* if we're here, all clear to set the lock */
86 LeaveCriticalSection(csp);
89 void lock_ReleaseRead(osi_rwlock_t *lockp)
92 CRITICAL_SECTION *csp;
94 if ((i = lockp->type) != 0) {
95 (osi_lockOps[i]->ReleaseReadProc)(lockp);
99 /* otherwise we're the fast base type */
100 csp = &osi_baseAtomicCS[lockp->atomicIndex];
101 EnterCriticalSection(csp);
103 osi_assertx(lockp->readers > 0, "read lock not held");
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);
110 /* and finally release the big lock */
111 LeaveCriticalSection(csp);
115 void lock_ReleaseWrite(osi_rwlock_t *lockp)
118 CRITICAL_SECTION *csp;
120 if ((i = lockp->type) != 0) {
121 (osi_lockOps[i]->ReleaseWriteProc)(lockp);
125 /* otherwise we're the fast base type */
126 csp = &osi_baseAtomicCS[lockp->atomicIndex];
127 EnterCriticalSection(csp);
129 osi_assertx(lockp->flags & OSI_LOCKFLAG_EXCL, "write lock not held");
131 lockp->flags &= ~OSI_LOCKFLAG_EXCL;
132 if (!osi_TEmpty(&lockp->d.turn)) {
133 osi_TSignalForMLs(&lockp->d.turn, 0, csp);
136 /* and finally release the big lock */
137 LeaveCriticalSection(csp);
141 void lock_ConvertWToR(osi_rwlock_t *lockp)
144 CRITICAL_SECTION *csp;
146 if ((i = lockp->type) != 0) {
147 (osi_lockOps[i]->ConvertWToRProc)(lockp);
151 /* otherwise we're the fast base type */
152 csp = &osi_baseAtomicCS[lockp->atomicIndex];
153 EnterCriticalSection(csp);
155 osi_assertx(lockp->flags & OSI_LOCKFLAG_EXCL, "write lock not held");
157 /* convert write lock to read lock */
158 lockp->flags &= ~OSI_LOCKFLAG_EXCL;
161 if (!osi_TEmpty(&lockp->d.turn)) {
162 osi_TSignalForMLs(&lockp->d.turn, /* still have readers */ 1, csp);
165 /* and finally release the big lock */
166 LeaveCriticalSection(csp);
170 void lock_ObtainMutex(struct osi_mutex *lockp)
173 CRITICAL_SECTION *csp;
175 if ((i=lockp->type) != 0) {
176 (osi_lockOps[i]->ObtainMutexProc)(lockp);
180 /* otherwise we're the fast base type */
181 csp = &osi_baseAtomicCS[lockp->atomicIndex];
182 EnterCriticalSection(csp);
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)) {
187 osi_TWait(&lockp->d.turn, OSI_SLEEPINFO_W4WRITE, &lockp->flags, csp);
189 osi_assert(lockp->flags & OSI_LOCKFLAG_EXCL);
192 /* if we're here, all clear to set the lock */
193 lockp->flags |= OSI_LOCKFLAG_EXCL;
195 lockp->tid = thrd_Current();
196 LeaveCriticalSection(csp);
199 void lock_ReleaseMutex(struct osi_mutex *lockp)
202 CRITICAL_SECTION *csp;
204 if ((i = lockp->type) != 0) {
205 (osi_lockOps[i]->ReleaseMutexProc)(lockp);
209 /* otherwise we're the fast base type */
210 csp = &osi_baseAtomicCS[lockp->atomicIndex];
211 EnterCriticalSection(csp);
213 osi_assertx(lockp->flags & OSI_LOCKFLAG_EXCL, "mutex not held");
215 lockp->flags &= ~OSI_LOCKFLAG_EXCL;
217 if (!osi_TEmpty(&lockp->d.turn)) {
218 osi_TSignalForMLs(&lockp->d.turn, 0, csp);
221 /* and finally release the big lock */
222 LeaveCriticalSection(csp);
226 int lock_TryRead(struct osi_rwlock *lockp)
229 CRITICAL_SECTION *csp;
231 if ((i=lockp->type) != 0)
232 return (osi_lockOps[i]->TryReadProc)(lockp);
234 /* otherwise we're the fast base type */
235 csp = &osi_baseAtomicCS[lockp->atomicIndex];
236 EnterCriticalSection(csp);
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)) {
243 /* if we're here, all clear to set the lock */
248 LeaveCriticalSection(csp);
254 int lock_TryWrite(struct osi_rwlock *lockp)
257 CRITICAL_SECTION *csp;
259 if ((i=lockp->type) != 0)
260 return (osi_lockOps[i]->TryWriteProc)(lockp);
262 /* otherwise we're the fast base type */
263 csp = &osi_baseAtomicCS[lockp->atomicIndex];
264 EnterCriticalSection(csp);
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)) {
272 /* if we're here, all clear to set the lock */
273 lockp->flags |= OSI_LOCKFLAG_EXCL;
277 LeaveCriticalSection(csp);
283 int lock_TryMutex(struct osi_mutex *lockp) {
285 CRITICAL_SECTION *csp;
287 if ((i=lockp->type) != 0)
288 return (osi_lockOps[i]->TryMutexProc)(lockp);
290 /* otherwise we're the fast base type */
291 csp = &osi_baseAtomicCS[lockp->atomicIndex];
292 EnterCriticalSection(csp);
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)) {
299 /* if we're here, all clear to set the lock */
300 lockp->flags |= OSI_LOCKFLAG_EXCL;
304 LeaveCriticalSection(csp);
309 void osi_SleepR(LONG_PTR sleepVal, struct osi_rwlock *lockp)
312 CRITICAL_SECTION *csp;
314 if ((i = lockp->type) != 0) {
315 (osi_lockOps[i]->SleepRProc)(sleepVal, lockp);
319 /* otherwise we're the fast base type */
320 csp = &osi_baseAtomicCS[lockp->atomicIndex];
321 EnterCriticalSection(csp);
323 osi_assertx(lockp->readers > 0, "osi_SleepR: not held");
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.
328 if (--lockp->readers == 0 && !osi_TEmpty(&lockp->d.turn)) {
329 osi_TSignalForMLs(&lockp->d.turn, 0, NULL);
332 /* now call into scheduler to sleep atomically with releasing spin lock */
333 osi_SleepSpin(sleepVal, csp);
336 void osi_SleepW(LONG_PTR sleepVal, struct osi_rwlock *lockp)
339 CRITICAL_SECTION *csp;
341 if ((i = lockp->type) != 0) {
342 (osi_lockOps[i]->SleepWProc)(sleepVal, lockp);
346 /* otherwise we're the fast base type */
347 csp = &osi_baseAtomicCS[lockp->atomicIndex];
348 EnterCriticalSection(csp);
350 osi_assertx(lockp->flags & OSI_LOCKFLAG_EXCL, "osi_SleepW: not held");
352 lockp->flags &= ~OSI_LOCKFLAG_EXCL;
353 if (!osi_TEmpty(&lockp->d.turn)) {
354 osi_TSignalForMLs(&lockp->d.turn, 0, NULL);
357 /* and finally release the big lock */
358 osi_SleepSpin(sleepVal, csp);
361 void osi_SleepM(LONG_PTR sleepVal, struct osi_mutex *lockp)
364 CRITICAL_SECTION *csp;
366 if ((i = lockp->type) != 0) {
367 (osi_lockOps[i]->SleepMProc)(sleepVal, lockp);
371 /* otherwise we're the fast base type */
372 csp = &osi_baseAtomicCS[lockp->atomicIndex];
373 EnterCriticalSection(csp);
375 osi_assertx(lockp->flags & OSI_LOCKFLAG_EXCL, "osi_SleepM not held");
377 lockp->flags &= ~OSI_LOCKFLAG_EXCL;
378 if (!osi_TEmpty(&lockp->d.turn)) {
379 osi_TSignalForMLs(&lockp->d.turn, 0, NULL);
382 /* and finally release the big lock */
383 osi_SleepSpin(sleepVal, csp);
386 void lock_FinalizeRWLock(osi_rwlock_t *lockp)
390 if ((i=lockp->type) != 0)
391 (osi_lockOps[i]->FinalizeRWLockProc)(lockp);
394 void lock_FinalizeMutex(osi_mutex_t *lockp)
398 if ((i=lockp->type) != 0)
399 (osi_lockOps[i]->FinalizeMutexProc)(lockp);
402 void lock_InitializeMutex(osi_mutex_t *mp, char *namep)
406 if ((i = osi_lockTypeDefault) > 0) {
407 (osi_lockOps[i]->InitializeMutexProc)(mp, namep);
411 /* otherwise we have the base case, which requires no special
417 mp->atomicIndex = osi_MUTEXHASH(mp);
418 osi_TInit(&mp->d.turn);
422 void lock_InitializeRWLock(osi_rwlock_t *mp, char *namep)
426 if ((i = osi_lockTypeDefault) > 0) {
427 (osi_lockOps[i]->InitializeRWLockProc)(mp, namep);
431 /* otherwise we have the base case, which requires no special
436 mp->atomicIndex = osi_MUTEXHASH(mp);
438 osi_TInit(&mp->d.turn);
442 int lock_GetRWLockState(osi_rwlock_t *lp)
445 CRITICAL_SECTION *csp;
447 if ((i=lp->type) != 0)
448 return (osi_lockOps[i]->GetRWLockState)(lp);
450 /* otherwise we're the fast base type */
451 csp = &osi_baseAtomicCS[lp->atomicIndex];
452 EnterCriticalSection(csp);
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;
457 if (lp->readers > 0) i |= OSI_RWLOCK_READHELD;
459 LeaveCriticalSection(csp);
464 int lock_GetMutexState(struct osi_mutex *mp) {
466 CRITICAL_SECTION *csp;
468 if ((i=mp->type) != 0)
469 return (osi_lockOps[i]->GetMutexState)(mp);
471 /* otherwise we're the fast base type */
472 csp = &osi_baseAtomicCS[mp->atomicIndex];
473 EnterCriticalSection(csp);
475 if (mp->flags & OSI_LOCKFLAG_EXCL)
480 LeaveCriticalSection(csp);