/* Test-ZConcurrency.cpp Author: Patrick Baggett Purpose : Unit tests for ZConcurrency implementation to ensure correct behavior Changelog : 12/18/2011 - Removed dependency on ZString (crertel) 5/15/2011 - Created (ptbaggett) */ #include "ZUnitTest.hpp" #include #include #include static const char* testCreateThread(); static const char* testSleepGetTicks(); static const char* testUncontLockUnlockMutex(); static const char* testContLockUnlockMutex(); static const char* testUncontSema(); static const char* testContSema(); #define NRTHR 16 #define NRITER 10000 //List of unit tests ZUnitTest ZConcurrencyUnitTests[] = { { "CreateThread()/WaitThread()", testCreateThread }, { "Sleep()/GetTicks()", testSleepGetTicks }, { "Uncontested LockMutex()/UnlockMutex()", testUncontLockUnlockMutex }, { "Heavily contested LockMutex/UnlockMutex()", testContLockUnlockMutex }, { "Uncontested Semaphore", testUncontSema }, { "Heavily contested Semaphore", testContSema } }; DECLARE_ZTESTBLOCK(ZConcurrency); /*************************************************************************/ static const char* testThread1Data; static int testThread1(void* arg) { unsigned int* val = (unsigned int*)arg; if(*val == 0xAABBCCDD) testThread1Data = ZTEST_SUCCESS; else testThread1Data = "Error with CreateThread()'s argument passing"; return 0x11223344; } static const char* testCreateThread() { ZThreadContext ctx; int arg = 0xAABBCCDD; ctx = ZConcurrency::CreateThread(testThread1, &arg); TASSERT(ctx.IsValid(), "CreateThread() returned invalid thread context"); ZConcurrency::WaitThread(ctx); int thrRetVal = ctx.ThreadExitStatus; TASSERT(thrRetVal == 0x11223344, "WaitThread() returned wrong value"); ZConcurrency::DestroyThread(ctx); TASSERT(!ctx.IsValid(), "ZThreadContext is valid after DestroyThread()"); return testThread1Data; } /*************************************************************************/ static const char* testSleepGetTicks() { uint64_t timeStart, timeEnd; timeStart = ZConcurrency::GetTicks(); ZConcurrency::SleepThread(1000); timeEnd = ZConcurrency::GetTicks(); TASSERT(timeStart < timeEnd, "GetTicks() not monotonically increasing"); //We can't require precisely 1,000ms, but we do require it as a lower bound TASSERT(timeEnd - timeStart >= 1000, "GetTicks() reports < 1000ms elapsed, but SleepThread(1000) called."); return ZTEST_SUCCESS; } /*************************************************************************/ static const char* testUncontLockUnlockMutex() { //Basically, if this crashes, then FAIL ZMutex lock; //TASSERT(lock != NULL, "CreateMutex() returned null pointer"); //Lock/unlock a bunch. This should be fast since it is uncontested. //Mainly, we're checking here to see if lock/unlock repeatedly triggers a crash for(int i=0; i<1000; i++) { lock.Acquire(); lock.Release(); } return ZTEST_SUCCESS; } /*************************************************************************/ static ZMutex testContLock; static int testContFunc(void* arg) { int* inc = (int*) arg; for(int i=0; i static int testContSemaFunc(void* arg) { ZSemaphore* sem = (ZSemaphore*)arg; bool ok; do { ok = sem->Wait(0); if (ok) { testContSemaLock.Acquire(); testContSemaCounter++; testContSemaLock.Release(); } } while(ok); return 0; } static const char* testContSema() { ZThreadContext thread[NRTHR]; //sem = ZConcurrency::CreateSemaphore(NRITER); //testContSemaLock = ZConcurrency::CreateMutex(); //Run 50 batches of this test just in case there might be a race condition for(int j = 0; j < 50; j++) { ZSemaphore sem(NRITER); testContSemaCounter = 0; //Create a bunch of threads. for(int i=0; i