Initial IBM OpenAFS 1.0 tree
[openafs.git] / src / WINNT / client_osi / osistatl.c
1 /* 
2  * Copyright (C) 1998, 1989 Transarc Corporation - All rights reserved
3  *
4  * (C) COPYRIGHT IBM CORPORATION 1987, 1988
5  * LICENSED MATERIALS - PROPERTY OF IBM
6  *
7  */
8
9 /* Copyright (C) 1994 Cazamar Systems, Inc. */
10
11 #include <afs/param.h>
12 #include <afs/stds.h>
13
14 #include <windows.h>
15 #include "osi.h"
16 #include <stdlib.h>
17 #include <assert.h>
18
19 /* locking hierarchy:
20  * 1. osi_statFDCS
21  * 2. osi_activeInfoAllocCS.
22  * 3. individual log critical sections (since we call log pkg).
23  *
24  * There are no cases today where both 1 and 2 are locked simultaneously.
25  */
26
27 /* el cheapo watch system */
28 osi_watchProc_t *osi_statWatchProcp;    /* proc to call on too-long held locks */
29 void *osi_statWatchRockp;               /* with this rock */
30 unsigned long osi_statWatchMS;          /* after a lock is held this many MS */
31
32 /* type index of the statistics gathering lock package */
33 int osi_statType;
34
35 /* log to which to log lock events */
36 osi_log_t *osi_statLogp;
37
38 /* queue of all rwlock auxiliary structures */
39 osi_queue_t *osi_allRWLocks;
40
41 /* queue of all mutex auxiliary structures */
42 osi_queue_t *osi_allMutexes;
43
44 /* free list and mutex for active info structures */
45 osi_activeInfo_t *osi_activeInfoFreeListp;
46 CRITICAL_SECTION osi_activeInfoAllocCS;
47
48 /* atomicity-providing critical sections */
49 CRITICAL_SECTION osi_statAtomicCS[OSI_MUTEXHASHSIZE];
50
51 /* lock protecting ref count on locks, osi_allMutexes and osi_RWLocks, and
52  * file descriptor contents
53  */
54 CRITICAL_SECTION osi_statFDCS;
55
56 void osi_SetStatLog(osi_log_t *logp)
57 {
58         /* nicer if ref counted */
59         osi_statLogp = logp;
60 }
61
62 static void lock_ObtainWriteStat(osi_rwlock_t *lockp)
63 {
64         osi_rwlockStat_t *realp;
65         osi_activeInfo_t *ap;
66         CRITICAL_SECTION *csp;
67
68         realp = (osi_rwlockStat_t *)lockp->d.privateDatap;
69         ap = NULL;
70
71         csp = &osi_statAtomicCS[lockp->atomicIndex];
72         EnterCriticalSection(csp);
73
74         /* here we have the fast lock, so see if we can obtain the real lock */
75         if ((lockp->waiters > 0) || (lockp->flags & OSI_LOCKFLAG_EXCL)
76                 || (lockp->readers > 0)) {
77                 lockp->waiters++;
78                 if (!ap) ap = osi_QueueActiveInfo(&realp->qi,
79                         OSI_ACTIVEFLAGS_WRITER | OSI_ACTIVEFLAGS_WAITER);
80                 osi_TWait(&realp->turn, OSI_SLEEPINFO_W4WRITE, &lockp->flags, csp);
81                 lockp->waiters--;
82                 osi_assert((lockp->flags & OSI_LOCKFLAG_EXCL) && lockp->readers == 0);
83         }
84         else {
85                 /* if we're here, all clear to set the lock */
86                 lockp->flags |= OSI_LOCKFLAG_EXCL;
87         }
88
89         /* if we have ap set, we have some timer info about the last sleep operation
90          * that we should merge in under the spin lock.
91          */
92         if (ap) {
93                 /* remove from queue and turn time to incremental time */
94                 osi_RemoveActiveInfo(&realp->qi, ap);
95                 
96                 /* add in increment to statistics */
97                 realp->writeBlockedCount++;
98                 realp->writeBlockedTime = LargeIntegerAdd(realp->writeBlockedTime,
99                         ap->startTime);
100                 osi_FreeActiveInfo(ap);
101         }
102
103         osi_QueueActiveInfo(&realp->qi, OSI_ACTIVEFLAGS_WRITER);
104         LeaveCriticalSection(csp);
105 }
106
107 static void lock_ObtainReadStat(osi_rwlock_t *lockp)
108 {
109         osi_activeInfo_t *ap;
110         osi_rwlockStat_t *realp;
111         CRITICAL_SECTION *csp;
112
113         ap = NULL;
114         realp = (osi_rwlockStat_t *) lockp->d.privateDatap;
115
116         /* otherwise we're the fast base type */
117         csp = &osi_statAtomicCS[lockp->atomicIndex];
118         EnterCriticalSection(csp);
119
120         /* here we have the fast lock, so see if we can obtain the real lock */
121         if (lockp->waiters > 0 || (lockp->flags & OSI_LOCKFLAG_EXCL)) {
122                 lockp->waiters++;
123                 if (!ap) ap = osi_QueueActiveInfo(&realp->qi,
124                         OSI_ACTIVEFLAGS_WAITER | OSI_ACTIVEFLAGS_READER);
125                 osi_TWait(&realp->turn, OSI_SLEEPINFO_W4READ, &lockp->readers, csp);
126                 lockp->waiters--;
127                 osi_assert(!(lockp->flags & OSI_LOCKFLAG_EXCL) && lockp->readers > 0);
128         }
129         else {
130                 /* if we're here, all clear to set the lock */
131                 lockp->readers++;
132         }
133
134         if (ap) {
135                 /* have statistics to merge in */
136                 osi_RemoveActiveInfo(&realp->qi, ap);
137                 realp->readBlockedCount++;
138                 realp->readBlockedTime = LargeIntegerAdd(realp->readBlockedTime, ap->startTime);
139                 osi_FreeActiveInfo(ap);
140         }
141
142         osi_QueueActiveInfo(&realp->qi, OSI_ACTIVEFLAGS_READER);
143         LeaveCriticalSection(csp);
144 }
145
146 static void lock_ReleaseReadStat(osi_rwlock_t *lockp)
147 {
148         osi_activeInfo_t *ap;
149         osi_rwlockStat_t *realp;
150         CRITICAL_SECTION *csp;
151
152         realp = (osi_rwlockStat_t *)lockp->d.privateDatap;
153
154         csp = &osi_statAtomicCS[lockp->atomicIndex];
155         EnterCriticalSection(csp);
156
157         osi_assert(lockp->readers > 0);
158         ap = osi_FindActiveInfo(&realp->qi);
159         osi_assert(ap != NULL);
160         osi_RemoveActiveInfo(&realp->qi, ap);
161         realp->readLockedCount++;
162         realp->readLockedTime = LargeIntegerAdd(realp->readLockedTime, ap->startTime);
163         osi_FreeActiveInfo(ap);
164         
165         if (--lockp->readers == 0 && !osi_TEmpty(&realp->turn)) {
166                 osi_TSignalForMLs(&realp->turn, 0, csp);
167         }
168         else {
169                 /* and finally release the big lock */
170                 LeaveCriticalSection(csp);
171         }
172 }
173
174 static void lock_ConvertWToRStat(osi_rwlock_t *lockp)
175 {
176         osi_activeInfo_t *ap;
177         osi_rwlockStat_t *realp;
178         CRITICAL_SECTION *csp;
179
180         realp = (osi_rwlockStat_t *)lockp->d.privateDatap;
181
182         /* otherwise we're the fast base type */
183         csp = &osi_statAtomicCS[lockp->atomicIndex];
184         EnterCriticalSection(csp);
185
186         osi_assert(lockp->flags & OSI_LOCKFLAG_EXCL);
187         ap = osi_FindActiveInfo(&realp->qi);
188         osi_assert(ap !=NULL);
189         osi_RemoveActiveInfo(&realp->qi, ap);
190         realp->writeLockedCount++;
191         realp->writeLockedTime = LargeIntegerAdd(realp->writeLockedTime, ap->startTime);
192         osi_FreeActiveInfo(ap);
193         
194         /* and obtain the read lock */
195         lockp->readers++;
196         osi_QueueActiveInfo(&realp->qi, OSI_ACTIVEFLAGS_READER);
197         
198         lockp->flags &= ~OSI_LOCKFLAG_EXCL;
199         if (!osi_TEmpty(&realp->turn)) {
200                 osi_TSignalForMLs(&realp->turn, 1, csp);
201         }
202         else {
203                 /* and finally release the big lock */
204                 LeaveCriticalSection(csp);
205         }
206 }
207
208 static void lock_ReleaseWriteStat(osi_rwlock_t *lockp)
209 {
210         osi_activeInfo_t *ap;
211         osi_rwlockStat_t *realp;
212         CRITICAL_SECTION *csp;
213
214         realp = (osi_rwlockStat_t *)lockp->d.privateDatap;
215
216         /* otherwise we're the fast base type */
217         csp = &osi_statAtomicCS[lockp->atomicIndex];
218         EnterCriticalSection(csp);
219
220         osi_assert(lockp->flags & OSI_LOCKFLAG_EXCL);
221         ap = osi_FindActiveInfo(&realp->qi);
222         osi_assert(ap !=NULL);
223         osi_RemoveActiveInfo(&realp->qi, ap);
224         realp->writeLockedCount++;
225         realp->writeLockedTime = LargeIntegerAdd(realp->writeLockedTime, ap->startTime);
226         osi_FreeActiveInfo(ap);
227         
228         lockp->flags &= ~OSI_LOCKFLAG_EXCL;
229         if (!osi_TEmpty(&realp->turn)) {
230                 osi_TSignalForMLs(&realp->turn, 0, csp);
231         }
232         else {
233                 /* and finally release the big lock */
234                 LeaveCriticalSection(csp);
235         }
236 }
237
238 static void lock_ObtainMutexStat(struct osi_mutex *lockp)
239 {
240         osi_activeInfo_t *ap;
241         osi_mutexStat_t *realp;
242         CRITICAL_SECTION *csp;
243
244         ap = NULL;
245         realp = (osi_mutexStat_t *) lockp->d.privateDatap;
246
247         csp = &osi_statAtomicCS[lockp->atomicIndex];
248         EnterCriticalSection(csp);
249
250         /* here we have the fast lock, so see if we can obtain the real lock */
251         if (lockp->waiters > 0 || (lockp->flags & OSI_LOCKFLAG_EXCL)) {
252                 lockp->waiters++;
253                 ap = osi_QueueActiveInfo(&realp->qi, OSI_ACTIVEFLAGS_WAITER);
254                 osi_TWait(&realp->turn, OSI_SLEEPINFO_W4WRITE, &lockp->flags, csp);
255                 lockp->waiters--;
256                 osi_assert(lockp->flags & OSI_LOCKFLAG_EXCL);
257         }
258         else {
259                 /* if we're here, all clear to set the lock */
260                 lockp->flags |= OSI_LOCKFLAG_EXCL;
261         }
262
263         /* release the blocking ap */
264         if (ap) {
265                 osi_RemoveActiveInfo(&realp->qi, ap);
266                 realp->blockedCount++;
267                 realp->blockedTime = LargeIntegerAdd(realp->blockedTime, ap->startTime);
268                 osi_FreeActiveInfo(ap);
269         }
270
271         /* start tracking this call */
272         osi_QueueActiveInfo(&realp->qi, OSI_ACTIVEFLAGS_WRITER);
273
274         LeaveCriticalSection(csp);
275 }
276
277 static void lock_ReleaseMutexStat(struct osi_mutex *lockp)
278 {
279         osi_activeInfo_t *ap;
280         osi_mutexStat_t *realp;
281         CRITICAL_SECTION *csp;
282
283         realp = (osi_mutexStat_t *)lockp->d.privateDatap;
284
285         csp = &osi_statAtomicCS[lockp->atomicIndex];
286         EnterCriticalSection(csp);
287
288         osi_assert(lockp->flags & OSI_LOCKFLAG_EXCL);
289         
290         ap = osi_FindActiveInfo(&realp->qi);
291         osi_assert(ap != NULL);
292         osi_RemoveActiveInfo(&realp->qi, ap);
293         realp->lockedCount++;
294         realp->lockedTime = LargeIntegerAdd(realp->lockedTime, ap->startTime);
295         osi_FreeActiveInfo(ap);
296
297         lockp->flags &= ~OSI_LOCKFLAG_EXCL;
298         if (!osi_TEmpty(&realp->turn)) {
299                 osi_TSignalForMLs(&realp->turn, 0, csp);
300         }
301         else {
302                 /* and finally release the big lock */
303                 LeaveCriticalSection(csp);
304         }
305 }
306
307 static int lock_TryReadStat(struct osi_rwlock *lockp)
308 {
309         long i;
310         osi_rwlockStat_t *realp; 
311         CRITICAL_SECTION *csp;
312
313         realp = (osi_rwlockStat_t *) lockp->d.privateDatap;
314
315         /* otherwise we're the fast base type */
316         csp = &osi_statAtomicCS[lockp->atomicIndex];
317         EnterCriticalSection(csp);
318
319         /* here we have the fast lock, so see if we can obtain the real lock */
320         if (lockp->waiters > 0 || (lockp->flags & OSI_LOCKFLAG_EXCL)) {
321                 i = 0;
322         }
323         else {
324                 /* if we're here, all clear to set the lock */
325                 lockp->readers++;
326                 i = 1;
327         }
328
329         /* start tracking lock holding stats */
330         if (i) osi_QueueActiveInfo(&realp->qi, OSI_ACTIVEFLAGS_READER);
331
332         LeaveCriticalSection(csp);
333
334         return i;
335 }
336
337
338 static int lock_TryWriteStat(struct osi_rwlock *lockp)
339 {
340         long i;
341         osi_rwlockStat_t *realp;
342         CRITICAL_SECTION *csp;
343
344         realp = (osi_rwlockStat_t *) lockp->d.privateDatap;
345
346         /* otherwise we're the fast base type */
347         csp = &osi_statAtomicCS[lockp->atomicIndex];
348         EnterCriticalSection(csp);
349
350         /* here we have the fast lock, so see if we can obtain the real lock */
351         if ((lockp->waiters > 0) || (lockp->flags & OSI_LOCKFLAG_EXCL)
352                 || (lockp->readers > 0)) {
353                 i = 0;
354         }
355         else {
356                 /* if we're here, all clear to set the lock */
357                 lockp->flags |= OSI_LOCKFLAG_EXCL;
358                 i = 1;
359         }
360
361         /* start tracking lock holding stats */
362         if (i) osi_QueueActiveInfo(&realp->qi, OSI_ACTIVEFLAGS_WRITER);
363
364         LeaveCriticalSection(csp);
365
366         return i;
367 }
368
369
370 static int lock_GetRWLockStateStat(struct osi_rwlock *lockp)
371 {
372         long i;
373         osi_rwlockStat_t *realp;
374         CRITICAL_SECTION *csp;
375
376         realp = (osi_rwlockStat_t *) lockp->d.privateDatap;
377
378         /* otherwise we're the fast base type */
379         csp = &osi_statAtomicCS[lockp->atomicIndex];
380         EnterCriticalSection(csp);
381
382         i = 0;
383         if (lockp->flags & OSI_LOCKFLAG_EXCL) {
384                 i |= OSI_RWLOCK_WRITEHELD;
385         }
386         if (lockp->readers) {
387                 i |= OSI_RWLOCK_READHELD;
388         }
389
390         LeaveCriticalSection(csp);
391
392         return i;
393 }
394
395
396 static int lock_GetMutexStateStat(struct osi_mutex *lockp) {
397         long i;
398         osi_mutexStat_t *realp;
399         CRITICAL_SECTION *csp;
400
401         realp = (osi_mutexStat_t *) lockp->d.privateDatap;
402
403         /* otherwise we're the fast base type */
404         csp = &osi_statAtomicCS[lockp->atomicIndex];
405         EnterCriticalSection(csp);
406
407         /* here we have the fast lock, so see if we can obtain the real lock */
408         i = 0;
409         if (lockp->flags & OSI_LOCKFLAG_EXCL) {
410                 i |= OSI_MUTEX_HELD;
411         }
412
413         LeaveCriticalSection(csp);
414
415         return i;
416 }
417
418 static int lock_TryMutexStat(struct osi_mutex *lockp) {
419         long i;
420         osi_mutexStat_t *realp;
421         CRITICAL_SECTION *csp;
422
423         realp = (osi_mutexStat_t *) lockp->d.privateDatap;
424
425         /* otherwise we're the fast base type */
426         csp = &osi_statAtomicCS[lockp->atomicIndex];
427         EnterCriticalSection(csp);
428
429         /* here we have the fast lock, so see if we can obtain the real lock */
430         if ((lockp->waiters > 0) || (lockp->flags & OSI_LOCKFLAG_EXCL)) {
431                 i = 0;
432         }
433         else {
434                 /* if we're here, all clear to set the lock */
435                 lockp->flags |= OSI_LOCKFLAG_EXCL;
436                 i = 1;
437         }
438
439         if (i) osi_QueueActiveInfo(&realp->qi, 0);
440
441         LeaveCriticalSection(csp);
442
443         return i;
444 }
445
446 static void osi_SleepRStat(long sleepVal, struct osi_rwlock *lockp)
447 {
448         osi_rwlockStat_t *realp;
449         osi_activeInfo_t *ap;
450         CRITICAL_SECTION *csp;
451
452         realp = (osi_rwlockStat_t *) lockp->d.privateDatap;
453
454         /* otherwise we're the fast base type */
455         csp = &osi_statAtomicCS[lockp->atomicIndex];
456         EnterCriticalSection(csp);
457
458         osi_assert(lockp->readers > 0);
459         
460         if (--lockp->readers == 0 && !osi_TEmpty(&realp->turn)) {
461                 osi_TSignalForMLs(&realp->turn, 0, NULL);
462         }
463
464         /* now merge in lock hold stats */
465         ap = osi_FindActiveInfo(&realp->qi);
466         osi_assert(ap != NULL);
467         osi_RemoveActiveInfo(&realp->qi, ap);
468         realp->writeLockedCount++;
469         realp->writeLockedTime = LargeIntegerAdd(realp->writeLockedTime, ap->startTime);
470         osi_FreeActiveInfo(ap);
471
472         /* now call into scheduler to sleep atomically with releasing spin lock */
473         osi_SleepSpin(sleepVal, csp);
474 }
475
476 static void osi_SleepWStat(long sleepVal, struct osi_rwlock *lockp)
477 {
478         osi_activeInfo_t *ap;
479         osi_rwlockStat_t *realp;
480         CRITICAL_SECTION *csp;
481
482         realp = (osi_rwlockStat_t *) lockp->d.privateDatap;
483
484         /* otherwise we're the fast base type */
485         csp = &osi_statAtomicCS[lockp->atomicIndex];
486         EnterCriticalSection(csp);
487
488         osi_assert(lockp->flags & OSI_LOCKFLAG_EXCL);
489         
490         lockp->flags &= ~OSI_LOCKFLAG_EXCL;
491         if (!osi_TEmpty(&realp->turn)) {
492                 osi_TSignalForMLs(&realp->turn, 0, NULL);
493         }
494
495         /* now merge in lock hold stats */
496         ap = osi_FindActiveInfo(&realp->qi);
497         osi_assert(ap != NULL);
498         osi_RemoveActiveInfo(&realp->qi, ap);
499         realp->readLockedCount++;
500         realp->readLockedTime = LargeIntegerAdd(realp->readLockedTime, ap->startTime);
501         osi_FreeActiveInfo(ap);
502
503         /* and finally release the big lock */
504         osi_SleepSpin(sleepVal, csp);
505 }
506
507 static void osi_SleepMStat(long sleepVal, struct osi_mutex *lockp)
508 {
509         osi_mutexStat_t *realp;
510         osi_activeInfo_t *ap;
511         CRITICAL_SECTION *csp;
512
513         realp = (osi_mutexStat_t *) lockp->d.privateDatap;
514
515         /* otherwise we're the fast base type */
516         csp = &osi_statAtomicCS[lockp->atomicIndex];
517         EnterCriticalSection(csp);
518
519         osi_assert(lockp->flags & OSI_LOCKFLAG_EXCL);
520         
521         lockp->flags &= ~OSI_LOCKFLAG_EXCL;
522         if (!osi_TEmpty(&realp->turn)) {
523                 osi_TSignalForMLs(&realp->turn, 0, NULL);
524         }
525
526         /* now merge in lock hold stats */
527         ap = osi_FindActiveInfo(&realp->qi);
528         osi_assert(ap != NULL);
529         osi_RemoveActiveInfo(&realp->qi, ap);
530         realp->lockedCount++;
531         realp->lockedTime = LargeIntegerAdd(realp->lockedTime, ap->startTime);
532         osi_FreeActiveInfo(ap);
533
534         /* and finally release the big lock */
535         osi_SleepSpin(sleepVal, csp);
536 }
537
538 /* this is a function that release a ref count, but we give it a different
539  * name than release to avoid confusion with all of the releases here.
540  * Must be called holding the osi_statFDCS lock.
541  */
542 static void lock_DecrMutexStat(osi_mutexStat_t *mp)
543 {
544         if (--mp->refCount <= 0 && (mp->states & OSI_STATL_DELETED)) {
545                 osi_QRemove(&osi_allMutexes, &mp->q);
546                 free((void *)mp);
547         }
548 }
549
550 /* Must be called holding the osi_statFDCS lock. */
551 static void lock_DecrRWLockStat(osi_rwlockStat_t *rwp)
552 {
553         if (--rwp->refCount <= 0 && (rwp->states & OSI_STATL_DELETED)) {
554                 osi_QRemove(&osi_allRWLocks, &rwp->q);
555                 free((void *)rwp);
556         }
557 }
558
559 static void lock_FinalizeMutexStat(osi_mutex_t *lockp)
560 {
561         osi_mutexStat_t *realp;
562         
563         /* pull out the real pointer */
564         realp = (osi_mutexStat_t *) lockp->d.privateDatap;
565         
566         /* remove from the queues, and free */
567         EnterCriticalSection(&osi_statFDCS);
568         if (realp->refCount <= 0) {
569                 osi_QRemove(&osi_allMutexes, &realp->q);
570                 free((void *) realp);
571         }
572         else realp->states |= OSI_STATL_DELETED;
573         LeaveCriticalSection(&osi_statFDCS);
574 }
575
576 static void lock_FinalizeRWLockStat(osi_rwlock_t *lockp)
577 {
578         osi_rwlockStat_t *realp;
579         
580         /* pull out the real pointer */
581         realp = (osi_rwlockStat_t *) lockp->d.privateDatap;
582         
583         /* remove from the queues, and free */
584         EnterCriticalSection(&osi_statFDCS);
585         if (realp->refCount <= 0) {
586                 osi_QRemove(&osi_allRWLocks, &realp->q);
587                 free((void *) realp);
588         }
589         else realp->states |= OSI_STATL_DELETED;
590         LeaveCriticalSection(&osi_statFDCS);
591 }
592
593 void lock_InitializeRWLockStat(osi_rwlock_t *lockp, char *namep)
594 {
595         osi_rwlockStat_t *realp;
596         
597         realp = (osi_rwlockStat_t *) malloc(sizeof(*realp));
598         lockp->d.privateDatap = (void *) realp;
599         lockp->type = osi_statType;
600         lockp->flags = 0;
601         lockp->readers = 0;
602         lockp->atomicIndex = osi_MUTEXHASH(lockp);
603         memset(realp, 0, sizeof(*realp));
604         osi_TInit(&realp->turn);
605         realp->qi.namep = namep;
606         realp->qi.backp = lockp;
607         EnterCriticalSection(&osi_statFDCS);
608         osi_QAdd(&osi_allRWLocks, &realp->q);
609         LeaveCriticalSection(&osi_statFDCS);
610 }
611
612 void lock_InitializeMutexStat(osi_mutex_t *lockp, char *namep)
613 {
614         osi_mutexStat_t *realp;
615         
616         realp = (osi_mutexStat_t *) malloc(sizeof(*realp));
617         lockp->d.privateDatap = (void *) realp;
618         lockp->type = osi_statType;
619         lockp->flags = 0;
620         lockp->atomicIndex = osi_MUTEXHASH(lockp);
621         memset(realp, 0, sizeof(*realp));
622         osi_TInit(&realp->turn);
623         realp->qi.namep = namep;
624         realp->qi.backp = lockp;
625         EnterCriticalSection(&osi_statFDCS);
626         osi_QAdd(&osi_allMutexes, &realp->q);
627         LeaveCriticalSection(&osi_statFDCS);
628 }
629
630 static void osi_FreeActiveInfo(osi_activeInfo_t *ap)
631 {
632         EnterCriticalSection(&osi_activeInfoAllocCS);
633         ap->q.nextp = (osi_queue_t *) osi_activeInfoFreeListp;
634         osi_activeInfoFreeListp = ap;
635         LeaveCriticalSection(&osi_activeInfoAllocCS);
636 }
637
638 static osi_activeInfo_t *osi_AllocActiveInfo()
639 {
640         osi_activeInfo_t *ap;
641
642         EnterCriticalSection(&osi_activeInfoAllocCS);
643         if (!(ap = osi_activeInfoFreeListp)) {
644                 ap = (osi_activeInfo_t *) malloc(sizeof(osi_activeInfo_t));
645         }
646         else {
647                 osi_activeInfoFreeListp = (osi_activeInfo_t *) ap->q.nextp;
648         }
649         LeaveCriticalSection(&osi_activeInfoAllocCS);
650
651         return ap;
652 }
653
654 static osi_activeInfo_t *osi_QueueActiveInfo(osi_qiStat_t *qp, int flags)
655 {
656         osi_activeInfo_t *ap;
657         osi_queue_t **qpp = (osi_queue_t **) &qp->activeListp;
658         char *whatp;
659
660         ap = osi_AllocActiveInfo();
661         ap->flags = flags;
662         ap->startTime.LowPart = GetCurrentTime();
663         ap->startTime.HighPart = 0;
664         ap->tid = GetCurrentThreadId();
665         osi_QAdd(qpp, &ap->q);
666         if (osi_statLogp && (flags & OSI_ACTIVEFLAGS_WAITER)) {
667                 if (flags & OSI_ACTIVEFLAGS_READER)
668                         whatp = "read lock";
669                 else if (flags & OSI_ACTIVEFLAGS_WRITER)
670                         whatp = "write lock";
671                 else whatp = "mutex";
672                 osi_Log2(osi_statLogp, "Blocking on %s on %s", whatp, qp->namep);
673         }
674         return ap;
675 }
676
677 static void osi_RemoveActiveInfo(osi_qiStat_t *qp, osi_activeInfo_t *ap)
678 {
679         unsigned long now;
680         osi_queue_t **qpp = (osi_queue_t **) &qp->activeListp;
681         long flags;
682         char *whatp;
683
684         now = GetCurrentTime();
685         osi_QRemove(qpp, &ap->q);
686         flags = ap->flags;
687         ap->startTime.LowPart = now - ap->startTime.LowPart;
688
689         if (osi_statLogp && (flags & OSI_ACTIVEFLAGS_WAITER)) {
690                 if (flags & OSI_ACTIVEFLAGS_READER)
691                         whatp = "read lock";
692                 else if (flags & OSI_ACTIVEFLAGS_WRITER)
693                         whatp = "write lock";
694                 else whatp = "mutex";
695                 osi_Log2(osi_statLogp, "Finally obtained %s on %s", whatp, qp->namep);
696         }
697         else {
698                 /* releasing a lock or mutex */
699                 if (osi_statWatchProcp && ap->startTime.LowPart > osi_statWatchMS) {
700                         (*osi_statWatchProcp)(osi_statWatchRockp, ap->startTime.LowPart,
701                                 qp->backp);
702                 }
703         }
704 }
705
706 static osi_activeInfo_t *osi_FindActiveInfo(osi_qiStat_t *qp)
707 {
708         unsigned long tid;
709         osi_activeInfo_t *ap;
710         osi_queue_t *tqp;
711         osi_queue_t **qpp = (osi_queue_t **) &qp->activeListp;
712
713         ap = NULL;
714         tid = GetCurrentThreadId();
715         if (*qpp != NULL) {
716                 for(tqp = *qpp; tqp; tqp = tqp->nextp) {
717                         ap = (osi_activeInfo_t *) tqp;
718                         if (ap->tid == tid) break;
719                 }
720         }
721         return ap;
722 }
723
724 static osi_lockOps_t osi_statOps = {
725         lock_ObtainReadStat,
726         lock_ObtainWriteStat,
727         lock_ReleaseReadStat,
728         lock_ReleaseWriteStat,
729         lock_ObtainMutexStat,
730         lock_ReleaseMutexStat,
731         lock_TryReadStat,
732         lock_TryWriteStat,
733         lock_TryMutexStat,
734         osi_SleepRStat,
735         osi_SleepWStat,
736         osi_SleepMStat,
737         lock_InitializeMutexStat,
738         lock_InitializeRWLockStat,
739         lock_FinalizeMutexStat,
740         lock_FinalizeRWLockStat,
741         lock_ConvertWToRStat,
742         lock_GetRWLockStateStat,
743         lock_GetMutexStateStat
744 };
745
746 long osi_StatFDCreate(osi_fdType_t *typep, osi_fd_t **fdpp)
747 {
748         osi_statFD_t *fdp;
749         osi_mutexStat_t *mp;
750         osi_rwlockStat_t *rwp;
751
752         fdp = (osi_statFD_t *) malloc(sizeof(*fdp));
753         EnterCriticalSection(&osi_statFDCS);
754         if (osi_allMutexes) {
755                 fdp->curp = osi_allMutexes;
756                 mp = (osi_mutexStat_t *) fdp->curp;
757                 mp->refCount++;
758                 fdp->which = 0;
759         }
760         else if (osi_allRWLocks) {
761                 fdp->curp = osi_allRWLocks;
762                 rwp = (osi_rwlockStat_t *) fdp->curp;
763                 rwp->refCount++;
764                 fdp->which = 1;
765         }
766         else fdp->curp = NULL;
767         LeaveCriticalSection(&osi_statFDCS);
768
769         *fdpp = &fdp->fd;
770
771         return 0;
772 }
773
774 long osi_StatFDGetInfo(osi_fd_t *ifdp, osi_remGetInfoParms_t *parmsp)
775 {
776         osi_mutexStat_t *mp;
777         osi_statFD_t *fdp;
778         osi_rwlockStat_t *rwp;
779         osi_queue_t *qp;
780         osi_mutex_t *backMutexp;
781         osi_rwlock_t *backRWLockp;
782
783         /* initialize out structure */
784         parmsp->icount = 0;
785         parmsp->scount = 0;
786
787         fdp = (osi_statFD_t *) ifdp;
788         qp = fdp->curp;
789
790         /* we're done if curp is null */
791         if (qp == NULL) return OSI_DBRPC_EOF;
792
793         /* copy out statistics */
794         if (fdp->which == 0) {
795                 /* this is a mutex */
796                 mp = (osi_mutexStat_t *) qp;
797
798                 memset((void *) parmsp, 0, sizeof(*parmsp));
799                 backMutexp = mp->qi.backp;
800                 parmsp->idata[0] = (long) backMutexp;
801                 parmsp->idata[1] = (backMutexp->flags & OSI_LOCKFLAG_EXCL)? 1 : 0;
802                 /* reader count [2] is 0 */
803                 parmsp->idata[3] = (backMutexp->waiters > 0)? 1 : 0;
804                 parmsp->idata[4] = mp->lockedTime.LowPart;
805                 parmsp->idata[5] = mp->lockedCount;
806                 parmsp->idata[6] = mp->blockedTime.LowPart;
807                 parmsp->idata[7] = mp->blockedCount;
808                 strcpy(parmsp->sdata[0], mp->qi.namep);
809                 parmsp->icount = 8;
810                 parmsp->scount = 1;
811         }
812         else if (fdp->which == 1) {
813                 /* rwlock */
814                 rwp = (osi_rwlockStat_t *) qp;
815
816                 memset((void *) parmsp, 0, sizeof(*parmsp));
817                 backRWLockp = rwp->qi.backp;
818                 parmsp->idata[0] = (long) backRWLockp;
819                 parmsp->idata[1] = (backRWLockp->flags & OSI_LOCKFLAG_EXCL)? 1 : 0;
820                 parmsp->idata[2] = backRWLockp->readers;
821                 parmsp->idata[3] = (backRWLockp->waiters > 0)? 1 : 0;
822                 parmsp->idata[4] = rwp->writeLockedTime.LowPart;
823                 parmsp->idata[5] = rwp->writeLockedCount;
824                 parmsp->idata[6] = rwp->writeBlockedTime.LowPart;
825                 parmsp->idata[7] = rwp->writeBlockedCount;
826                 parmsp->idata[8] = rwp->readLockedTime.LowPart;
827                 parmsp->idata[9] = rwp->readLockedCount;
828                 parmsp->idata[10] = rwp->readBlockedTime.LowPart;
829                 parmsp->idata[11] = rwp->readBlockedCount;
830                 strcpy(parmsp->sdata[0], rwp->qi.namep);
831                 parmsp->scount = 1;
832                 parmsp->icount = 12;
833         }
834
835         /* advance to next position */
836         EnterCriticalSection(&osi_statFDCS);
837         if (qp != NULL) {
838                 if (fdp->which == 0) {
839                         mp = (osi_mutexStat_t *) qp;
840                         lock_DecrMutexStat(mp);
841                 }
842                 else if (fdp->which == 1) {
843                         rwp = (osi_rwlockStat_t *) qp;
844                         lock_DecrRWLockStat(rwp);
845                 }
846                 qp = osi_QNext(qp);
847         }
848         if (qp == NULL && fdp->which == 0) {
849                 fdp->which = 1;
850                 if (osi_allRWLocks) qp = osi_allRWLocks;
851                 else qp = NULL;
852         }
853         fdp->curp = qp;
854         if (qp != NULL) {
855                 if (fdp->which == 0) {
856                         mp = (osi_mutexStat_t *) qp;
857                         mp->refCount++;
858                 }
859                 else if (fdp->which == 1) {
860                         rwp = (osi_rwlockStat_t *) qp;
861                         rwp->refCount++;
862                 }
863         }
864         LeaveCriticalSection(&osi_statFDCS);
865
866         return 0;
867 }
868
869 long osi_StatFDClose(osi_fd_t *ifdp)
870 {
871         free((void *)ifdp);
872         return 0;
873 }
874
875 osi_fdOps_t osi_statFDOps = {
876         osi_StatFDCreate,
877         osi_StatFDGetInfo,
878         osi_StatFDClose
879 };
880
881 void osi_StatInit()
882 {
883         osi_fdType_t *typep;
884         int i;
885
886         /* initialize the stat package */
887         InitializeCriticalSection(&osi_activeInfoAllocCS);
888         InitializeCriticalSection(&osi_statFDCS);
889
890         for(i=0; i<OSI_MUTEXHASHSIZE; i++)
891                 InitializeCriticalSection(&osi_statAtomicCS[i]);
892
893         /* add stat ops to dynamic registry */
894         osi_LockTypeAdd(&osi_statOps, "stat", &osi_statType);
895
896         /* add debugging info and file descriptor support */
897         typep = osi_RegisterFDType("lock", &osi_statFDOps, NULL);
898         if (typep) {
899                 /* add formatting info */
900                 osi_AddFDFormatInfo(typep, OSI_DBRPC_REGIONINT, 0,
901                         "Lock address", OSI_DBRPC_HEX);
902                 osi_AddFDFormatInfo(typep, OSI_DBRPC_REGIONINT, 1,
903                         "Writer count", 0);
904                 osi_AddFDFormatInfo(typep, OSI_DBRPC_REGIONINT, 2,
905                         "Reader count", 0);
906                 osi_AddFDFormatInfo(typep, OSI_DBRPC_REGIONINT, 3,
907                         "Are waiters", 0);
908                 osi_AddFDFormatInfo(typep, OSI_DBRPC_REGIONINT, 4,
909                         "Write-locked time", 0);
910                 osi_AddFDFormatInfo(typep, OSI_DBRPC_REGIONINT, 5,
911                         "Write-locked count", 0);
912                 osi_AddFDFormatInfo(typep, OSI_DBRPC_REGIONINT, 6,
913                         "Write-blocked time", 0);
914                 osi_AddFDFormatInfo(typep, OSI_DBRPC_REGIONINT, 7,
915                         "Write-blocked count", 0);
916                 osi_AddFDFormatInfo(typep, OSI_DBRPC_REGIONINT, 8,
917                         "Read-locked time", 0);
918                 osi_AddFDFormatInfo(typep, OSI_DBRPC_REGIONINT, 9,
919                         "Read-locked count", 0);
920                 osi_AddFDFormatInfo(typep, OSI_DBRPC_REGIONINT, 10,
921                         "Read-blocked time", 0);
922                 osi_AddFDFormatInfo(typep, OSI_DBRPC_REGIONINT, 11,
923                         "Read-blocked count", 0);
924
925                 /* and the string */
926                 osi_AddFDFormatInfo(typep,  OSI_DBRPC_REGIONSTRING, 0,
927                         "Lock name", 0);
928         }
929 }
930
931 /* set lock watching stuff */
932 void osi_SetWatchProc(long ms, osi_watchProc_t *procp, void *rockp)
933 {
934         osi_statWatchProcp = procp;
935         osi_statWatchRockp = rockp;
936         osi_statWatchMS = ms;
937 }