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