Update NEWS for 1.6.22
[pkg-k5-afs_openafs.git] / src / WINNT / client_osi / osistatl.c
blobd11f5d7ed1e8d6fc7cb9c7b2da3c152b2e5abff9
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
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 */
10 /* Copyright (C) 1994 Cazamar Systems, Inc. */
12 #include <afs/param.h>
13 #include <afs/stds.h>
15 #include <windows.h>
16 #include "osi.h"
17 #include <stdlib.h>
18 #include <assert.h>
20 /* locking hierarchy:
21 * 1. osi_statFDCS
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 */
34 int osi_statType;
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 */
60 osi_statLogp = logp;
63 static void lock_ObtainWriteStat(osi_rwlock_t *lockp)
65 osi_rwlockStat_t *realp;
66 osi_activeInfo_t *ap;
67 CRITICAL_SECTION *csp;
69 realp = (osi_rwlockStat_t *)lockp->d.privateDatap;
70 ap = NULL;
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)) {
78 lockp->waiters++;
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);
82 lockp->waiters--;
83 osi_assert((lockp->flags & OSI_LOCKFLAG_EXCL) && lockp->readers == 0);
85 else {
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.
93 if (ap) {
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,
100 ap->startTime);
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;
114 ap = NULL;
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)) {
123 lockp->waiters++;
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);
127 lockp->waiters--;
128 osi_assert(!(lockp->flags & OSI_LOCKFLAG_EXCL) && lockp->readers > 0);
130 else {
131 /* if we're here, all clear to set the lock */
132 lockp->readers++;
135 if (ap) {
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);
169 else {
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 */
196 lockp->readers++;
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);
203 else {
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 */
231 lockp->readers--;
232 lockp->flags |= OSI_LOCKFLAG_EXCL;
233 } else {
234 lockp->waiters++;
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);
238 lockp->waiters--;
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,
251 ap->startTime);
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);
283 else {
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;
295 ap = NULL;
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)) {
303 lockp->waiters++;
304 ap = osi_QueueActiveInfo(&realp->qi, OSI_ACTIVEFLAGS_WAITER);
305 osi_TWait(&realp->turn, OSI_SLEEPINFO_W4WRITE, &lockp->flags, &lockp->tid, csp);
306 lockp->waiters--;
307 osi_assert(lockp->flags & OSI_LOCKFLAG_EXCL);
309 else {
310 /* if we're here, all clear to set the lock */
311 lockp->flags |= OSI_LOCKFLAG_EXCL;
314 /* release the blocking ap */
315 if (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);
352 else {
353 /* and finally release the big lock */
354 LeaveCriticalSection(csp);
358 static int lock_TryReadStat(struct osi_rwlock *lockp)
360 long i;
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)) {
372 i = 0;
374 else {
375 /* if we're here, all clear to set the lock */
376 lockp->readers++;
377 i = 1;
380 /* start tracking lock holding stats */
381 if (i) osi_QueueActiveInfo(&realp->qi, OSI_ACTIVEFLAGS_READER);
383 LeaveCriticalSection(csp);
385 return i;
389 static int lock_TryWriteStat(struct osi_rwlock *lockp)
391 long i;
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)) {
404 i = 0;
406 else {
407 /* if we're here, all clear to set the lock */
408 lockp->flags |= OSI_LOCKFLAG_EXCL;
409 i = 1;
412 /* start tracking lock holding stats */
413 if (i) osi_QueueActiveInfo(&realp->qi, OSI_ACTIVEFLAGS_WRITER);
415 LeaveCriticalSection(csp);
417 return i;
421 static int lock_GetRWLockStateStat(struct osi_rwlock *lockp)
423 long i;
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);
433 i = 0;
434 if (lockp->flags & OSI_LOCKFLAG_EXCL) {
435 i |= OSI_RWLOCK_WRITEHELD;
437 if (lockp->readers) {
438 i |= OSI_RWLOCK_READHELD;
441 LeaveCriticalSection(csp);
443 return i;
447 static int lock_GetMutexStateStat(struct osi_mutex *lockp) {
448 long i;
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 */
459 i = 0;
460 if (lockp->flags & OSI_LOCKFLAG_EXCL) {
461 i |= OSI_MUTEX_HELD;
464 LeaveCriticalSection(csp);
466 return i;
469 static int lock_TryMutexStat(struct osi_mutex *lockp) {
470 long i;
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)) {
482 i = 0;
484 else {
485 /* if we're here, all clear to set the lock */
486 lockp->flags |= OSI_LOCKFLAG_EXCL;
487 i = 1;
490 if (i) osi_QueueActiveInfo(&realp->qi, 0);
492 LeaveCriticalSection(csp);
494 return i;
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);
597 free((void *)mp);
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);
606 free((void *)rwp);
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;
651 lockp->flags = 0;
652 lockp->readers = 0;
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;
670 lockp->flags = 0;
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));
697 else {
698 osi_activeInfoFreeListp = (osi_activeInfo_t *) ap->q.nextp;
700 LeaveCriticalSection(&osi_activeInfoAllocCS);
702 return ap;
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;
709 char *whatp;
711 ap = osi_AllocActiveInfo();
712 ap->flags = flags;
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)
719 whatp = "read lock";
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);
725 return ap;
728 static void osi_RemoveActiveInfo(osi_qiStat_t *qp, osi_activeInfo_t *ap)
730 unsigned long now;
731 osi_queue_t **qpp = (osi_queue_t **) &qp->activeListp;
732 long flags;
733 char *whatp;
735 now = GetCurrentTime();
736 osi_QRemove(qpp, &ap->q);
737 flags = ap->flags;
738 ap->startTime.LowPart = now - ap->startTime.LowPart;
740 if (osi_statLogp && (flags & OSI_ACTIVEFLAGS_WAITER)) {
741 if (flags & OSI_ACTIVEFLAGS_READER)
742 whatp = "read lock";
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);
748 else {
749 /* releasing a lock or mutex */
750 if (osi_statWatchProcp && ap->startTime.LowPart > osi_statWatchMS) {
751 (*osi_statWatchProcp)(osi_statWatchRockp, ap->startTime.LowPart,
752 qp->backp);
757 static osi_activeInfo_t *osi_FindActiveInfo(osi_qiStat_t *qp)
759 unsigned long tid;
760 osi_activeInfo_t *ap;
761 osi_queue_t *tqp;
762 osi_queue_t **qpp = (osi_queue_t **) &qp->activeListp;
764 ap = NULL;
765 tid = GetCurrentThreadId();
766 if (*qpp != NULL) {
767 for(tqp = *qpp; tqp; tqp = tqp->nextp) {
768 ap = (osi_activeInfo_t *) tqp;
769 if (ap->tid == tid) break;
772 return ap;
775 static osi_lockOps_t osi_statOps = {
776 lock_ObtainReadStat,
777 lock_ObtainWriteStat,
778 lock_ReleaseReadStat,
779 lock_ReleaseWriteStat,
780 lock_ObtainMutexStat,
781 lock_ReleaseMutexStat,
782 lock_TryReadStat,
783 lock_TryWriteStat,
784 lock_TryMutexStat,
785 osi_SleepRStat,
786 osi_SleepWStat,
787 osi_SleepMStat,
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)
800 osi_statFD_t *fdp;
801 osi_mutexStat_t *mp;
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;
809 mp->refCount++;
810 fdp->which = 0;
812 else if (osi_allRWLocks) {
813 fdp->curp = osi_allRWLocks;
814 rwp = (osi_rwlockStat_t *) fdp->curp;
815 rwp->refCount++;
816 fdp->which = 1;
818 else fdp->curp = NULL;
819 LeaveCriticalSection(&osi_statFDCS);
821 *fdpp = &fdp->fd;
823 return 0;
826 long osi_StatFDGetInfo(osi_fd_t *ifdp, osi_remGetInfoParms_t *parmsp)
828 osi_mutexStat_t *mp;
829 osi_statFD_t *fdp;
830 osi_rwlockStat_t *rwp;
831 osi_queue_t *qp;
832 osi_mutex_t *backMutexp;
833 osi_rwlock_t *backRWLockp;
835 /* initialize out structure */
836 parmsp->icount = 0;
837 parmsp->scount = 0;
839 fdp = (osi_statFD_t *) ifdp;
840 qp = fdp->curp;
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);
861 parmsp->icount = 8;
862 parmsp->scount = 1;
864 else if (fdp->which == 1) {
865 /* rwlock */
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);
883 parmsp->scount = 1;
884 parmsp->icount = 12;
887 /* advance to next position */
888 EnterCriticalSection(&osi_statFDCS);
889 if (qp != NULL) {
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);
898 qp = osi_QNext(qp);
900 if (qp == NULL && fdp->which == 0) {
901 fdp->which = 1;
902 if (osi_allRWLocks) qp = osi_allRWLocks;
903 else qp = NULL;
905 fdp->curp = qp;
906 if (qp != NULL) {
907 if (fdp->which == 0) {
908 mp = (osi_mutexStat_t *) qp;
909 mp->refCount++;
911 else if (fdp->which == 1) {
912 rwp = (osi_rwlockStat_t *) qp;
913 rwp->refCount++;
916 LeaveCriticalSection(&osi_statFDCS);
918 return 0;
921 long osi_StatFDClose(osi_fd_t *ifdp)
923 free((void *)ifdp);
924 return 0;
927 osi_fdOps_t osi_statFDOps = {
928 osi_StatFDCreate,
929 osi_StatFDGetInfo,
930 osi_StatFDClose
933 void osi_StatInit()
935 osi_fdType_t *typep;
936 int i;
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);
950 if (typep) {
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,
955 "Writer count", 0);
956 osi_AddFDFormatInfo(typep, OSI_DBRPC_REGIONINT, 2,
957 "Reader count", 0);
958 osi_AddFDFormatInfo(typep, OSI_DBRPC_REGIONINT, 3,
959 "Are waiters", 0);
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);
977 /* and the string */
978 osi_AddFDFormatInfo(typep, OSI_DBRPC_REGIONSTRING, 0,
979 "Lock name", 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;