#include #include #include #include #include #include #include #define TEST_SYNC_CRITICAL_TEST1_RUNTIME_MS 500 #define TEST_SYNC_CRITICAL_TEST1_RUNS 4 CRITICAL_SECTION critical; LONG gTestValueVulnerable = 0; LONG gTestValueSerialized = 0; BOOL TestSynchCritical_TriggerAndCheckRaceCondition(HANDLE OwningThread, LONG RecursionCount) { /* if called unprotected this will hopefully trigger a race condition ... */ gTestValueVulnerable++; if (critical.OwningThread != OwningThread) { printf("CriticalSection failure: OwningThread is invalid\n"); return FALSE; } if (critical.RecursionCount != RecursionCount) { printf("CriticalSection failure: RecursionCount is invalid\n"); return FALSE; } /* ... which we try to detect using the serialized counter */ if (gTestValueVulnerable != InterlockedIncrement(&gTestValueSerialized)) { printf("CriticalSection failure: Data corruption detected\n"); return FALSE; } return TRUE; } /* this thread function shall increment the global dwTestValue until the PBOOL passsed in arg is FALSE */ static PVOID TestSynchCritical_Test1(PVOID arg) { int i, j, rc; HANDLE hThread = (HANDLE)GetCurrentThreadId(); PBOOL pbContinueRunning = (PBOOL)arg; while(*pbContinueRunning) { EnterCriticalSection(&critical); rc = 1; if (!TestSynchCritical_TriggerAndCheckRaceCondition(hThread, rc)) return (PVOID)1; /* add some random recursion level */ j = rand()%5; for (i=0; i 1) dwSpinCountExpected = dwSpinCount+1; #endif if (dwPreviousSpinCount != dwSpinCountExpected) { printf("CriticalSection failure: SetCriticalSectionSpinCount returned %lu (expected: %lu)\n", dwPreviousSpinCount, dwSpinCountExpected); goto fail; } DeleteCriticalSection(&critical); if (dwSpinCount%2==0) InitializeCriticalSectionAndSpinCount(&critical, dwSpinCount); else InitializeCriticalSectionEx(&critical, dwSpinCount, 0); } DeleteCriticalSection(&critical); /** * Test single-threaded recursive TryEnterCriticalSection/EnterCriticalSection/LeaveCriticalSection * */ InitializeCriticalSection(&critical); for (i=0; i<1000; i++) { if (critical.RecursionCount != i) { printf("CriticalSection failure: RecursionCount field is %ld instead of %d.\n", critical.RecursionCount, i); goto fail; } if (i%2==0) { EnterCriticalSection(&critical); } else { if (TryEnterCriticalSection(&critical) == FALSE) { printf("CriticalSection failure: TryEnterCriticalSection failed where it should not.\n"); goto fail; } } if (critical.OwningThread != hMainThread) { printf("CriticalSection failure: Could not verify section ownership (loop index=%d).\n", i); goto fail; } } while (--i >= 0) { LeaveCriticalSection(&critical); if (critical.RecursionCount != i) { printf("CriticalSection failure: RecursionCount field is %ld instead of %d.\n", critical.RecursionCount, i); goto fail; } if (critical.OwningThread != (HANDLE)(i ? hMainThread : NULL)) { printf("CriticalSection failure: Could not verify section ownership (loop index=%d).\n", i); goto fail; } } DeleteCriticalSection(&critical); /** * Test using multiple threads modifying the same value */ dwThreadCount = sysinfo.dwNumberOfProcessors > 1 ? sysinfo.dwNumberOfProcessors : 2; hThreads = (HANDLE*)calloc(dwThreadCount, sizeof(HANDLE)); for (j=0; j < TEST_SYNC_CRITICAL_TEST1_RUNS; j++) { dwSpinCount = j * 1000; InitializeCriticalSectionAndSpinCount(&critical, dwSpinCount); gTestValueVulnerable = 0; gTestValueSerialized = 0; /* the TestSynchCritical_Test1 threads shall run until bTest1Running is FALSE */ bTest1Running = TRUE; for (i=0; i