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 if (i >= 0 && i < OSI_NLOCKTYPES)
38 (osi_lockOps[i]->ObtainWriteProc)(lockp);
42 /* otherwise we're the fast base type */
43 csp = &osi_baseAtomicCS[lockp->atomicIndex];
44 EnterCriticalSection(csp);
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)) {
50 osi_TWait(&lockp->d.turn, OSI_SLEEPINFO_W4WRITE, &lockp->flags, csp);
52 osi_assert(lockp->readers == 0 && (lockp->flags & OSI_LOCKFLAG_EXCL));
55 /* if we're here, all clear to set the lock */
56 lockp->flags |= OSI_LOCKFLAG_EXCL;
59 lockp->tid = thrd_Current();
61 LeaveCriticalSection(csp);
64 void lock_ObtainRead(osi_rwlock_t *lockp)
67 CRITICAL_SECTION *csp;
69 if ((i=lockp->type) != 0) {
70 if (i >= 0 && i < OSI_NLOCKTYPES)
71 (osi_lockOps[i]->ObtainReadProc)(lockp);
75 /* otherwise we're the fast base type */
76 csp = &osi_baseAtomicCS[lockp->atomicIndex];
77 EnterCriticalSection(csp);
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)) {
82 osi_TWait(&lockp->d.turn, OSI_SLEEPINFO_W4READ, &lockp->readers, csp);
84 osi_assert(!(lockp->flags & OSI_LOCKFLAG_EXCL) && lockp->readers > 0);
87 /* if we're here, all clear to set the lock */
91 LeaveCriticalSection(csp);
94 void lock_ReleaseRead(osi_rwlock_t *lockp)
97 CRITICAL_SECTION *csp;
99 if ((i = lockp->type) != 0) {
100 if (i >= 0 && i < OSI_NLOCKTYPES)
101 (osi_lockOps[i]->ReleaseReadProc)(lockp);
105 /* otherwise we're the fast base type */
106 csp = &osi_baseAtomicCS[lockp->atomicIndex];
107 EnterCriticalSection(csp);
109 osi_assertx(lockp->readers > 0, "read lock not held");
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);
116 /* and finally release the big lock */
117 LeaveCriticalSection(csp);
121 void lock_ReleaseWrite(osi_rwlock_t *lockp)
124 CRITICAL_SECTION *csp;
126 if ((i = lockp->type) != 0) {
127 if (i >= 0 && i < OSI_NLOCKTYPES)
128 (osi_lockOps[i]->ReleaseWriteProc)(lockp);
132 /* otherwise we're the fast base type */
133 csp = &osi_baseAtomicCS[lockp->atomicIndex];
134 EnterCriticalSection(csp);
136 osi_assertx(lockp->flags & OSI_LOCKFLAG_EXCL, "write lock not held");
140 lockp->flags &= ~OSI_LOCKFLAG_EXCL;
141 if (!osi_TEmpty(&lockp->d.turn)) {
142 osi_TSignalForMLs(&lockp->d.turn, 0, csp);
145 /* and finally release the big lock */
146 LeaveCriticalSection(csp);
150 void lock_ConvertWToR(osi_rwlock_t *lockp)
153 CRITICAL_SECTION *csp;
155 if ((i = lockp->type) != 0) {
156 if (i >= 0 && i < OSI_NLOCKTYPES)
157 (osi_lockOps[i]->ConvertWToRProc)(lockp);
161 /* otherwise we're the fast base type */
162 csp = &osi_baseAtomicCS[lockp->atomicIndex];
163 EnterCriticalSection(csp);
165 osi_assertx(lockp->flags & OSI_LOCKFLAG_EXCL, "write lock not held");
167 /* convert write lock to read lock */
168 lockp->flags &= ~OSI_LOCKFLAG_EXCL;
173 if (!osi_TEmpty(&lockp->d.turn)) {
174 osi_TSignalForMLs(&lockp->d.turn, /* still have readers */ 1, csp);
177 /* and finally release the big lock */
178 LeaveCriticalSection(csp);
182 void lock_ObtainMutex(struct osi_mutex *lockp)
185 CRITICAL_SECTION *csp;
187 if ((i=lockp->type) != 0) {
188 if (i >= 0 && i < OSI_NLOCKTYPES)
189 (osi_lockOps[i]->ObtainMutexProc)(lockp);
193 /* otherwise we're the fast base type */
194 csp = &osi_baseAtomicCS[lockp->atomicIndex];
195 EnterCriticalSection(csp);
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)) {
200 osi_TWait(&lockp->d.turn, OSI_SLEEPINFO_W4WRITE, &lockp->flags, csp);
202 osi_assert(lockp->flags & OSI_LOCKFLAG_EXCL);
205 /* if we're here, all clear to set the lock */
206 lockp->flags |= OSI_LOCKFLAG_EXCL;
208 lockp->tid = thrd_Current();
209 LeaveCriticalSection(csp);
212 void lock_ReleaseMutex(struct osi_mutex *lockp)
215 CRITICAL_SECTION *csp;
217 if ((i = lockp->type) != 0) {
218 if (i >= 0 && i < OSI_NLOCKTYPES)
219 (osi_lockOps[i]->ReleaseMutexProc)(lockp);
223 /* otherwise we're the fast base type */
224 csp = &osi_baseAtomicCS[lockp->atomicIndex];
225 EnterCriticalSection(csp);
227 osi_assertx(lockp->flags & OSI_LOCKFLAG_EXCL, "mutex not held");
229 lockp->flags &= ~OSI_LOCKFLAG_EXCL;
231 if (!osi_TEmpty(&lockp->d.turn)) {
232 osi_TSignalForMLs(&lockp->d.turn, 0, csp);
235 /* and finally release the big lock */
236 LeaveCriticalSection(csp);
240 int lock_TryRead(struct osi_rwlock *lockp)
243 CRITICAL_SECTION *csp;
245 if ((i=lockp->type) != 0)
246 if (i >= 0 && i < OSI_NLOCKTYPES)
247 return (osi_lockOps[i]->TryReadProc)(lockp);
249 /* otherwise we're the fast base type */
250 csp = &osi_baseAtomicCS[lockp->atomicIndex];
251 EnterCriticalSection(csp);
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)) {
258 /* if we're here, all clear to set the lock */
263 LeaveCriticalSection(csp);
269 int lock_TryWrite(struct osi_rwlock *lockp)
272 CRITICAL_SECTION *csp;
274 if ((i=lockp->type) != 0)
275 if (i >= 0 && i < OSI_NLOCKTYPES)
276 return (osi_lockOps[i]->TryWriteProc)(lockp);
278 /* otherwise we're the fast base type */
279 csp = &osi_baseAtomicCS[lockp->atomicIndex];
280 EnterCriticalSection(csp);
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)) {
288 /* if we're here, all clear to set the lock */
289 lockp->flags |= OSI_LOCKFLAG_EXCL;
294 lockp->tid = thrd_Current();
296 LeaveCriticalSection(csp);
302 int lock_TryMutex(struct osi_mutex *lockp) {
304 CRITICAL_SECTION *csp;
306 if ((i=lockp->type) != 0)
307 if (i >= 0 && i < OSI_NLOCKTYPES)
308 return (osi_lockOps[i]->TryMutexProc)(lockp);
310 /* otherwise we're the fast base type */
311 csp = &osi_baseAtomicCS[lockp->atomicIndex];
312 EnterCriticalSection(csp);
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)) {
319 /* if we're here, all clear to set the lock */
320 lockp->flags |= OSI_LOCKFLAG_EXCL;
325 lockp->tid = thrd_Current();
327 LeaveCriticalSection(csp);
332 void osi_SleepR(LONG_PTR sleepVal, struct osi_rwlock *lockp)
335 CRITICAL_SECTION *csp;
337 if ((i = lockp->type) != 0) {
338 if (i >= 0 && i < OSI_NLOCKTYPES)
339 (osi_lockOps[i]->SleepRProc)(sleepVal, lockp);
343 /* otherwise we're the fast base type */
344 csp = &osi_baseAtomicCS[lockp->atomicIndex];
345 EnterCriticalSection(csp);
347 osi_assertx(lockp->readers > 0, "osi_SleepR: not held");
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.
352 if (--lockp->readers == 0 && !osi_TEmpty(&lockp->d.turn)) {
353 osi_TSignalForMLs(&lockp->d.turn, 0, NULL);
356 /* now call into scheduler to sleep atomically with releasing spin lock */
357 osi_SleepSpin(sleepVal, csp);
360 void osi_SleepW(LONG_PTR sleepVal, struct osi_rwlock *lockp)
363 CRITICAL_SECTION *csp;
365 if ((i = lockp->type) != 0) {
366 if (i >= 0 && i < OSI_NLOCKTYPES)
367 (osi_lockOps[i]->SleepWProc)(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_SleepW: 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 osi_SleepM(LONG_PTR sleepVal, struct osi_mutex *lockp)
389 CRITICAL_SECTION *csp;
391 if ((i = lockp->type) != 0) {
392 if (i >= 0 && i < OSI_NLOCKTYPES)
393 (osi_lockOps[i]->SleepMProc)(sleepVal, lockp);
397 /* otherwise we're the fast base type */
398 csp = &osi_baseAtomicCS[lockp->atomicIndex];
399 EnterCriticalSection(csp);
401 osi_assertx(lockp->flags & OSI_LOCKFLAG_EXCL, "osi_SleepM not held");
403 lockp->flags &= ~OSI_LOCKFLAG_EXCL;
404 if (!osi_TEmpty(&lockp->d.turn)) {
405 osi_TSignalForMLs(&lockp->d.turn, 0, NULL);
408 /* and finally release the big lock */
409 osi_SleepSpin(sleepVal, csp);
412 void lock_FinalizeRWLock(osi_rwlock_t *lockp)
416 if ((i=lockp->type) != 0)
417 if (i >= 0 && i < OSI_NLOCKTYPES)
418 (osi_lockOps[i]->FinalizeRWLockProc)(lockp);
421 void lock_FinalizeMutex(osi_mutex_t *lockp)
425 if ((i=lockp->type) != 0)
426 if (i >= 0 && i < OSI_NLOCKTYPES)
427 (osi_lockOps[i]->FinalizeMutexProc)(lockp);
430 void lock_InitializeMutex(osi_mutex_t *mp, char *namep)
434 if ((i = osi_lockTypeDefault) > 0) {
435 if (i >= 0 && i < OSI_NLOCKTYPES)
436 (osi_lockOps[i]->InitializeMutexProc)(mp, namep);
440 /* otherwise we have the base case, which requires no special
446 mp->atomicIndex = osi_MUTEXHASH(mp);
447 osi_TInit(&mp->d.turn);
451 void lock_InitializeRWLock(osi_rwlock_t *mp, char *namep)
455 if ((i = osi_lockTypeDefault) > 0) {
456 if (i >= 0 && i < OSI_NLOCKTYPES)
457 (osi_lockOps[i]->InitializeRWLockProc)(mp, namep);
461 /* otherwise we have the base case, which requires no special
466 mp->atomicIndex = osi_MUTEXHASH(mp);
469 osi_TInit(&mp->d.turn);
473 int lock_GetRWLockState(osi_rwlock_t *lp)
476 CRITICAL_SECTION *csp;
478 if ((i=lp->type) != 0)
479 if (i >= 0 && i < OSI_NLOCKTYPES)
480 return (osi_lockOps[i]->GetRWLockState)(lp);
482 /* otherwise we're the fast base type */
483 csp = &osi_baseAtomicCS[lp->atomicIndex];
484 EnterCriticalSection(csp);
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;
489 if (lp->readers > 0) i |= OSI_RWLOCK_READHELD;
491 LeaveCriticalSection(csp);
496 int lock_GetMutexState(struct osi_mutex *mp) {
498 CRITICAL_SECTION *csp;
500 if ((i=mp->type) != 0)
501 if (i >= 0 && i < OSI_NLOCKTYPES)
502 return (osi_lockOps[i]->GetMutexState)(mp);
504 /* otherwise we're the fast base type */
505 csp = &osi_baseAtomicCS[mp->atomicIndex];
506 EnterCriticalSection(csp);
508 if (mp->flags & OSI_LOCKFLAG_EXCL)
513 LeaveCriticalSection(csp);