Windows: record history of read lock threads
authorJeffrey Altman <jaltman@your-file-system.com>
Sun, 21 Aug 2011 04:38:24 +0000 (00:38 -0400)
committerJeffrey Altman <jaltman@openafs.org>
Wed, 14 Sep 2011 01:28:42 +0000 (18:28 -0700)
Maintance an array of up to 32 reader threads that have
acquired a rwlock.  Use it for debugging when things go bad.

Change-Id: I2e2e781ff355f1452e991898dfb5b91c47db9e34
Reviewed-on: http://gerrit.openafs.org/5411
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Jeffrey Altman <jaltman@openafs.org>
Tested-by: Jeffrey Altman <jaltman@openafs.org>

src/WINNT/client_osi/osibasel.c
src/WINNT/client_osi/osibasel.h
src/WINNT/client_osi/osisleep.c
src/WINNT/client_osi/osisleep.h
src/WINNT/client_osi/osistatl.c
src/WINNT/client_osi/osistatl.h

index 40d1207..d6916e3 100644 (file)
@@ -177,17 +177,14 @@ void lock_ObtainWrite(osi_rwlock_t *lockp)
     if (lockp->waiters > 0 || (lockp->flags & OSI_LOCKFLAG_EXCL) ||
         (lockp->readers > 0)) {
         lockp->waiters++;
-        osi_TWait(&lockp->d.turn, OSI_SLEEPINFO_W4WRITE, &lockp->flags, csp);
+        osi_TWait(&lockp->d.turn, OSI_SLEEPINFO_W4WRITE, &lockp->flags, lockp->tid, csp);
         lockp->waiters--;
         osi_assert(lockp->readers == 0 && (lockp->flags & OSI_LOCKFLAG_EXCL));
-    }
-    else {
+    } else {
         /* if we're here, all clear to set the lock */
         lockp->flags |= OSI_LOCKFLAG_EXCL;
+        lockp->tid[0] = thrd_Current();
     }
-
-    lockp->tid = thrd_Current();
-
     LeaveCriticalSection(csp);
 
     if (lockOrderValidation) {
@@ -204,6 +201,7 @@ void lock_ObtainRead(osi_rwlock_t *lockp)
     CRITICAL_SECTION *csp;
     osi_queue_t * lockRefH, *lockRefT;
     osi_lock_ref_t *lockRefp;
+    DWORD tid = thrd_Current();
 
     if ((i=lockp->type) != 0) {
         if (i >= 0 && i < OSI_NLOCKTYPES)
@@ -223,18 +221,21 @@ void lock_ObtainRead(osi_rwlock_t *lockp)
     csp = &osi_baseAtomicCS[lockp->atomicIndex];
     EnterCriticalSection(csp);
 
+    for ( i=0; i < lockp->readers; i++ ) {
+        osi_assertx(lockp->tid[i] != tid, "OSI_RWLOCK_READHELD");
+    }
+
     /* here we have the fast lock, so see if we can obtain the real lock */
     if (lockp->waiters > 0 || (lockp->flags & OSI_LOCKFLAG_EXCL)) {
         lockp->waiters++;
-        osi_TWait(&lockp->d.turn, OSI_SLEEPINFO_W4READ, &lockp->readers, csp);
+        osi_TWait(&lockp->d.turn, OSI_SLEEPINFO_W4READ, &lockp->readers, lockp->tid, csp);
         lockp->waiters--;
         osi_assert(!(lockp->flags & OSI_LOCKFLAG_EXCL) && lockp->readers > 0);
-    }
-    else {
+    } else {
         /* if we're here, all clear to set the lock */
-        lockp->readers++;
+        if (++lockp->readers <= OSI_RWLOCK_THREADS)
+            lockp->tid[lockp->readers-1] = tid;
     }
-
     LeaveCriticalSection(csp);
 
     if (lockOrderValidation) {
@@ -251,6 +252,7 @@ void lock_ReleaseRead(osi_rwlock_t *lockp)
     CRITICAL_SECTION *csp;
     osi_queue_t * lockRefH, *lockRefT;
     osi_lock_ref_t *lockRefp;
+    DWORD tid = thrd_Current();
 
     if ((i = lockp->type) != 0) {
         if (i >= 0 && i < OSI_NLOCKTYPES)
@@ -283,6 +285,15 @@ void lock_ReleaseRead(osi_rwlock_t *lockp)
 
     osi_assertx(lockp->readers > 0, "read lock not held");
 
+    for ( i=0; i < lockp->readers; i++) {
+        if ( lockp->tid[i] == tid ) {
+            for ( ; i < lockp->readers - 1; i++)
+                lockp->tid[i] = lockp->tid[i+1];
+            lockp->tid[i] = 0;
+            break;
+        }
+    }
+
     /* releasing a read lock can allow readers or writers */
     if (--lockp->readers == 0 && !osi_TEmpty(&lockp->d.turn)) {
         osi_TSignalForMLs(&lockp->d.turn, 0, csp);
@@ -330,9 +341,9 @@ void lock_ReleaseWrite(osi_rwlock_t *lockp)
     EnterCriticalSection(csp);
 
     osi_assertx(lockp->flags & OSI_LOCKFLAG_EXCL, "write lock not held");
-    osi_assertx(lockp->tid == thrd_Current(), "write lock not held by current thread");
+    osi_assertx(lockp->tid[0] == thrd_Current(), "write lock not held by current thread");
 
-    lockp->tid = 0;
+    lockp->tid[0] = 0;
 
     lockp->flags &= ~OSI_LOCKFLAG_EXCL;
     if (!osi_TEmpty(&lockp->d.turn)) {
@@ -360,14 +371,12 @@ void lock_ConvertWToR(osi_rwlock_t *lockp)
     EnterCriticalSection(csp);
 
     osi_assertx(lockp->flags & OSI_LOCKFLAG_EXCL, "write lock not held");
-    osi_assertx(lockp->tid == thrd_Current(), "write lock not held by current thread");
+    osi_assertx(lockp->tid[0] == thrd_Current(), "write lock not held by current thread");
 
     /* convert write lock to read lock */
     lockp->flags &= ~OSI_LOCKFLAG_EXCL;
     lockp->readers++;
 
-    lockp->tid = 0;
-
     if (!osi_TEmpty(&lockp->d.turn)) {
         osi_TSignalForMLs(&lockp->d.turn, /* still have readers */ 1, csp);
     }
@@ -381,6 +390,7 @@ void lock_ConvertRToW(osi_rwlock_t *lockp)
 {
     long i;
     CRITICAL_SECTION *csp;
+    DWORD tid = thrd_Current();
 
     if ((i = lockp->type) != 0) {
         if (i >= 0 && i < OSI_NLOCKTYPES)
@@ -395,17 +405,26 @@ void lock_ConvertRToW(osi_rwlock_t *lockp)
     osi_assertx(!(lockp->flags & OSI_LOCKFLAG_EXCL), "write lock held");
     osi_assertx(lockp->readers > 0, "read lock not held");
 
+    for ( i=0; i < lockp->readers; i++) {
+        if ( lockp->tid[i] == tid ) {
+            for ( ; i < lockp->readers - 1; i++)
+                lockp->tid[i] = lockp->tid[i+1];
+            lockp->tid[i] = 0;
+            break;
+        }
+    }
+
     if (--lockp->readers == 0) {
         /* convert read lock to write lock */
         lockp->flags |= OSI_LOCKFLAG_EXCL;
+        lockp->tid[0] = tid;
     } else {
         lockp->waiters++;
-        osi_TWait(&lockp->d.turn, OSI_SLEEPINFO_W4WRITE, &lockp->flags, csp);
+        osi_TWait(&lockp->d.turn, OSI_SLEEPINFO_W4WRITE, &lockp->flags, lockp->tid, csp);
         lockp->waiters--;
         osi_assert(lockp->readers == 0 && (lockp->flags & OSI_LOCKFLAG_EXCL));
     }
 
-    lockp->tid = thrd_Current();
     LeaveCriticalSection(csp);
 }
 
@@ -437,15 +456,14 @@ void lock_ObtainMutex(struct osi_mutex *lockp)
     /* here we have the fast lock, so see if we can obtain the real lock */
     if (lockp->waiters > 0 || (lockp->flags & OSI_LOCKFLAG_EXCL)) {
         lockp->waiters++;
-        osi_TWait(&lockp->d.turn, OSI_SLEEPINFO_W4WRITE, &lockp->flags, csp);
+        osi_TWait(&lockp->d.turn, OSI_SLEEPINFO_W4WRITE, &lockp->flags, &lockp->tid, csp);
         lockp->waiters--;
         osi_assert(lockp->flags & OSI_LOCKFLAG_EXCL);
-    }
-    else {
+    } else {
         /* if we're here, all clear to set the lock */
         lockp->flags |= OSI_LOCKFLAG_EXCL;
+        lockp->tid = thrd_Current();
     }
-    lockp->tid = thrd_Current();
     LeaveCriticalSection(csp);
 
     if (lockOrderValidation) {
@@ -540,7 +558,8 @@ int lock_TryRead(struct osi_rwlock *lockp)
     }
     else {
         /* if we're here, all clear to set the lock */
-        lockp->readers++;
+        if (++lockp->readers < OSI_RWLOCK_THREADS)
+            lockp->tid[lockp->readers-1] = thrd_Current();
         i = 1;
     }
 
@@ -593,12 +612,10 @@ int lock_TryWrite(struct osi_rwlock *lockp)
     else {
         /* if we're here, all clear to set the lock */
         lockp->flags |= OSI_LOCKFLAG_EXCL;
+        lockp->tid[0] = thrd_Current();
         i = 1;
     }
 
-    if (i)
-        lockp->tid = thrd_Current();
-
     LeaveCriticalSection(csp);
 
     if (lockOrderValidation && i) {
@@ -646,12 +663,10 @@ int lock_TryMutex(struct osi_mutex *lockp) {
     else {
         /* if we're here, all clear to set the lock */
         lockp->flags |= OSI_LOCKFLAG_EXCL;
+        lockp->tid = thrd_Current();
         i = 1;
     }
 
-    if (i)
-        lockp->tid = thrd_Current();
-
     LeaveCriticalSection(csp);
 
     if (lockOrderValidation && i) {
@@ -669,6 +684,7 @@ void osi_SleepR(LONG_PTR sleepVal, struct osi_rwlock *lockp)
     CRITICAL_SECTION *csp;
     osi_queue_t * lockRefH, *lockRefT;
     osi_lock_ref_t *lockRefp;
+    DWORD tid = thrd_Current();
 
     if ((i = lockp->type) != 0) {
         if (i >= 0 && i < OSI_NLOCKTYPES)
@@ -698,6 +714,15 @@ void osi_SleepR(LONG_PTR sleepVal, struct osi_rwlock *lockp)
 
     osi_assertx(lockp->readers > 0, "osi_SleepR: not held");
 
+    for ( i=0; i < lockp->readers; i++) {
+        if ( lockp->tid[i] == tid ) {
+            for ( ; i < lockp->readers - 1; i++)
+                lockp->tid[i] = lockp->tid[i+1];
+            lockp->tid[i] = 0;
+            break;
+        }
+    }
+
     /* XXX better to get the list of things to wakeup from TSignalForMLs, and
      * then do the wakeup after SleepSpin releases the low-level mutex.
      */
@@ -715,6 +740,7 @@ void osi_SleepW(LONG_PTR sleepVal, struct osi_rwlock *lockp)
     CRITICAL_SECTION *csp;
     osi_queue_t * lockRefH, *lockRefT;
     osi_lock_ref_t *lockRefp;
+    DWORD tid = thrd_Current();
 
     if ((i = lockp->type) != 0) {
         if (i >= 0 && i < OSI_NLOCKTYPES)
@@ -745,6 +771,7 @@ void osi_SleepW(LONG_PTR sleepVal, struct osi_rwlock *lockp)
     osi_assertx(lockp->flags & OSI_LOCKFLAG_EXCL, "osi_SleepW: not held");
 
     lockp->flags &= ~OSI_LOCKFLAG_EXCL;
+    lockp->tid[0] = 0;
     if (!osi_TEmpty(&lockp->d.turn)) {
         osi_TSignalForMLs(&lockp->d.turn, 0, NULL);
     }
@@ -789,6 +816,7 @@ void osi_SleepM(LONG_PTR sleepVal, struct osi_mutex *lockp)
     osi_assertx(lockp->flags & OSI_LOCKFLAG_EXCL, "osi_SleepM not held");
 
     lockp->flags &= ~OSI_LOCKFLAG_EXCL;
+    lockp->tid = 0;
     if (!osi_TEmpty(&lockp->d.turn)) {
         osi_TSignalForMLs(&lockp->d.turn, 0, NULL);
     }
@@ -850,11 +878,8 @@ void lock_InitializeRWLock(osi_rwlock_t *mp, char *namep, unsigned short level)
     /* otherwise we have the base case, which requires no special
      * initialization.
      */
-    mp->type = 0;
-    mp->flags = 0;
+    memset(mp, 0, sizeof(osi_rwlock_t));
     mp->atomicIndex = (unsigned short)(InterlockedIncrement(&atomicIndexCounter) % OSI_MUTEXHASHSIZE);
-    mp->readers = 0;
-    mp->tid = 0;
     mp->level = level;
     osi_TInit(&mp->d.turn);
     return;
index 73679dd..9ef6b90 100644 (file)
@@ -53,11 +53,14 @@ typedef struct osi_mutex {
  *
  * This type of lock has N readers or one writer.
  */
+
+#define OSI_RWLOCK_THREADS 32
+
 typedef struct osi_rwlock {
     char type;                 /* for all types; type 0 uses atomic count */
     char flags;                        /* flags for base type */
     unsigned short atomicIndex;        /* index into hash table for low-level sync */
-    DWORD tid;                 /* writer's tid */
+    DWORD tid[OSI_RWLOCK_THREADS];                     /* writer's tid */
     unsigned short waiters;    /* waiters */
     unsigned short readers;    /* readers */
     union {
@@ -149,10 +152,10 @@ extern void osi_SetLockOrderValidation(int);
 
 #define lock_AssertRead(x) osi_assertx(lock_GetRWLockState(x) & OSI_RWLOCK_READHELD, "!OSI_RWLOCK_READHELD")
 
-#define lock_AssertWrite(x) osi_assertx(lock_GetRWLockState(x) & OSI_RWLOCK_WRITEHELD, "!OSI_RWLOCK_WRITEHELD")
+#define lock_AssertWrite(x) osi_assertx((lock_GetRWLockState(x) & OSI_RWLOCK_WRITEHELD) && ((x)->tid[0] == thrd_Current()), "!OSI_RWLOCK_WRITEHELD")
 
 #define lock_AssertAny(x) osi_assertx(lock_GetRWLockState(x) != 0, "!(OSI_RWLOCK_READHELD | OSI_RWLOCK_WRITEHELD)")
 
-#define lock_AssertMutex(x) osi_assertx(lock_GetMutexState(x) & OSI_MUTEX_HELD, "!OSI_MUTEX_HELD")
+#define lock_AssertMutex(x) osi_assertx((lock_GetMutexState(x) & OSI_MUTEX_HELD) && ((x)->tid == thrd_Current()), "!OSI_MUTEX_HELD")
 
 #endif /* OPENAFS_WINNT_CLIENT_OSI_OSIBASEL_H */
index aa1ded3..a810936 100644 (file)
@@ -125,63 +125,63 @@ void osi_FreeSleepInfo(osi_sleepInfo_t *ap)
 /* allocate a new sleep structure from the free list */
 osi_sleepInfo_t *osi_AllocSleepInfo()
 {
-       osi_sleepInfo_t *ap;
+    osi_sleepInfo_t *ap;
 
-       EnterCriticalSection(&osi_sleepInfoAllocCS);
-       if (!(ap = osi_sleepInfoFreeListp)) {
-               ap = (osi_sleepInfo_t *) malloc(sizeof(osi_sleepInfo_t));
-               ap->sema = CreateSemaphore(NULL, 0, 65536, (char *) 0);
-                osi_sleepInfoAllocs++;
-       }
-       else {
-               osi_sleepInfoFreeListp = (osi_sleepInfo_t *) ap->q.nextp;
-               osi_sleepInfoCount--;
-       }
-       ap->tid = GetCurrentThreadId();
-       ap->states = 0; /* not signalled yet */
-       LeaveCriticalSection(&osi_sleepInfoAllocCS);
+    EnterCriticalSection(&osi_sleepInfoAllocCS);
+    if (!(ap = osi_sleepInfoFreeListp)) {
+        ap = (osi_sleepInfo_t *) malloc(sizeof(osi_sleepInfo_t));
+        ap->sema = CreateSemaphore(NULL, 0, 65536, (char *) 0);
+        osi_sleepInfoAllocs++;
+    }
+    else {
+        osi_sleepInfoFreeListp = (osi_sleepInfo_t *) ap->q.nextp;
+        osi_sleepInfoCount--;
+    }
+    ap->tid = GetCurrentThreadId();
+    ap->states = 0;    /* not signalled yet */
+    LeaveCriticalSection(&osi_sleepInfoAllocCS);
 
-       return ap;
+    return ap;
 }
 
 int osi_Once(osi_once_t *argp)
 {
-       long i;
+    long i;
 
-       while ((i=InterlockedExchange(&argp->atomic, 1)) != 0) {
-               Sleep(0);
-       }
+    while ((i=InterlockedExchange(&argp->atomic, 1)) != 0) {
+        Sleep(0);
+    }
 
-       if (argp->done == 0) {
-               argp->done = 1;
-               return 1;
-       }
+    if (argp->done == 0) {
+        argp->done = 1;
+        return 1;
+    }
 
-       /* otherwise we've already been initialized, so clear lock and return */
-       InterlockedExchange(&argp->atomic, 0);
-       return 0;
+    /* otherwise we've already been initialized, so clear lock and return */
+    InterlockedExchange(&argp->atomic, 0);
+    return 0;
 }
 
 void osi_EndOnce(osi_once_t *argp)
 {
-       InterlockedExchange(&argp->atomic, 0);
+    InterlockedExchange(&argp->atomic, 0);
 }
 
 int osi_TestOnce(osi_once_t *argp)
 {
-       long localDone;
-       long i;
+    long localDone;
+    long i;
 
-       while ((i=InterlockedExchange(&argp->atomic, 1)) != 0) {
-               Sleep(0);
-       }
+    while ((i=InterlockedExchange(&argp->atomic, 1)) != 0) {
+        Sleep(0);
+    }
 
-       localDone = argp->done;
+    localDone = argp->done;
 
-       /* drop interlock */
-       InterlockedExchange(&argp->atomic, 0);
+    /* drop interlock */
+    InterlockedExchange(&argp->atomic, 0);
 
-       return (localDone? 0 : 1);
+    return (localDone? 0 : 1);
 }
 
 /* Initialize the package, should be called while single-threaded.
@@ -190,74 +190,75 @@ int osi_TestOnce(osi_once_t *argp)
  */
 void osi_Init(void)
 {
-       int i;
-       static osi_once_t once;
-        unsigned long remainder;               /* for division output */
-       osi_fdType_t *typep;
-        SYSTEMTIME sysTime;
-        FILETIME fileTime;
-        osi_hyper_t bootTime;
-
-       /* check to see if already initialized; if so, claim success */
-       if (!osi_Once(&once)) return;
-
-       /* setup boot time values */
-        GetSystemTime(&sysTime);
-        SystemTimeToFileTime(&sysTime, &fileTime);
-
-       /* change the base of the time so it won't be negative for a long time */
-       fileTime.dwHighDateTime -= 28000000;
-
-        bootTime.HighPart = fileTime.dwHighDateTime;
-        bootTime.LowPart = fileTime.dwLowDateTime;
-        /* now, bootTime is in 100 nanosecond units, and we'd really rather
-         * have it in 1 second units, units 10,000,000 times bigger.
-         * So, we divide.
-         */
-        bootTime = ExtendedLargeIntegerDivide(bootTime, 10000000, &remainder);
-        osi_bootTime = bootTime.LowPart;
+    int i;
+    static osi_once_t once;
+    unsigned long remainder;           /* for division output */
+    osi_fdType_t *typep;
+    SYSTEMTIME sysTime;
+    FILETIME fileTime;
+    osi_hyper_t bootTime;
 
-       /* initialize thread-local storage for sleep Info structures */
-       osi_SleepSlot = TlsAlloc();
+    /* check to see if already initialized; if so, claim success */
+    if (!osi_Once(&once))
+        return;
 
-       /* init FD system */
-       osi_InitFD();
+    /* setup boot time values */
+    GetSystemTime(&sysTime);
+    SystemTimeToFileTime(&sysTime, &fileTime);
 
-       /* initialize critical regions and semaphores */
-       for(i=0;i<OSI_SLEEPHASHSIZE; i++) {
-               InitializeCriticalSection(&osi_critSec[i]);
-               osi_sleepers[i] = (osi_sleepInfo_t *) NULL;
-               osi_sleepersEnd[i] = (osi_sleepInfo_t *) NULL;
-       }
+    /* change the base of the time so it won't be negative for a long time */
+    fileTime.dwHighDateTime -= 28000000;
 
-       /* free list CS */
-       InitializeCriticalSection(&osi_sleepInfoAllocCS);
-
-       /* initialize cookie system */
-       InitializeCriticalSection(&osi_sleepFDCS);
-
-       /* register the FD type */
-       typep = osi_RegisterFDType("sleep", &osi_sleepFDOps, NULL);
-       if (typep) {
-               /* add formatting info */
-               osi_AddFDFormatInfo(typep, OSI_DBRPC_REGIONINT, 0,
-                       "Sleep address", OSI_DBRPC_HEX);
-               osi_AddFDFormatInfo(typep, OSI_DBRPC_REGIONINT, 1,
-                       "Thread ID", 0);
-               osi_AddFDFormatInfo(typep, OSI_DBRPC_REGIONINT, 2,
-                       "States", OSI_DBRPC_HEX);
-       }
+    bootTime.HighPart = fileTime.dwHighDateTime;
+    bootTime.LowPart = fileTime.dwLowDateTime;
+    /* now, bootTime is in 100 nanosecond units, and we'd really rather
+     * have it in 1 second units, units 10,000,000 times bigger.
+     * So, we divide.
+     */
+    bootTime = ExtendedLargeIntegerDivide(bootTime, 10000000, &remainder);
+    osi_bootTime = bootTime.LowPart;
+
+    /* initialize thread-local storage for sleep Info structures */
+    osi_SleepSlot = TlsAlloc();
+
+    /* init FD system */
+    osi_InitFD();
+
+    /* initialize critical regions and semaphores */
+    for(i=0;i<OSI_SLEEPHASHSIZE; i++) {
+        InitializeCriticalSection(&osi_critSec[i]);
+        osi_sleepers[i] = (osi_sleepInfo_t *) NULL;
+        osi_sleepersEnd[i] = (osi_sleepInfo_t *) NULL;
+    }
+
+    /* free list CS */
+    InitializeCriticalSection(&osi_sleepInfoAllocCS);
+
+    /* initialize cookie system */
+    InitializeCriticalSection(&osi_sleepFDCS);
+
+    /* register the FD type */
+    typep = osi_RegisterFDType("sleep", &osi_sleepFDOps, NULL);
+    if (typep) {
+        /* add formatting info */
+        osi_AddFDFormatInfo(typep, OSI_DBRPC_REGIONINT, 0,
+                             "Sleep address", OSI_DBRPC_HEX);
+        osi_AddFDFormatInfo(typep, OSI_DBRPC_REGIONINT, 1,
+                             "Thread ID", 0);
+        osi_AddFDFormatInfo(typep, OSI_DBRPC_REGIONINT, 2,
+                             "States", OSI_DBRPC_HEX);
+    }
 
-       osi_BaseInit();
+    osi_BaseInit();
 
-       osi_StatInit();
+    osi_StatInit();
 
-        osi_InitQueue();
+    osi_InitQueue();
 
-       osi_EndOnce(&once);
+    osi_EndOnce(&once);
 }
 
-void osi_TWait(osi_turnstile_t *turnp, int waitFor, void *patchp, CRITICAL_SECTION *releasep)
+void osi_TWait(osi_turnstile_t *turnp, int waitFor, void *patchp, DWORD *tidp, CRITICAL_SECTION *releasep)
 {
     osi_sleepInfo_t *sp;
     unsigned int code;
@@ -273,35 +274,36 @@ void osi_TWait(osi_turnstile_t *turnp, int waitFor, void *patchp, CRITICAL_SECTI
     sp->refCount = 0;
     sp->waitFor = waitFor;
     sp->value = (LONG_PTR) patchp;
+    sp->tidp   = tidp;
     osi_QAddT((osi_queue_t **) &turnp->firstp, (osi_queue_t **) &turnp->lastp, &sp->q);
     if (!turnp->lastp)
        turnp->lastp = sp;
     LeaveCriticalSection(releasep);
 
-       /* now wait for the signal */
-       while(1) {
-               /* wait */
-               code = WaitForSingleObject(sp->sema,
-                       /* timeout */ INFINITE);
-
-               /* if the reason for the wakeup was that we were signalled,
-                * break out, otherwise try again, since the semaphore count is
-                * decreased only when we get WAIT_OBJECT_0 back.
-                */
-               if (code == WAIT_OBJECT_0) break;
-       }       /* while we're waiting */
-
-       /* we're the only one who should be looking at or changing this
-        * structure after it gets signalled.  Sema sp->sema isn't signalled
-        * any longer after we're back from WaitForSingleObject, so we can
-        * free this element directly.
+    /* now wait for the signal */
+    while(1) {
+        /* wait */
+        code = WaitForSingleObject(sp->sema,
+                                    /* timeout */ INFINITE);
+
+        /* if the reason for the wakeup was that we were signalled,
+         * break out, otherwise try again, since the semaphore count is
+         * decreased only when we get WAIT_OBJECT_0 back.
          */
-        osi_assert(sp->states & OSI_SLEEPINFO_SIGNALLED);
+        if (code == WAIT_OBJECT_0) break;
+    }  /* while we're waiting */
+
+    /* we're the only one who should be looking at or changing this
+     * structure after it gets signalled.  Sema sp->sema isn't signalled
+     * any longer after we're back from WaitForSingleObject, so we can
+     * free this element directly.
+     */
+    osi_assert(sp->states & OSI_SLEEPINFO_SIGNALLED);
 
-        osi_FreeSleepInfo(sp);
+    osi_FreeSleepInfo(sp);
 
-       /* reobtain, since caller commonly needs it */
-        EnterCriticalSection(releasep);
+    /* reobtain, since caller commonly needs it */
+    EnterCriticalSection(releasep);
 }
 
 /* must be called with a critical section held that guards the turnstile
@@ -311,29 +313,29 @@ void osi_TWait(osi_turnstile_t *turnp, int waitFor, void *patchp, CRITICAL_SECTI
  */
 void osi_TSignal(osi_turnstile_t *turnp)
 {
-       osi_sleepInfo_t *sp;
+    osi_sleepInfo_t *sp;
 
-       if (!turnp->lastp)
-           return;
+    if (!turnp->lastp)
+        return;
 
-        sp = turnp->lastp;
-       turnp->lastp = (osi_sleepInfo_t *) osi_QPrev(&sp->q);
-        osi_QRemoveHT((osi_queue_t **) &turnp->firstp, (osi_queue_t **) &turnp->lastp, &sp->q);
-        sp->states |= OSI_SLEEPINFO_SIGNALLED;
-        ReleaseSemaphore(sp->sema, 1, (long *) 0);
+    sp = turnp->lastp;
+    turnp->lastp = (osi_sleepInfo_t *) osi_QPrev(&sp->q);
+    osi_QRemoveHT((osi_queue_t **) &turnp->firstp, (osi_queue_t **) &turnp->lastp, &sp->q);
+    sp->states |= OSI_SLEEPINFO_SIGNALLED;
+    ReleaseSemaphore(sp->sema, 1, (long *) 0);
 }
 
 /* like TSignal, only wake *everyone* */
 void osi_TBroadcast(osi_turnstile_t *turnp)
 {
-       osi_sleepInfo_t *sp;
-
-        while(sp = turnp->lastp) {
-               turnp->lastp = (osi_sleepInfo_t *) osi_QPrev(&sp->q);
-               osi_QRemoveHT((osi_queue_t **) &turnp->firstp, (osi_queue_t **) &turnp->lastp, &sp->q);
-               sp->states |= OSI_SLEEPINFO_SIGNALLED;
-               ReleaseSemaphore(sp->sema, 1, (long *) 0);
-       }       /* while someone's still asleep */
+    osi_sleepInfo_t *sp;
+
+    while(sp = turnp->lastp) {
+        turnp->lastp = (osi_sleepInfo_t *) osi_QPrev(&sp->q);
+        osi_QRemoveHT((osi_queue_t **) &turnp->firstp, (osi_queue_t **) &turnp->lastp, &sp->q);
+        sp->states |= OSI_SLEEPINFO_SIGNALLED;
+        ReleaseSemaphore(sp->sema, 1, (long *) 0);
+    }  /* while someone's still asleep */
 }
 
 /* special turnstile signal for mutexes and locks.  Wakes up only those who
@@ -352,64 +354,71 @@ void osi_TBroadcast(osi_turnstile_t *turnp)
  */
 void osi_TSignalForMLs(osi_turnstile_t *turnp, int stillHaveReaders, CRITICAL_SECTION *csp)
 {
-       osi_sleepInfo_t *tsp;           /* a temp */
-       osi_sleepInfo_t *nsp;           /* a temp */
-        osi_queue_t *wakeupListp;      /* list of dudes to wakeup after dropping lock */
-        int wokeReader;
-        unsigned short *sp;
-        unsigned char *cp;
-
-       wokeReader = stillHaveReaders;
-       wakeupListp = NULL;
-        while(tsp = turnp->lastp) {
-               /* look at each sleepInfo until we find someone we're not supposed to
-                 * wakeup.
-                 */
-               if (tsp->waitFor & OSI_SLEEPINFO_W4WRITE) {
-                       if (wokeReader) break;
-                }
-                else wokeReader = 1;
-
-                /* otherwise, we will wake this guy.  For now, remove from this list
-                 * and move to private one, so we can do the wakeup after releasing
-                 * the crit sec.
-                 */
-               turnp->lastp = (osi_sleepInfo_t *) osi_QPrev(&tsp->q);
-               osi_QRemoveHT((osi_queue_t **) &turnp->firstp, (osi_queue_t **) &turnp->lastp, &tsp->q);
-
-               /* do the patching required for lock obtaining */
-                if (tsp->waitFor & OSI_SLEEPINFO_W4WRITE) {
-                       cp = (void *) tsp->value;
-                        (*cp) |= OSI_LOCKFLAG_EXCL;
-                }
-                else if (tsp->waitFor & OSI_SLEEPINFO_W4READ) {
-                       sp = (void *) tsp->value;
-                        (*sp)++;
-                }
-
-                /* and add to our own list */
-                tsp->q.nextp = wakeupListp;
-                wakeupListp = &tsp->q;
-
-                /* now if we woke a writer, we're done, since it is pointless
-                 * to wake more than one writer.
-                 */
-                if (!wokeReader) break;
+    osi_sleepInfo_t *tsp;              /* a temp */
+    osi_sleepInfo_t *nsp;              /* a temp */
+    osi_queue_t *wakeupListp;  /* list of dudes to wakeup after dropping lock */
+    int wokeReader;
+    unsigned short *sp;
+    unsigned char *cp;
+
+    wokeReader = stillHaveReaders;
+    wakeupListp = NULL;
+    while(tsp = turnp->lastp) {
+        /* look at each sleepInfo until we find someone we're not supposed to
+         * wakeup.
+         */
+        if (tsp->waitFor & OSI_SLEEPINFO_W4WRITE) {
+            if (wokeReader)
+                break;
+        }
+        else
+            wokeReader = 1;
+
+        /* otherwise, we will wake this guy.  For now, remove from this list
+         * and move to private one, so we can do the wakeup after releasing
+         * the crit sec.
+         */
+        turnp->lastp = (osi_sleepInfo_t *) osi_QPrev(&tsp->q);
+        osi_QRemoveHT((osi_queue_t **) &turnp->firstp, (osi_queue_t **) &turnp->lastp, &tsp->q);
+
+        /* do the patching required for lock obtaining */
+        if (tsp->waitFor & OSI_SLEEPINFO_W4WRITE) {
+            cp = (void *) tsp->value;
+            (*cp) |= OSI_LOCKFLAG_EXCL;
+            tsp->tidp[0] = tsp->tid;
+        }
+        else if (tsp->waitFor & OSI_SLEEPINFO_W4READ) {
+            sp = (void *) tsp->value;
+            (*sp)++;
+            if ((*sp) <= OSI_RWLOCK_THREADS)
+                tsp->tidp[(*sp)-1] = tsp->tid;
         }
 
-        /* hit end, or found someone we're not supposed to wakeup */
-       if (csp) LeaveCriticalSection(csp);
+        /* and add to our own list */
+        tsp->q.nextp = wakeupListp;
+        wakeupListp = &tsp->q;
+
+        /* now if we woke a writer, we're done, since it is pointless
+         * to wake more than one writer.
+         */
+        if (!wokeReader)
+            break;
+    }
+
+    /* hit end, or found someone we're not supposed to wakeup */
+    if (csp)
+        LeaveCriticalSection(csp);
 
         /* finally, wakeup everyone we found.  Don't free things since the sleeper
          * will free the sleepInfo structure.
          */
        for(tsp = (osi_sleepInfo_t *) wakeupListp; tsp; tsp = nsp) {
-               /* pull this out first, since *tsp *could* get freed immediately
-                 * after the ReleaseSemaphore, if a context swap occurs.
-                 */
-               nsp = (osi_sleepInfo_t *) tsp->q.nextp;
-               tsp->states |= OSI_SLEEPINFO_SIGNALLED;
-               ReleaseSemaphore(tsp->sema, 1, (long *) 0);
+            /* pull this out first, since *tsp *could* get freed immediately
+             * after the ReleaseSemaphore, if a context swap occurs.
+             */
+            nsp = (osi_sleepInfo_t *) tsp->q.nextp;
+            tsp->states |= OSI_SLEEPINFO_SIGNALLED;
+            ReleaseSemaphore(tsp->sema, 1, (long *) 0);
         }
 }
 
@@ -492,39 +501,39 @@ void osi_WakeupSpin(LONG_PTR sleepValue)
 
 void osi_Sleep(LONG_PTR sleepVal)
 {
-       CRITICAL_SECTION *csp;
+    CRITICAL_SECTION *csp;
 
-       /* may as well save some code by using SleepSched again */
-        csp = &osi_baseAtomicCS[0];
-        EnterCriticalSection(csp);
-       osi_SleepSpin(sleepVal, csp);
+    /* may as well save some code by using SleepSched again */
+    csp = &osi_baseAtomicCS[0];
+    EnterCriticalSection(csp);
+    osi_SleepSpin(sleepVal, csp);
 }
 
 void osi_Wakeup(LONG_PTR sleepVal)
 {
-       /* how do we do osi_Wakeup on a per-lock package type? */
+    /* how do we do osi_Wakeup on a per-lock package type? */
 
-       osi_WakeupSpin(sleepVal);
+    osi_WakeupSpin(sleepVal);
 }
 
 long osi_SleepFDCreate(osi_fdType_t *fdTypep, osi_fd_t **outpp)
 {
-       osi_sleepFD_t *cp;
+    osi_sleepFD_t *cp;
 
-       cp = (osi_sleepFD_t *)malloc(sizeof(*cp));
-       memset((void *) cp, 0, sizeof(*cp));
-       cp->idx = 0;
-       cp->sip = NULL;
+    cp = (osi_sleepFD_t *)malloc(sizeof(*cp));
+    memset((void *) cp, 0, sizeof(*cp));
+    cp->idx = 0;
+    cp->sip = NULL;
 
-       /* done */
-       *outpp = &cp->fd;
-       return 0;
+    /* done */
+    *outpp = &cp->fd;
+    return 0;
 }
 
 long osi_SleepFDClose(osi_fd_t *cp)
 {
-       free((void *) cp);
-       return 0;
+    free((void *) cp);
+    return 0;
 }
 
 /* called with osi_sleepFDCS locked; returns with same, so that
@@ -533,52 +542,55 @@ long osi_SleepFDClose(osi_fd_t *cp)
  */
 void osi_AdvanceSleepFD(osi_sleepFD_t *cp)
 {
-       int idx;                /* index we're dealing with */
-       int oidx;               /* index we locked */
-       osi_sleepInfo_t *sip;
-       osi_sleepInfo_t *nsip;
-
-       idx = 0;        /* so we go around once safely */
-       sip = NULL;
-       while(idx < OSI_SLEEPHASHSIZE) {
-               /* cp->sip should be held */
-               idx = cp->idx;
-               EnterCriticalSection(&osi_critSec[idx]);
-               oidx = idx;     /* remember original index; that's the one we locked */
-
-               /* if there's a sleep info structure in the FD, it should be held; it
-                * is the one we just processed, so we want to move on to the next.
-                * If not, then we want to process the chain in the bucket idx points
-                * to.
-                */
-               if ((sip = cp->sip) == NULL) {
-                       sip = osi_sleepers[idx];
-                       if (!sip) idx++;
-                       else sip->refCount++;
-               }
-               else {
-                       /* it is safe to release the current sleep info guy now
-                        * since we hold the bucket lock.  Pull next guy out first,
-                        * since if sip is deleted, Release will move him into
-                        * free list.
-                        */
-                       nsip = (osi_sleepInfo_t *) sip->q.nextp;
-                       osi_ReleaseSleepInfo(sip);
-                       sip = nsip;
-
-                       if (sip) sip->refCount++;
-                       else idx++;
-               }
-               cp->idx = idx;
-               cp->sip = sip;
-               LeaveCriticalSection(&osi_critSec[oidx]);
-
-               /* now, if we advanced to a new sleep info structure, we're
-                * done, otherwise we continue and look at the next hash bucket
-                * until we're out of them.
-                */
-               if (sip) break;
-       }
+    int idx;           /* index we're dealing with */
+    int oidx;          /* index we locked */
+    osi_sleepInfo_t *sip;
+    osi_sleepInfo_t *nsip;
+
+    idx = 0;   /* so we go around once safely */
+    sip = NULL;
+    while(idx < OSI_SLEEPHASHSIZE) {
+        /* cp->sip should be held */
+        idx = cp->idx;
+        EnterCriticalSection(&osi_critSec[idx]);
+        oidx = idx;    /* remember original index; that's the one we locked */
+
+        /* if there's a sleep info structure in the FD, it should be held; it
+         * is the one we just processed, so we want to move on to the next.
+         * If not, then we want to process the chain in the bucket idx points
+         * to.
+         */
+        if ((sip = cp->sip) == NULL) {
+            sip = osi_sleepers[idx];
+            if (!sip) idx++;
+            else sip->refCount++;
+        }
+        else {
+            /* it is safe to release the current sleep info guy now
+             * since we hold the bucket lock.  Pull next guy out first,
+             * since if sip is deleted, Release will move him into
+             * free list.
+             */
+            nsip = (osi_sleepInfo_t *) sip->q.nextp;
+            osi_ReleaseSleepInfo(sip);
+            sip = nsip;
+
+            if (sip)
+                sip->refCount++;
+            else
+                idx++;
+        }
+        cp->idx = idx;
+        cp->sip = sip;
+        LeaveCriticalSection(&osi_critSec[oidx]);
+
+        /* now, if we advanced to a new sleep info structure, we're
+         * done, otherwise we continue and look at the next hash bucket
+         * until we're out of them.
+         */
+        if (sip)
+            break;
+    }
 }
 
 
@@ -620,7 +632,7 @@ long osi_SleepFDGetInfo(osi_fd_t *ifdp, osi_remGetInfoParms_t *parmsp)
 /* finally, DLL-specific code for NT */
 BOOL APIENTRY DLLMain(HANDLE inst, DWORD why, char *reserved)
 {
-       return 1;
+    return 1;
 }
 
 /* some misc functions for setting hash table sizes */
@@ -628,48 +640,51 @@ BOOL APIENTRY DLLMain(HANDLE inst, DWORD why, char *reserved)
 /* return true iff x is prime */
 int osi_IsPrime(unsigned long x)
 {
-       unsigned long c;
+    unsigned long c;
 
-       /* even numbers aren't prime */
-       if ((x & 1) == 0 && x != 2) return 0;
+    /* even numbers aren't prime */
+    if ((x & 1) == 0 && x != 2) return 0;
 
-        for(c = 3; c<x; c += 2) {
-               /* see if x is divisible by c */
-               if ((x % c) == 0) return 0;     /* yup, it ain't prime */
+    for(c = 3; c<x; c += 2) {
+        /* see if x is divisible by c */
+        if ((x % c) == 0)
+            return 0;  /* yup, it ain't prime */
 
-                /* see if we've gone far enough; only have to compute until
-                 * square root of x.
-                 */
-                if (c*c > x) return 1;
-        }
+        /* see if we've gone far enough; only have to compute until
+         * square root of x.
+         */
+        if (c*c > x)
+            return 1;
+    }
 
-       /* probably never get here */
-        return 1;
+    /* probably never get here */
+    return 1;
 }
 
 /* return first prime number less than or equal to x */
 unsigned long osi_PrimeLessThan(unsigned long x) {
-       unsigned long c;
+    unsigned long c;
 
-        for(c = x; c > 1; c--) {
-               if (osi_IsPrime(c)) return c;
-        }
+    for(c = x; c > 1; c--) {
+        if (osi_IsPrime(c))
+            return c;
+    }
 
-       /* ever reached? */
-        return 1;
+    /* ever reached? */
+    return 1;
 }
 
 /* return the # of seconds since some fixed date */
 unsigned long osi_GetBootTime(void)
 {
-       return osi_bootTime;
+    return osi_bootTime;
 }
 
 static int (*notifFunc)(char *, char *, long) = NULL;
 
 void osi_InitPanic(void *anotifFunc)
 {
-       notifFunc = anotifFunc;
+    notifFunc = anotifFunc;
 }
 
 void osi_panic(char *msgp, char *filep, long line)
@@ -712,26 +727,26 @@ time_t osi_Time(void)
 /* get time in seconds since some relatively recent time */
 void osi_GetTime(long *timesp)
 {
-       FILETIME fileTime;
-        SYSTEMTIME sysTime;
-        unsigned long remainder;
-        LARGE_INTEGER bootTime;
-
-       /* setup boot time values */
-        GetSystemTime(&sysTime);
-        SystemTimeToFileTime(&sysTime, &fileTime);
-
-       /* change the base of the time so it won't be negative for a long time */
-       fileTime.dwHighDateTime -= 28000000;
-
-        bootTime.HighPart = fileTime.dwHighDateTime;
-        bootTime.LowPart = fileTime.dwLowDateTime;
-        /* now, bootTime is in 100 nanosecond units, and we'd really rather
-         * have it in 1 microsecond units, units 10 times bigger.
-         * So, we divide.
-         */
-        bootTime = ExtendedLargeIntegerDivide(bootTime, 10, &remainder);
-       bootTime = ExtendedLargeIntegerDivide(bootTime, 1000000, &remainder);
-       timesp[0] = bootTime.LowPart;           /* seconds */
-        timesp[1] = remainder;                 /* microseconds */
+    FILETIME fileTime;
+    SYSTEMTIME sysTime;
+    unsigned long remainder;
+    LARGE_INTEGER bootTime;
+
+    /* setup boot time values */
+    GetSystemTime(&sysTime);
+    SystemTimeToFileTime(&sysTime, &fileTime);
+
+    /* change the base of the time so it won't be negative for a long time */
+    fileTime.dwHighDateTime -= 28000000;
+
+    bootTime.HighPart = fileTime.dwHighDateTime;
+    bootTime.LowPart = fileTime.dwLowDateTime;
+    /* now, bootTime is in 100 nanosecond units, and we'd really rather
+     * have it in 1 microsecond units, units 10 times bigger.
+     * So, we divide.
+     */
+    bootTime = ExtendedLargeIntegerDivide(bootTime, 10, &remainder);
+    bootTime = ExtendedLargeIntegerDivide(bootTime, 1000000, &remainder);
+    timesp[0] = bootTime.LowPart;              /* seconds */
+    timesp[1] = remainder;                     /* microseconds */
 }
index 4c7fb9b..0c3fe46 100644 (file)
 #define OSI_SLEEPINFO_W4READ   1       /* waiting for a read lock */
 #define OSI_SLEEPINFO_W4WRITE  2       /* waiting for a write lock */
 typedef struct osi_sleepInfo {
-       osi_queue_t q;
-       LONG_PTR value;         /* sleep value when in a sleep queue, patch addr for turnstiles */
-       size_t tid;             /* thread ID of sleeper */
-       EVENT_HANDLE sema;      /* semaphore for this entry */
-       unsigned short states;  /* states bits */
-       unsigned short idx;     /* sleep hash table we're in, if in hash */
-        unsigned short waitFor;        /* what are we waiting for; used for bulk wakeups */
-       unsigned long refCount; /* reference count from FDs */
+    osi_queue_t q;
+    LONG_PTR value;            /* sleep value when in a sleep queue, patch addr for turnstiles */
+    DWORD *tidp;                /* tid history */
+    size_t tid;                        /* thread ID of sleeper */
+    EVENT_HANDLE sema;         /* semaphore for this entry */
+    unsigned short states;     /* states bits */
+    unsigned short idx;                /* sleep hash table we're in, if in hash */
+    unsigned short waitFor;    /* what are we waiting for; used for bulk wakeups */
+    unsigned long refCount;     /* reference count from FDs */
 } osi_sleepInfo_t;
 
 /* first guy is the most recently added process */
@@ -144,8 +145,9 @@ void osi_panic(char *, char *, long);
 
 time_t osi_Time(void);
 
-extern void osi_TWait(osi_turnstile_t *turnp, int waitFor, void *patchp,
-       Crit_Sec *releasep);
+extern void osi_TWait(osi_turnstile_t *turnp, int waitFor,
+                      void *patchp, DWORD *tidp,
+                      Crit_Sec *releasep);
 
 extern void osi_TSignal(osi_turnstile_t *turnp);
 
index 1f42042..d11f5d7 100644 (file)
@@ -78,7 +78,7 @@ static void lock_ObtainWriteStat(osi_rwlock_t *lockp)
                lockp->waiters++;
                if (!ap) ap = osi_QueueActiveInfo(&realp->qi,
                        OSI_ACTIVEFLAGS_WRITER | OSI_ACTIVEFLAGS_WAITER);
-                osi_TWait(&realp->turn, OSI_SLEEPINFO_W4WRITE, &lockp->flags, csp);
+                osi_TWait(&realp->turn, OSI_SLEEPINFO_W4WRITE, &lockp->flags, lockp->tid, csp);
                lockp->waiters--;
                osi_assert((lockp->flags & OSI_LOCKFLAG_EXCL) && lockp->readers == 0);
        }
@@ -123,7 +123,7 @@ static void lock_ObtainReadStat(osi_rwlock_t *lockp)
                lockp->waiters++;
                if (!ap) ap = osi_QueueActiveInfo(&realp->qi,
                        OSI_ACTIVEFLAGS_WAITER | OSI_ACTIVEFLAGS_READER);
-               osi_TWait(&realp->turn, OSI_SLEEPINFO_W4READ, &lockp->readers, csp);
+               osi_TWait(&realp->turn, OSI_SLEEPINFO_W4READ, &lockp->readers, lockp->tid, csp);
                 lockp->waiters--;
                 osi_assert(!(lockp->flags & OSI_LOCKFLAG_EXCL) && lockp->readers > 0);
        }
@@ -234,7 +234,7 @@ static void lock_ConvertRToWStat(osi_rwlock_t *lockp)
             lockp->waiters++;
             ap = osi_QueueActiveInfo(&realp->qi,
                                      OSI_ACTIVEFLAGS_WRITER | OSI_ACTIVEFLAGS_WAITER);
-            osi_TWait(&realp->turn, OSI_SLEEPINFO_W4WRITE, &lockp->flags, csp);
+            osi_TWait(&realp->turn, OSI_SLEEPINFO_W4WRITE, &lockp->flags, lockp->tid, csp);
             lockp->waiters--;
             osi_assert((lockp->flags & OSI_LOCKFLAG_EXCL) && lockp->readers == 0);
 
@@ -302,7 +302,7 @@ static void lock_ObtainMutexStat(struct osi_mutex *lockp)
        if (lockp->waiters > 0 || (lockp->flags & OSI_LOCKFLAG_EXCL)) {
                lockp->waiters++;
                ap = osi_QueueActiveInfo(&realp->qi, OSI_ACTIVEFLAGS_WAITER);
-               osi_TWait(&realp->turn, OSI_SLEEPINFO_W4WRITE, &lockp->flags, csp);
+               osi_TWait(&realp->turn, OSI_SLEEPINFO_W4WRITE, &lockp->flags, &lockp->tid, csp);
                lockp->waiters--;
                 osi_assert(lockp->flags & OSI_LOCKFLAG_EXCL);
        }
index b81a3a8..89e81c5 100644 (file)
@@ -82,7 +82,7 @@ typedef struct osi_rwlockStat {
        osi_turnstile_t turn;           /* the real turnstile */
        unsigned long refCount;         /* so we can iterate cleanly */
        short states;
-        DWORD tid;
+        DWORD tid[OSI_RWLOCK_THREADS];
 
        /* statistics */
        LARGE_INTEGER writeLockedTime;  /* total time held */