0526144020ff4ae9bc2604376ecefc2eafeac559
[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_ConvertRToWStat(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->readLockedCount++;
226         realp->readLockedTime = LargeIntegerAdd(realp->readLockedTime, ap->startTime);
227         osi_FreeActiveInfo(ap);
228         
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, csp);
238             lockp->waiters--;
239             osi_assert((lockp->flags & OSI_LOCKFLAG_EXCL) && lockp->readers == 0);
240
241             /*  we have some timer info about the last sleep operation
242              * that we should merge in under the spin lock.
243              */
244
245             /* remove from queue and turn time to incremental time */
246             osi_RemoveActiveInfo(&realp->qi, ap);
247                 
248             /* add in increment to statistics */
249             realp->writeBlockedCount++;
250             realp->writeBlockedTime = LargeIntegerAdd(realp->writeBlockedTime,
251                                                    ap->startTime);
252             osi_FreeActiveInfo(ap);
253         }
254
255         osi_QueueActiveInfo(&realp->qi, OSI_ACTIVEFLAGS_WRITER);
256         LeaveCriticalSection(csp);
257 }
258
259 static void lock_ReleaseWriteStat(osi_rwlock_t *lockp)
260 {
261         osi_activeInfo_t *ap;
262         osi_rwlockStat_t *realp;
263         CRITICAL_SECTION *csp;
264
265         realp = (osi_rwlockStat_t *)lockp->d.privateDatap;
266
267         /* otherwise we're the fast base type */
268         csp = &osi_statAtomicCS[lockp->atomicIndex];
269         EnterCriticalSection(csp);
270
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);
278         
279         lockp->flags &= ~OSI_LOCKFLAG_EXCL;
280         if (!osi_TEmpty(&realp->turn)) {
281                 osi_TSignalForMLs(&realp->turn, 0, csp);
282         }
283         else {
284                 /* and finally release the big lock */
285                 LeaveCriticalSection(csp);
286         }
287 }
288
289 static void lock_ObtainMutexStat(struct osi_mutex *lockp)
290 {
291         osi_activeInfo_t *ap;
292         osi_mutexStat_t *realp;
293         CRITICAL_SECTION *csp;
294
295         ap = NULL;
296         realp = (osi_mutexStat_t *) lockp->d.privateDatap;
297
298         csp = &osi_statAtomicCS[lockp->atomicIndex];
299         EnterCriticalSection(csp);
300
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, csp);
306                 lockp->waiters--;
307                 osi_assert(lockp->flags & OSI_LOCKFLAG_EXCL);
308         }
309         else {
310                 /* if we're here, all clear to set the lock */
311                 lockp->flags |= OSI_LOCKFLAG_EXCL;
312         }
313
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);
320         }
321
322         /* start tracking this call */
323         osi_QueueActiveInfo(&realp->qi, OSI_ACTIVEFLAGS_WRITER);
324
325         LeaveCriticalSection(csp);
326 }
327
328 static void lock_ReleaseMutexStat(struct osi_mutex *lockp)
329 {
330         osi_activeInfo_t *ap;
331         osi_mutexStat_t *realp;
332         CRITICAL_SECTION *csp;
333
334         realp = (osi_mutexStat_t *)lockp->d.privateDatap;
335
336         csp = &osi_statAtomicCS[lockp->atomicIndex];
337         EnterCriticalSection(csp);
338
339         osi_assert(lockp->flags & OSI_LOCKFLAG_EXCL);
340         
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);
347
348         lockp->flags &= ~OSI_LOCKFLAG_EXCL;
349         if (!osi_TEmpty(&realp->turn)) {
350                 osi_TSignalForMLs(&realp->turn, 0, csp);
351         }
352         else {
353                 /* and finally release the big lock */
354                 LeaveCriticalSection(csp);
355         }
356 }
357
358 static int lock_TryReadStat(struct osi_rwlock *lockp)
359 {
360         long i;
361         osi_rwlockStat_t *realp; 
362         CRITICAL_SECTION *csp;
363
364         realp = (osi_rwlockStat_t *) lockp->d.privateDatap;
365
366         /* otherwise we're the fast base type */
367         csp = &osi_statAtomicCS[lockp->atomicIndex];
368         EnterCriticalSection(csp);
369
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;
373         }
374         else {
375                 /* if we're here, all clear to set the lock */
376                 lockp->readers++;
377                 i = 1;
378         }
379
380         /* start tracking lock holding stats */
381         if (i) osi_QueueActiveInfo(&realp->qi, OSI_ACTIVEFLAGS_READER);
382
383         LeaveCriticalSection(csp);
384
385         return i;
386 }
387
388
389 static int lock_TryWriteStat(struct osi_rwlock *lockp)
390 {
391         long i;
392         osi_rwlockStat_t *realp;
393         CRITICAL_SECTION *csp;
394
395         realp = (osi_rwlockStat_t *) lockp->d.privateDatap;
396
397         /* otherwise we're the fast base type */
398         csp = &osi_statAtomicCS[lockp->atomicIndex];
399         EnterCriticalSection(csp);
400
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;
405         }
406         else {
407                 /* if we're here, all clear to set the lock */
408                 lockp->flags |= OSI_LOCKFLAG_EXCL;
409                 i = 1;
410         }
411
412         /* start tracking lock holding stats */
413         if (i) osi_QueueActiveInfo(&realp->qi, OSI_ACTIVEFLAGS_WRITER);
414
415         LeaveCriticalSection(csp);
416
417         return i;
418 }
419
420
421 static int lock_GetRWLockStateStat(struct osi_rwlock *lockp)
422 {
423         long i;
424         osi_rwlockStat_t *realp;
425         CRITICAL_SECTION *csp;
426
427         realp = (osi_rwlockStat_t *) lockp->d.privateDatap;
428
429         /* otherwise we're the fast base type */
430         csp = &osi_statAtomicCS[lockp->atomicIndex];
431         EnterCriticalSection(csp);
432
433         i = 0;
434         if (lockp->flags & OSI_LOCKFLAG_EXCL) {
435                 i |= OSI_RWLOCK_WRITEHELD;
436         }
437         if (lockp->readers) {
438                 i |= OSI_RWLOCK_READHELD;
439         }
440
441         LeaveCriticalSection(csp);
442
443         return i;
444 }
445
446
447 static int lock_GetMutexStateStat(struct osi_mutex *lockp) {
448         long i;
449         osi_mutexStat_t *realp;
450         CRITICAL_SECTION *csp;
451
452         realp = (osi_mutexStat_t *) lockp->d.privateDatap;
453
454         /* otherwise we're the fast base type */
455         csp = &osi_statAtomicCS[lockp->atomicIndex];
456         EnterCriticalSection(csp);
457
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;
462         }
463
464         LeaveCriticalSection(csp);
465
466         return i;
467 }
468
469 static int lock_TryMutexStat(struct osi_mutex *lockp) {
470         long i;
471         osi_mutexStat_t *realp;
472         CRITICAL_SECTION *csp;
473
474         realp = (osi_mutexStat_t *) lockp->d.privateDatap;
475
476         /* otherwise we're the fast base type */
477         csp = &osi_statAtomicCS[lockp->atomicIndex];
478         EnterCriticalSection(csp);
479
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;
483         }
484         else {
485                 /* if we're here, all clear to set the lock */
486                 lockp->flags |= OSI_LOCKFLAG_EXCL;
487                 i = 1;
488         }
489
490         if (i) osi_QueueActiveInfo(&realp->qi, 0);
491
492         LeaveCriticalSection(csp);
493
494         return i;
495 }
496
497 static void osi_SleepRStat(LONG_PTR sleepVal, struct osi_rwlock *lockp)
498 {
499         osi_rwlockStat_t *realp;
500         osi_activeInfo_t *ap;
501         CRITICAL_SECTION *csp;
502
503         realp = (osi_rwlockStat_t *) lockp->d.privateDatap;
504
505         /* otherwise we're the fast base type */
506         csp = &osi_statAtomicCS[lockp->atomicIndex];
507         EnterCriticalSection(csp);
508
509         osi_assert(lockp->readers > 0);
510         
511         if (--lockp->readers == 0 && !osi_TEmpty(&realp->turn)) {
512                 osi_TSignalForMLs(&realp->turn, 0, NULL);
513         }
514
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);
522
523         /* now call into scheduler to sleep atomically with releasing spin lock */
524         osi_SleepSpin(sleepVal, csp);
525 }
526
527 static void osi_SleepWStat(LONG_PTR sleepVal, struct osi_rwlock *lockp)
528 {
529         osi_activeInfo_t *ap;
530         osi_rwlockStat_t *realp;
531         CRITICAL_SECTION *csp;
532
533         realp = (osi_rwlockStat_t *) lockp->d.privateDatap;
534
535         /* otherwise we're the fast base type */
536         csp = &osi_statAtomicCS[lockp->atomicIndex];
537         EnterCriticalSection(csp);
538
539         osi_assert(lockp->flags & OSI_LOCKFLAG_EXCL);
540         
541         lockp->flags &= ~OSI_LOCKFLAG_EXCL;
542         if (!osi_TEmpty(&realp->turn)) {
543                 osi_TSignalForMLs(&realp->turn, 0, NULL);
544         }
545
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);
553
554         /* and finally release the big lock */
555         osi_SleepSpin(sleepVal, csp);
556 }
557
558 static void osi_SleepMStat(LONG_PTR sleepVal, struct osi_mutex *lockp)
559 {
560         osi_mutexStat_t *realp;
561         osi_activeInfo_t *ap;
562         CRITICAL_SECTION *csp;
563
564         realp = (osi_mutexStat_t *) lockp->d.privateDatap;
565
566         /* otherwise we're the fast base type */
567         csp = &osi_statAtomicCS[lockp->atomicIndex];
568         EnterCriticalSection(csp);
569
570         osi_assert(lockp->flags & OSI_LOCKFLAG_EXCL);
571         
572         lockp->flags &= ~OSI_LOCKFLAG_EXCL;
573         if (!osi_TEmpty(&realp->turn)) {
574                 osi_TSignalForMLs(&realp->turn, 0, NULL);
575         }
576
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);
584
585         /* and finally release the big lock */
586         osi_SleepSpin(sleepVal, csp);
587 }
588
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.
592  */
593 static void lock_DecrMutexStat(osi_mutexStat_t *mp)
594 {
595         if (--mp->refCount <= 0 && (mp->states & OSI_STATL_DELETED)) {
596                 osi_QRemove(&osi_allMutexes, &mp->q);
597                 free((void *)mp);
598         }
599 }
600
601 /* Must be called holding the osi_statFDCS lock. */
602 static void lock_DecrRWLockStat(osi_rwlockStat_t *rwp)
603 {
604         if (--rwp->refCount <= 0 && (rwp->states & OSI_STATL_DELETED)) {
605                 osi_QRemove(&osi_allRWLocks, &rwp->q);
606                 free((void *)rwp);
607         }
608 }
609
610 static void lock_FinalizeMutexStat(osi_mutex_t *lockp)
611 {
612         osi_mutexStat_t *realp;
613         
614         /* pull out the real pointer */
615         realp = (osi_mutexStat_t *) lockp->d.privateDatap;
616         
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);
622         }
623         else realp->states |= OSI_STATL_DELETED;
624         LeaveCriticalSection(&osi_statFDCS);
625 }
626
627 static void lock_FinalizeRWLockStat(osi_rwlock_t *lockp)
628 {
629         osi_rwlockStat_t *realp;
630         
631         /* pull out the real pointer */
632         realp = (osi_rwlockStat_t *) lockp->d.privateDatap;
633         
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);
639         }
640         else realp->states |= OSI_STATL_DELETED;
641         LeaveCriticalSection(&osi_statFDCS);
642 }
643
644 void lock_InitializeRWLockStat(osi_rwlock_t *lockp, char *namep)
645 {
646         osi_rwlockStat_t *realp;
647         
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);
661 }
662
663 void lock_InitializeMutexStat(osi_mutex_t *lockp, char *namep)
664 {
665         osi_mutexStat_t *realp;
666         
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);
679 }
680
681 static void osi_FreeActiveInfo(osi_activeInfo_t *ap)
682 {
683         EnterCriticalSection(&osi_activeInfoAllocCS);
684         ap->q.nextp = (osi_queue_t *) osi_activeInfoFreeListp;
685         osi_activeInfoFreeListp = ap;
686         LeaveCriticalSection(&osi_activeInfoAllocCS);
687 }
688
689 static osi_activeInfo_t *osi_AllocActiveInfo()
690 {
691         osi_activeInfo_t *ap;
692
693         EnterCriticalSection(&osi_activeInfoAllocCS);
694         if (!(ap = osi_activeInfoFreeListp)) {
695                 ap = (osi_activeInfo_t *) malloc(sizeof(osi_activeInfo_t));
696         }
697         else {
698                 osi_activeInfoFreeListp = (osi_activeInfo_t *) ap->q.nextp;
699         }
700         LeaveCriticalSection(&osi_activeInfoAllocCS);
701
702         return ap;
703 }
704
705 static osi_activeInfo_t *osi_QueueActiveInfo(osi_qiStat_t *qp, int flags)
706 {
707         osi_activeInfo_t *ap;
708         osi_queue_t **qpp = (osi_queue_t **) &qp->activeListp;
709         char *whatp;
710
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);
724         }
725         return ap;
726 }
727
728 static void osi_RemoveActiveInfo(osi_qiStat_t *qp, osi_activeInfo_t *ap)
729 {
730         unsigned long now;
731         osi_queue_t **qpp = (osi_queue_t **) &qp->activeListp;
732         long flags;
733         char *whatp;
734
735         now = GetCurrentTime();
736         osi_QRemove(qpp, &ap->q);
737         flags = ap->flags;
738         ap->startTime.LowPart = now - ap->startTime.LowPart;
739
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);
747         }
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);
753                 }
754         }
755 }
756
757 static osi_activeInfo_t *osi_FindActiveInfo(osi_qiStat_t *qp)
758 {
759         unsigned long tid;
760         osi_activeInfo_t *ap;
761         osi_queue_t *tqp;
762         osi_queue_t **qpp = (osi_queue_t **) &qp->activeListp;
763
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;
770                 }
771         }
772         return ap;
773 }
774
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
796 };
797
798 long osi_StatFDCreate(osi_fdType_t *typep, osi_fd_t **fdpp)
799 {
800         osi_statFD_t *fdp;
801         osi_mutexStat_t *mp;
802         osi_rwlockStat_t *rwp;
803
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;
811         }
812         else if (osi_allRWLocks) {
813                 fdp->curp = osi_allRWLocks;
814                 rwp = (osi_rwlockStat_t *) fdp->curp;
815                 rwp->refCount++;
816                 fdp->which = 1;
817         }
818         else fdp->curp = NULL;
819         LeaveCriticalSection(&osi_statFDCS);
820
821         *fdpp = &fdp->fd;
822
823         return 0;
824 }
825
826 long osi_StatFDGetInfo(osi_fd_t *ifdp, osi_remGetInfoParms_t *parmsp)
827 {
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;
834
835         /* initialize out structure */
836         parmsp->icount = 0;
837         parmsp->scount = 0;
838
839         fdp = (osi_statFD_t *) ifdp;
840         qp = fdp->curp;
841
842         /* we're done if curp is null */
843         if (qp == NULL) return OSI_DBRPC_EOF;
844
845         /* copy out statistics */
846         if (fdp->which == 0) {
847                 /* this is a mutex */
848                 mp = (osi_mutexStat_t *) qp;
849
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;
863         }
864         else if (fdp->which == 1) {
865                 /* rwlock */
866                 rwp = (osi_rwlockStat_t *) qp;
867
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;
885         }
886
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);
893                 }
894                 else if (fdp->which == 1) {
895                         rwp = (osi_rwlockStat_t *) qp;
896                         lock_DecrRWLockStat(rwp);
897                 }
898                 qp = osi_QNext(qp);
899         }
900         if (qp == NULL && fdp->which == 0) {
901                 fdp->which = 1;
902                 if (osi_allRWLocks) qp = osi_allRWLocks;
903                 else qp = NULL;
904         }
905         fdp->curp = qp;
906         if (qp != NULL) {
907                 if (fdp->which == 0) {
908                         mp = (osi_mutexStat_t *) qp;
909                         mp->refCount++;
910                 }
911                 else if (fdp->which == 1) {
912                         rwp = (osi_rwlockStat_t *) qp;
913                         rwp->refCount++;
914                 }
915         }
916         LeaveCriticalSection(&osi_statFDCS);
917
918         return 0;
919 }
920
921 long osi_StatFDClose(osi_fd_t *ifdp)
922 {
923         free((void *)ifdp);
924         return 0;
925 }
926
927 osi_fdOps_t osi_statFDOps = {
928         osi_StatFDCreate,
929         osi_StatFDGetInfo,
930         osi_StatFDClose
931 };
932
933 void osi_StatInit()
934 {
935         osi_fdType_t *typep;
936         int i;
937
938         /* initialize the stat package */
939         InitializeCriticalSection(&osi_activeInfoAllocCS);
940         InitializeCriticalSection(&osi_statFDCS);
941
942         for(i=0; i<OSI_MUTEXHASHSIZE; i++)
943                 InitializeCriticalSection(&osi_statAtomicCS[i]);
944
945         /* add stat ops to dynamic registry */
946         osi_LockTypeAdd(&osi_statOps, "stat", &osi_statType);
947
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);
976
977                 /* and the string */
978                 osi_AddFDFormatInfo(typep,  OSI_DBRPC_REGIONSTRING, 0,
979                         "Lock name", 0);
980         }
981 }
982
983 /* set lock watching stuff */
984 void osi_SetWatchProc(long ms, osi_watchProc_t *procp, void *rockp)
985 {
986         osi_statWatchProcp = procp;
987         osi_statWatchRockp = rockp;
988         osi_statWatchMS = ms;
989 }