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. */
12 #include <afs/param.h>
22 * 2. osi_activeInfoAllocCS.
23 * 3. individual log critical sections (since we call log pkg).
25 * There are no cases today where both 1 and 2 are locked simultaneously.
28 /* el cheapo watch system */
29 osi_watchProc_t
*osi_statWatchProcp
; /* proc to call on too-long held locks */
30 void *osi_statWatchRockp
; /* with this rock */
31 unsigned long osi_statWatchMS
; /* after a lock is held this many MS */
33 /* type index of the statistics gathering lock package */
36 /* log to which to log lock events */
37 osi_log_t
*osi_statLogp
;
39 /* queue of all rwlock auxiliary structures */
40 osi_queue_t
*osi_allRWLocks
;
42 /* queue of all mutex auxiliary structures */
43 osi_queue_t
*osi_allMutexes
;
45 /* free list and mutex for active info structures */
46 osi_activeInfo_t
*osi_activeInfoFreeListp
;
47 CRITICAL_SECTION osi_activeInfoAllocCS
;
49 /* atomicity-providing critical sections */
50 CRITICAL_SECTION osi_statAtomicCS
[OSI_MUTEXHASHSIZE
];
52 /* lock protecting ref count on locks, osi_allMutexes and osi_RWLocks, and
53 * file descriptor contents
55 CRITICAL_SECTION osi_statFDCS
;
57 void osi_SetStatLog(osi_log_t
*logp
)
59 /* nicer if ref counted */
63 static void lock_ObtainWriteStat(osi_rwlock_t
*lockp
)
65 osi_rwlockStat_t
*realp
;
67 CRITICAL_SECTION
*csp
;
69 realp
= (osi_rwlockStat_t
*)lockp
->d
.privateDatap
;
72 csp
= &osi_statAtomicCS
[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
)
77 || (lockp
->readers
> 0)) {
79 if (!ap
) ap
= osi_QueueActiveInfo(&realp
->qi
,
80 OSI_ACTIVEFLAGS_WRITER
| OSI_ACTIVEFLAGS_WAITER
);
81 osi_TWait(&realp
->turn
, OSI_SLEEPINFO_W4WRITE
, &lockp
->flags
, lockp
->tid
, csp
);
83 osi_assert((lockp
->flags
& OSI_LOCKFLAG_EXCL
) && lockp
->readers
== 0);
86 /* if we're here, all clear to set the lock */
87 lockp
->flags
|= OSI_LOCKFLAG_EXCL
;
90 /* if we have ap set, we have some timer info about the last sleep operation
91 * that we should merge in under the spin lock.
94 /* remove from queue and turn time to incremental time */
95 osi_RemoveActiveInfo(&realp
->qi
, ap
);
97 /* add in increment to statistics */
98 realp
->writeBlockedCount
++;
99 realp
->writeBlockedTime
= LargeIntegerAdd(realp
->writeBlockedTime
,
101 osi_FreeActiveInfo(ap
);
104 osi_QueueActiveInfo(&realp
->qi
, OSI_ACTIVEFLAGS_WRITER
);
105 LeaveCriticalSection(csp
);
108 static void lock_ObtainReadStat(osi_rwlock_t
*lockp
)
110 osi_activeInfo_t
*ap
;
111 osi_rwlockStat_t
*realp
;
112 CRITICAL_SECTION
*csp
;
115 realp
= (osi_rwlockStat_t
*) lockp
->d
.privateDatap
;
117 /* otherwise we're the fast base type */
118 csp
= &osi_statAtomicCS
[lockp
->atomicIndex
];
119 EnterCriticalSection(csp
);
121 /* here we have the fast lock, so see if we can obtain the real lock */
122 if (lockp
->waiters
> 0 || (lockp
->flags
& OSI_LOCKFLAG_EXCL
)) {
124 if (!ap
) ap
= osi_QueueActiveInfo(&realp
->qi
,
125 OSI_ACTIVEFLAGS_WAITER
| OSI_ACTIVEFLAGS_READER
);
126 osi_TWait(&realp
->turn
, OSI_SLEEPINFO_W4READ
, &lockp
->readers
, lockp
->tid
, csp
);
128 osi_assert(!(lockp
->flags
& OSI_LOCKFLAG_EXCL
) && lockp
->readers
> 0);
131 /* if we're here, all clear to set the lock */
136 /* have statistics to merge in */
137 osi_RemoveActiveInfo(&realp
->qi
, ap
);
138 realp
->readBlockedCount
++;
139 realp
->readBlockedTime
= LargeIntegerAdd(realp
->readBlockedTime
, ap
->startTime
);
140 osi_FreeActiveInfo(ap
);
143 osi_QueueActiveInfo(&realp
->qi
, OSI_ACTIVEFLAGS_READER
);
144 LeaveCriticalSection(csp
);
147 static void lock_ReleaseReadStat(osi_rwlock_t
*lockp
)
149 osi_activeInfo_t
*ap
;
150 osi_rwlockStat_t
*realp
;
151 CRITICAL_SECTION
*csp
;
153 realp
= (osi_rwlockStat_t
*)lockp
->d
.privateDatap
;
155 csp
= &osi_statAtomicCS
[lockp
->atomicIndex
];
156 EnterCriticalSection(csp
);
158 osi_assert(lockp
->readers
> 0);
159 ap
= osi_FindActiveInfo(&realp
->qi
);
160 osi_assert(ap
!= NULL
);
161 osi_RemoveActiveInfo(&realp
->qi
, ap
);
162 realp
->readLockedCount
++;
163 realp
->readLockedTime
= LargeIntegerAdd(realp
->readLockedTime
, ap
->startTime
);
164 osi_FreeActiveInfo(ap
);
166 if (--lockp
->readers
== 0 && !osi_TEmpty(&realp
->turn
)) {
167 osi_TSignalForMLs(&realp
->turn
, 0, csp
);
170 /* and finally release the big lock */
171 LeaveCriticalSection(csp
);
175 static void lock_ConvertWToRStat(osi_rwlock_t
*lockp
)
177 osi_activeInfo_t
*ap
;
178 osi_rwlockStat_t
*realp
;
179 CRITICAL_SECTION
*csp
;
181 realp
= (osi_rwlockStat_t
*)lockp
->d
.privateDatap
;
183 /* otherwise we're the fast base type */
184 csp
= &osi_statAtomicCS
[lockp
->atomicIndex
];
185 EnterCriticalSection(csp
);
187 osi_assert(lockp
->flags
& OSI_LOCKFLAG_EXCL
);
188 ap
= osi_FindActiveInfo(&realp
->qi
);
189 osi_assert(ap
!=NULL
);
190 osi_RemoveActiveInfo(&realp
->qi
, ap
);
191 realp
->writeLockedCount
++;
192 realp
->writeLockedTime
= LargeIntegerAdd(realp
->writeLockedTime
, ap
->startTime
);
193 osi_FreeActiveInfo(ap
);
195 /* and obtain the read lock */
197 osi_QueueActiveInfo(&realp
->qi
, OSI_ACTIVEFLAGS_READER
);
199 lockp
->flags
&= ~OSI_LOCKFLAG_EXCL
;
200 if (!osi_TEmpty(&realp
->turn
)) {
201 osi_TSignalForMLs(&realp
->turn
, 1, csp
);
204 /* and finally release the big lock */
205 LeaveCriticalSection(csp
);
209 static void lock_ConvertRToWStat(osi_rwlock_t
*lockp
)
211 osi_activeInfo_t
*ap
;
212 osi_rwlockStat_t
*realp
;
213 CRITICAL_SECTION
*csp
;
215 realp
= (osi_rwlockStat_t
*)lockp
->d
.privateDatap
;
217 /* otherwise we're the fast base type */
218 csp
= &osi_statAtomicCS
[lockp
->atomicIndex
];
219 EnterCriticalSection(csp
);
221 osi_assert(lockp
->flags
& OSI_LOCKFLAG_EXCL
);
222 ap
= osi_FindActiveInfo(&realp
->qi
);
223 osi_assert(ap
!=NULL
);
224 osi_RemoveActiveInfo(&realp
->qi
, ap
);
225 realp
->readLockedCount
++;
226 realp
->readLockedTime
= LargeIntegerAdd(realp
->readLockedTime
, ap
->startTime
);
227 osi_FreeActiveInfo(ap
);
229 if (--lockp
->readers
== 0) {
230 /* and obtain the write lock */
232 lockp
->flags
|= OSI_LOCKFLAG_EXCL
;
235 ap
= osi_QueueActiveInfo(&realp
->qi
,
236 OSI_ACTIVEFLAGS_WRITER
| OSI_ACTIVEFLAGS_WAITER
);
237 osi_TWait(&realp
->turn
, OSI_SLEEPINFO_W4WRITE
, &lockp
->flags
, lockp
->tid
, csp
);
239 osi_assert((lockp
->flags
& OSI_LOCKFLAG_EXCL
) && lockp
->readers
== 0);
241 /* we have some timer info about the last sleep operation
242 * that we should merge in under the spin lock.
245 /* remove from queue and turn time to incremental time */
246 osi_RemoveActiveInfo(&realp
->qi
, ap
);
248 /* add in increment to statistics */
249 realp
->writeBlockedCount
++;
250 realp
->writeBlockedTime
= LargeIntegerAdd(realp
->writeBlockedTime
,
252 osi_FreeActiveInfo(ap
);
255 osi_QueueActiveInfo(&realp
->qi
, OSI_ACTIVEFLAGS_WRITER
);
256 LeaveCriticalSection(csp
);
259 static void lock_ReleaseWriteStat(osi_rwlock_t
*lockp
)
261 osi_activeInfo_t
*ap
;
262 osi_rwlockStat_t
*realp
;
263 CRITICAL_SECTION
*csp
;
265 realp
= (osi_rwlockStat_t
*)lockp
->d
.privateDatap
;
267 /* otherwise we're the fast base type */
268 csp
= &osi_statAtomicCS
[lockp
->atomicIndex
];
269 EnterCriticalSection(csp
);
271 osi_assert(lockp
->flags
& OSI_LOCKFLAG_EXCL
);
272 ap
= osi_FindActiveInfo(&realp
->qi
);
273 osi_assert(ap
!=NULL
);
274 osi_RemoveActiveInfo(&realp
->qi
, ap
);
275 realp
->writeLockedCount
++;
276 realp
->writeLockedTime
= LargeIntegerAdd(realp
->writeLockedTime
, ap
->startTime
);
277 osi_FreeActiveInfo(ap
);
279 lockp
->flags
&= ~OSI_LOCKFLAG_EXCL
;
280 if (!osi_TEmpty(&realp
->turn
)) {
281 osi_TSignalForMLs(&realp
->turn
, 0, csp
);
284 /* and finally release the big lock */
285 LeaveCriticalSection(csp
);
289 static void lock_ObtainMutexStat(struct osi_mutex
*lockp
)
291 osi_activeInfo_t
*ap
;
292 osi_mutexStat_t
*realp
;
293 CRITICAL_SECTION
*csp
;
296 realp
= (osi_mutexStat_t
*) lockp
->d
.privateDatap
;
298 csp
= &osi_statAtomicCS
[lockp
->atomicIndex
];
299 EnterCriticalSection(csp
);
301 /* here we have the fast lock, so see if we can obtain the real lock */
302 if (lockp
->waiters
> 0 || (lockp
->flags
& OSI_LOCKFLAG_EXCL
)) {
304 ap
= osi_QueueActiveInfo(&realp
->qi
, OSI_ACTIVEFLAGS_WAITER
);
305 osi_TWait(&realp
->turn
, OSI_SLEEPINFO_W4WRITE
, &lockp
->flags
, &lockp
->tid
, csp
);
307 osi_assert(lockp
->flags
& OSI_LOCKFLAG_EXCL
);
310 /* if we're here, all clear to set the lock */
311 lockp
->flags
|= OSI_LOCKFLAG_EXCL
;
314 /* release the blocking ap */
316 osi_RemoveActiveInfo(&realp
->qi
, ap
);
317 realp
->blockedCount
++;
318 realp
->blockedTime
= LargeIntegerAdd(realp
->blockedTime
, ap
->startTime
);
319 osi_FreeActiveInfo(ap
);
322 /* start tracking this call */
323 osi_QueueActiveInfo(&realp
->qi
, OSI_ACTIVEFLAGS_WRITER
);
325 LeaveCriticalSection(csp
);
328 static void lock_ReleaseMutexStat(struct osi_mutex
*lockp
)
330 osi_activeInfo_t
*ap
;
331 osi_mutexStat_t
*realp
;
332 CRITICAL_SECTION
*csp
;
334 realp
= (osi_mutexStat_t
*)lockp
->d
.privateDatap
;
336 csp
= &osi_statAtomicCS
[lockp
->atomicIndex
];
337 EnterCriticalSection(csp
);
339 osi_assert(lockp
->flags
& OSI_LOCKFLAG_EXCL
);
341 ap
= osi_FindActiveInfo(&realp
->qi
);
342 osi_assert(ap
!= NULL
);
343 osi_RemoveActiveInfo(&realp
->qi
, ap
);
344 realp
->lockedCount
++;
345 realp
->lockedTime
= LargeIntegerAdd(realp
->lockedTime
, ap
->startTime
);
346 osi_FreeActiveInfo(ap
);
348 lockp
->flags
&= ~OSI_LOCKFLAG_EXCL
;
349 if (!osi_TEmpty(&realp
->turn
)) {
350 osi_TSignalForMLs(&realp
->turn
, 0, csp
);
353 /* and finally release the big lock */
354 LeaveCriticalSection(csp
);
358 static int lock_TryReadStat(struct osi_rwlock
*lockp
)
361 osi_rwlockStat_t
*realp
;
362 CRITICAL_SECTION
*csp
;
364 realp
= (osi_rwlockStat_t
*) lockp
->d
.privateDatap
;
366 /* otherwise we're the fast base type */
367 csp
= &osi_statAtomicCS
[lockp
->atomicIndex
];
368 EnterCriticalSection(csp
);
370 /* here we have the fast lock, so see if we can obtain the real lock */
371 if (lockp
->waiters
> 0 || (lockp
->flags
& OSI_LOCKFLAG_EXCL
)) {
375 /* if we're here, all clear to set the lock */
380 /* start tracking lock holding stats */
381 if (i
) osi_QueueActiveInfo(&realp
->qi
, OSI_ACTIVEFLAGS_READER
);
383 LeaveCriticalSection(csp
);
389 static int lock_TryWriteStat(struct osi_rwlock
*lockp
)
392 osi_rwlockStat_t
*realp
;
393 CRITICAL_SECTION
*csp
;
395 realp
= (osi_rwlockStat_t
*) lockp
->d
.privateDatap
;
397 /* otherwise we're the fast base type */
398 csp
= &osi_statAtomicCS
[lockp
->atomicIndex
];
399 EnterCriticalSection(csp
);
401 /* here we have the fast lock, so see if we can obtain the real lock */
402 if ((lockp
->waiters
> 0) || (lockp
->flags
& OSI_LOCKFLAG_EXCL
)
403 || (lockp
->readers
> 0)) {
407 /* if we're here, all clear to set the lock */
408 lockp
->flags
|= OSI_LOCKFLAG_EXCL
;
412 /* start tracking lock holding stats */
413 if (i
) osi_QueueActiveInfo(&realp
->qi
, OSI_ACTIVEFLAGS_WRITER
);
415 LeaveCriticalSection(csp
);
421 static int lock_GetRWLockStateStat(struct osi_rwlock
*lockp
)
424 osi_rwlockStat_t
*realp
;
425 CRITICAL_SECTION
*csp
;
427 realp
= (osi_rwlockStat_t
*) lockp
->d
.privateDatap
;
429 /* otherwise we're the fast base type */
430 csp
= &osi_statAtomicCS
[lockp
->atomicIndex
];
431 EnterCriticalSection(csp
);
434 if (lockp
->flags
& OSI_LOCKFLAG_EXCL
) {
435 i
|= OSI_RWLOCK_WRITEHELD
;
437 if (lockp
->readers
) {
438 i
|= OSI_RWLOCK_READHELD
;
441 LeaveCriticalSection(csp
);
447 static int lock_GetMutexStateStat(struct osi_mutex
*lockp
) {
449 osi_mutexStat_t
*realp
;
450 CRITICAL_SECTION
*csp
;
452 realp
= (osi_mutexStat_t
*) lockp
->d
.privateDatap
;
454 /* otherwise we're the fast base type */
455 csp
= &osi_statAtomicCS
[lockp
->atomicIndex
];
456 EnterCriticalSection(csp
);
458 /* here we have the fast lock, so see if we can obtain the real lock */
460 if (lockp
->flags
& OSI_LOCKFLAG_EXCL
) {
464 LeaveCriticalSection(csp
);
469 static int lock_TryMutexStat(struct osi_mutex
*lockp
) {
471 osi_mutexStat_t
*realp
;
472 CRITICAL_SECTION
*csp
;
474 realp
= (osi_mutexStat_t
*) lockp
->d
.privateDatap
;
476 /* otherwise we're the fast base type */
477 csp
= &osi_statAtomicCS
[lockp
->atomicIndex
];
478 EnterCriticalSection(csp
);
480 /* here we have the fast lock, so see if we can obtain the real lock */
481 if ((lockp
->waiters
> 0) || (lockp
->flags
& OSI_LOCKFLAG_EXCL
)) {
485 /* if we're here, all clear to set the lock */
486 lockp
->flags
|= OSI_LOCKFLAG_EXCL
;
490 if (i
) osi_QueueActiveInfo(&realp
->qi
, 0);
492 LeaveCriticalSection(csp
);
497 static void osi_SleepRStat(LONG_PTR sleepVal
, struct osi_rwlock
*lockp
)
499 osi_rwlockStat_t
*realp
;
500 osi_activeInfo_t
*ap
;
501 CRITICAL_SECTION
*csp
;
503 realp
= (osi_rwlockStat_t
*) lockp
->d
.privateDatap
;
505 /* otherwise we're the fast base type */
506 csp
= &osi_statAtomicCS
[lockp
->atomicIndex
];
507 EnterCriticalSection(csp
);
509 osi_assert(lockp
->readers
> 0);
511 if (--lockp
->readers
== 0 && !osi_TEmpty(&realp
->turn
)) {
512 osi_TSignalForMLs(&realp
->turn
, 0, NULL
);
515 /* now merge in lock hold stats */
516 ap
= osi_FindActiveInfo(&realp
->qi
);
517 osi_assert(ap
!= NULL
);
518 osi_RemoveActiveInfo(&realp
->qi
, ap
);
519 realp
->writeLockedCount
++;
520 realp
->writeLockedTime
= LargeIntegerAdd(realp
->writeLockedTime
, ap
->startTime
);
521 osi_FreeActiveInfo(ap
);
523 /* now call into scheduler to sleep atomically with releasing spin lock */
524 osi_SleepSpin(sleepVal
, csp
);
527 static void osi_SleepWStat(LONG_PTR sleepVal
, struct osi_rwlock
*lockp
)
529 osi_activeInfo_t
*ap
;
530 osi_rwlockStat_t
*realp
;
531 CRITICAL_SECTION
*csp
;
533 realp
= (osi_rwlockStat_t
*) lockp
->d
.privateDatap
;
535 /* otherwise we're the fast base type */
536 csp
= &osi_statAtomicCS
[lockp
->atomicIndex
];
537 EnterCriticalSection(csp
);
539 osi_assert(lockp
->flags
& OSI_LOCKFLAG_EXCL
);
541 lockp
->flags
&= ~OSI_LOCKFLAG_EXCL
;
542 if (!osi_TEmpty(&realp
->turn
)) {
543 osi_TSignalForMLs(&realp
->turn
, 0, NULL
);
546 /* now merge in lock hold stats */
547 ap
= osi_FindActiveInfo(&realp
->qi
);
548 osi_assert(ap
!= NULL
);
549 osi_RemoveActiveInfo(&realp
->qi
, ap
);
550 realp
->readLockedCount
++;
551 realp
->readLockedTime
= LargeIntegerAdd(realp
->readLockedTime
, ap
->startTime
);
552 osi_FreeActiveInfo(ap
);
554 /* and finally release the big lock */
555 osi_SleepSpin(sleepVal
, csp
);
558 static void osi_SleepMStat(LONG_PTR sleepVal
, struct osi_mutex
*lockp
)
560 osi_mutexStat_t
*realp
;
561 osi_activeInfo_t
*ap
;
562 CRITICAL_SECTION
*csp
;
564 realp
= (osi_mutexStat_t
*) lockp
->d
.privateDatap
;
566 /* otherwise we're the fast base type */
567 csp
= &osi_statAtomicCS
[lockp
->atomicIndex
];
568 EnterCriticalSection(csp
);
570 osi_assert(lockp
->flags
& OSI_LOCKFLAG_EXCL
);
572 lockp
->flags
&= ~OSI_LOCKFLAG_EXCL
;
573 if (!osi_TEmpty(&realp
->turn
)) {
574 osi_TSignalForMLs(&realp
->turn
, 0, NULL
);
577 /* now merge in lock hold stats */
578 ap
= osi_FindActiveInfo(&realp
->qi
);
579 osi_assert(ap
!= NULL
);
580 osi_RemoveActiveInfo(&realp
->qi
, ap
);
581 realp
->lockedCount
++;
582 realp
->lockedTime
= LargeIntegerAdd(realp
->lockedTime
, ap
->startTime
);
583 osi_FreeActiveInfo(ap
);
585 /* and finally release the big lock */
586 osi_SleepSpin(sleepVal
, csp
);
589 /* this is a function that release a ref count, but we give it a different
590 * name than release to avoid confusion with all of the releases here.
591 * Must be called holding the osi_statFDCS lock.
593 static void lock_DecrMutexStat(osi_mutexStat_t
*mp
)
595 if (--mp
->refCount
<= 0 && (mp
->states
& OSI_STATL_DELETED
)) {
596 osi_QRemove(&osi_allMutexes
, &mp
->q
);
601 /* Must be called holding the osi_statFDCS lock. */
602 static void lock_DecrRWLockStat(osi_rwlockStat_t
*rwp
)
604 if (--rwp
->refCount
<= 0 && (rwp
->states
& OSI_STATL_DELETED
)) {
605 osi_QRemove(&osi_allRWLocks
, &rwp
->q
);
610 static void lock_FinalizeMutexStat(osi_mutex_t
*lockp
)
612 osi_mutexStat_t
*realp
;
614 /* pull out the real pointer */
615 realp
= (osi_mutexStat_t
*) lockp
->d
.privateDatap
;
617 /* remove from the queues, and free */
618 EnterCriticalSection(&osi_statFDCS
);
619 if (realp
->refCount
<= 0) {
620 osi_QRemove(&osi_allMutexes
, &realp
->q
);
621 free((void *) realp
);
623 else realp
->states
|= OSI_STATL_DELETED
;
624 LeaveCriticalSection(&osi_statFDCS
);
627 static void lock_FinalizeRWLockStat(osi_rwlock_t
*lockp
)
629 osi_rwlockStat_t
*realp
;
631 /* pull out the real pointer */
632 realp
= (osi_rwlockStat_t
*) lockp
->d
.privateDatap
;
634 /* remove from the queues, and free */
635 EnterCriticalSection(&osi_statFDCS
);
636 if (realp
->refCount
<= 0) {
637 osi_QRemove(&osi_allRWLocks
, &realp
->q
);
638 free((void *) realp
);
640 else realp
->states
|= OSI_STATL_DELETED
;
641 LeaveCriticalSection(&osi_statFDCS
);
644 void lock_InitializeRWLockStat(osi_rwlock_t
*lockp
, char *namep
, unsigned short level
)
646 osi_rwlockStat_t
*realp
;
648 realp
= (osi_rwlockStat_t
*) malloc(sizeof(*realp
));
649 lockp
->d
.privateDatap
= (void *) realp
;
650 lockp
->type
= osi_statType
;
653 lockp
->atomicIndex
= osi_MUTEXHASH(lockp
);
654 memset(realp
, 0, sizeof(*realp
));
655 osi_TInit(&realp
->turn
);
656 realp
->qi
.namep
= namep
;
657 realp
->qi
.backp
= lockp
;
658 EnterCriticalSection(&osi_statFDCS
);
659 osi_QAdd(&osi_allRWLocks
, &realp
->q
);
660 LeaveCriticalSection(&osi_statFDCS
);
663 void lock_InitializeMutexStat(osi_mutex_t
*lockp
, char *namep
, unsigned short level
)
665 osi_mutexStat_t
*realp
;
667 realp
= (osi_mutexStat_t
*) malloc(sizeof(*realp
));
668 lockp
->d
.privateDatap
= (void *) realp
;
669 lockp
->type
= osi_statType
;
671 lockp
->atomicIndex
= osi_MUTEXHASH(lockp
);
672 memset(realp
, 0, sizeof(*realp
));
673 osi_TInit(&realp
->turn
);
674 realp
->qi
.namep
= namep
;
675 realp
->qi
.backp
= lockp
;
676 EnterCriticalSection(&osi_statFDCS
);
677 osi_QAdd(&osi_allMutexes
, &realp
->q
);
678 LeaveCriticalSection(&osi_statFDCS
);
681 static void osi_FreeActiveInfo(osi_activeInfo_t
*ap
)
683 EnterCriticalSection(&osi_activeInfoAllocCS
);
684 ap
->q
.nextp
= (osi_queue_t
*) osi_activeInfoFreeListp
;
685 osi_activeInfoFreeListp
= ap
;
686 LeaveCriticalSection(&osi_activeInfoAllocCS
);
689 static osi_activeInfo_t
*osi_AllocActiveInfo()
691 osi_activeInfo_t
*ap
;
693 EnterCriticalSection(&osi_activeInfoAllocCS
);
694 if (!(ap
= osi_activeInfoFreeListp
)) {
695 ap
= (osi_activeInfo_t
*) malloc(sizeof(osi_activeInfo_t
));
698 osi_activeInfoFreeListp
= (osi_activeInfo_t
*) ap
->q
.nextp
;
700 LeaveCriticalSection(&osi_activeInfoAllocCS
);
705 static osi_activeInfo_t
*osi_QueueActiveInfo(osi_qiStat_t
*qp
, int flags
)
707 osi_activeInfo_t
*ap
;
708 osi_queue_t
**qpp
= (osi_queue_t
**) &qp
->activeListp
;
711 ap
= osi_AllocActiveInfo();
713 ap
->startTime
.LowPart
= GetCurrentTime();
714 ap
->startTime
.HighPart
= 0;
715 ap
->tid
= GetCurrentThreadId();
716 osi_QAdd(qpp
, &ap
->q
);
717 if (osi_statLogp
&& (flags
& OSI_ACTIVEFLAGS_WAITER
)) {
718 if (flags
& OSI_ACTIVEFLAGS_READER
)
720 else if (flags
& OSI_ACTIVEFLAGS_WRITER
)
721 whatp
= "write lock";
722 else whatp
= "mutex";
723 osi_Log2(osi_statLogp
, "Blocking on %s on %s", whatp
, qp
->namep
);
728 static void osi_RemoveActiveInfo(osi_qiStat_t
*qp
, osi_activeInfo_t
*ap
)
731 osi_queue_t
**qpp
= (osi_queue_t
**) &qp
->activeListp
;
735 now
= GetCurrentTime();
736 osi_QRemove(qpp
, &ap
->q
);
738 ap
->startTime
.LowPart
= now
- ap
->startTime
.LowPart
;
740 if (osi_statLogp
&& (flags
& OSI_ACTIVEFLAGS_WAITER
)) {
741 if (flags
& OSI_ACTIVEFLAGS_READER
)
743 else if (flags
& OSI_ACTIVEFLAGS_WRITER
)
744 whatp
= "write lock";
745 else whatp
= "mutex";
746 osi_Log2(osi_statLogp
, "Finally obtained %s on %s", whatp
, qp
->namep
);
749 /* releasing a lock or mutex */
750 if (osi_statWatchProcp
&& ap
->startTime
.LowPart
> osi_statWatchMS
) {
751 (*osi_statWatchProcp
)(osi_statWatchRockp
, ap
->startTime
.LowPart
,
757 static osi_activeInfo_t
*osi_FindActiveInfo(osi_qiStat_t
*qp
)
760 osi_activeInfo_t
*ap
;
762 osi_queue_t
**qpp
= (osi_queue_t
**) &qp
->activeListp
;
765 tid
= GetCurrentThreadId();
767 for(tqp
= *qpp
; tqp
; tqp
= tqp
->nextp
) {
768 ap
= (osi_activeInfo_t
*) tqp
;
769 if (ap
->tid
== tid
) break;
775 static osi_lockOps_t osi_statOps
= {
777 lock_ObtainWriteStat
,
778 lock_ReleaseReadStat
,
779 lock_ReleaseWriteStat
,
780 lock_ObtainMutexStat
,
781 lock_ReleaseMutexStat
,
788 lock_InitializeMutexStat
,
789 lock_InitializeRWLockStat
,
790 lock_FinalizeMutexStat
,
791 lock_FinalizeRWLockStat
,
792 lock_ConvertWToRStat
,
793 lock_ConvertRToWStat
,
794 lock_GetRWLockStateStat
,
795 lock_GetMutexStateStat
798 long osi_StatFDCreate(osi_fdType_t
*typep
, osi_fd_t
**fdpp
)
802 osi_rwlockStat_t
*rwp
;
804 fdp
= (osi_statFD_t
*) malloc(sizeof(*fdp
));
805 EnterCriticalSection(&osi_statFDCS
);
806 if (osi_allMutexes
) {
807 fdp
->curp
= osi_allMutexes
;
808 mp
= (osi_mutexStat_t
*) fdp
->curp
;
812 else if (osi_allRWLocks
) {
813 fdp
->curp
= osi_allRWLocks
;
814 rwp
= (osi_rwlockStat_t
*) fdp
->curp
;
818 else fdp
->curp
= NULL
;
819 LeaveCriticalSection(&osi_statFDCS
);
826 long osi_StatFDGetInfo(osi_fd_t
*ifdp
, osi_remGetInfoParms_t
*parmsp
)
830 osi_rwlockStat_t
*rwp
;
832 osi_mutex_t
*backMutexp
;
833 osi_rwlock_t
*backRWLockp
;
835 /* initialize out structure */
839 fdp
= (osi_statFD_t
*) ifdp
;
842 /* we're done if curp is null */
843 if (qp
== NULL
) return OSI_DBRPC_EOF
;
845 /* copy out statistics */
846 if (fdp
->which
== 0) {
847 /* this is a mutex */
848 mp
= (osi_mutexStat_t
*) qp
;
850 memset((void *) parmsp
, 0, sizeof(*parmsp
));
851 backMutexp
= mp
->qi
.backp
;
852 parmsp
->idata
[0] = (LONG_PTR
)backMutexp
;
853 parmsp
->idata
[1] = (backMutexp
->flags
& OSI_LOCKFLAG_EXCL
)? 1 : 0;
854 /* reader count [2] is 0 */
855 parmsp
->idata
[3] = (backMutexp
->waiters
> 0)? 1 : 0;
856 parmsp
->idata
[4] = mp
->lockedTime
.LowPart
;
857 parmsp
->idata
[5] = mp
->lockedCount
;
858 parmsp
->idata
[6] = mp
->blockedTime
.LowPart
;
859 parmsp
->idata
[7] = mp
->blockedCount
;
860 strcpy(parmsp
->sdata
[0], mp
->qi
.namep
);
864 else if (fdp
->which
== 1) {
866 rwp
= (osi_rwlockStat_t
*) qp
;
868 memset((void *) parmsp
, 0, sizeof(*parmsp
));
869 backRWLockp
= rwp
->qi
.backp
;
870 parmsp
->idata
[0] = (LONG_PTR
)backRWLockp
;
871 parmsp
->idata
[1] = (backRWLockp
->flags
& OSI_LOCKFLAG_EXCL
)? 1 : 0;
872 parmsp
->idata
[2] = backRWLockp
->readers
;
873 parmsp
->idata
[3] = (backRWLockp
->waiters
> 0)? 1 : 0;
874 parmsp
->idata
[4] = rwp
->writeLockedTime
.LowPart
;
875 parmsp
->idata
[5] = rwp
->writeLockedCount
;
876 parmsp
->idata
[6] = rwp
->writeBlockedTime
.LowPart
;
877 parmsp
->idata
[7] = rwp
->writeBlockedCount
;
878 parmsp
->idata
[8] = rwp
->readLockedTime
.LowPart
;
879 parmsp
->idata
[9] = rwp
->readLockedCount
;
880 parmsp
->idata
[10] = rwp
->readBlockedTime
.LowPart
;
881 parmsp
->idata
[11] = rwp
->readBlockedCount
;
882 strcpy(parmsp
->sdata
[0], rwp
->qi
.namep
);
887 /* advance to next position */
888 EnterCriticalSection(&osi_statFDCS
);
890 if (fdp
->which
== 0) {
891 mp
= (osi_mutexStat_t
*) qp
;
892 lock_DecrMutexStat(mp
);
894 else if (fdp
->which
== 1) {
895 rwp
= (osi_rwlockStat_t
*) qp
;
896 lock_DecrRWLockStat(rwp
);
900 if (qp
== NULL
&& fdp
->which
== 0) {
902 if (osi_allRWLocks
) qp
= osi_allRWLocks
;
907 if (fdp
->which
== 0) {
908 mp
= (osi_mutexStat_t
*) qp
;
911 else if (fdp
->which
== 1) {
912 rwp
= (osi_rwlockStat_t
*) qp
;
916 LeaveCriticalSection(&osi_statFDCS
);
921 long osi_StatFDClose(osi_fd_t
*ifdp
)
927 osi_fdOps_t osi_statFDOps
= {
938 /* initialize the stat package */
939 InitializeCriticalSection(&osi_activeInfoAllocCS
);
940 InitializeCriticalSection(&osi_statFDCS
);
942 for(i
=0; i
<OSI_MUTEXHASHSIZE
; i
++)
943 InitializeCriticalSection(&osi_statAtomicCS
[i
]);
945 /* add stat ops to dynamic registry */
946 osi_LockTypeAdd(&osi_statOps
, "stat", &osi_statType
);
948 /* add debugging info and file descriptor support */
949 typep
= osi_RegisterFDType("lock", &osi_statFDOps
, NULL
);
951 /* add formatting info */
952 osi_AddFDFormatInfo(typep
, OSI_DBRPC_REGIONINT
, 0,
953 "Lock address", OSI_DBRPC_HEX
);
954 osi_AddFDFormatInfo(typep
, OSI_DBRPC_REGIONINT
, 1,
956 osi_AddFDFormatInfo(typep
, OSI_DBRPC_REGIONINT
, 2,
958 osi_AddFDFormatInfo(typep
, OSI_DBRPC_REGIONINT
, 3,
960 osi_AddFDFormatInfo(typep
, OSI_DBRPC_REGIONINT
, 4,
961 "Write-locked time", 0);
962 osi_AddFDFormatInfo(typep
, OSI_DBRPC_REGIONINT
, 5,
963 "Write-locked count", 0);
964 osi_AddFDFormatInfo(typep
, OSI_DBRPC_REGIONINT
, 6,
965 "Write-blocked time", 0);
966 osi_AddFDFormatInfo(typep
, OSI_DBRPC_REGIONINT
, 7,
967 "Write-blocked count", 0);
968 osi_AddFDFormatInfo(typep
, OSI_DBRPC_REGIONINT
, 8,
969 "Read-locked time", 0);
970 osi_AddFDFormatInfo(typep
, OSI_DBRPC_REGIONINT
, 9,
971 "Read-locked count", 0);
972 osi_AddFDFormatInfo(typep
, OSI_DBRPC_REGIONINT
, 10,
973 "Read-blocked time", 0);
974 osi_AddFDFormatInfo(typep
, OSI_DBRPC_REGIONINT
, 11,
975 "Read-blocked count", 0);
978 osi_AddFDFormatInfo(typep
, OSI_DBRPC_REGIONSTRING
, 0,
983 /* set lock watching stuff */
984 void osi_SetWatchProc(long ms
, osi_watchProc_t
*procp
, void *rockp
)
986 osi_statWatchProcp
= procp
;
987 osi_statWatchRockp
= rockp
;
988 osi_statWatchMS
= ms
;