266 lines
7.5 KiB
C++
266 lines
7.5 KiB
C++
#include "precompiled_unittests_core.h"
|
|
|
|
#include "core/system/Synchronize.h"
|
|
|
|
#include "core/system/Thread.h"
|
|
|
|
|
|
namespace ITF
|
|
{
|
|
|
|
namespace
|
|
{
|
|
|
|
struct TestEventThreadParams
|
|
{
|
|
ITF_THREAD_EVENT* m_mainEvent;
|
|
ITF_THREAD_EVENT* m_threadEvent;
|
|
volatile int* m_variable;
|
|
};
|
|
|
|
|
|
u32 WINAPI testEventThreadFunc(void* _param)
|
|
{
|
|
TestEventThreadParams* params = reinterpret_cast<TestEventThreadParams*>(_param);
|
|
|
|
// Set the main event to unlock it
|
|
Synchronize::setEvent(params->m_mainEvent);
|
|
|
|
// Waiting for the main to set my event
|
|
Synchronize::waitEvent(params->m_threadEvent);
|
|
|
|
*params->m_variable = 1;
|
|
|
|
// Set the main event to unlock it again
|
|
Synchronize::setEvent(params->m_mainEvent);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
void testEvent(bbool _autoresetEvents)
|
|
{
|
|
ITF_THREAD_EVENT mainEvent, threadEvent;
|
|
Synchronize::createEvent(&mainEvent, "mainEvent", _autoresetEvents);
|
|
Synchronize::createEvent(&threadEvent, "threadEvent", _autoresetEvents);
|
|
|
|
volatile int variable = 0;
|
|
|
|
TestEventThreadParams testEventParams;
|
|
testEventParams.m_mainEvent = &mainEvent;
|
|
testEventParams.m_threadEvent = &threadEvent;
|
|
testEventParams.m_variable = &variable;
|
|
|
|
ThreadSettings threadSettings;
|
|
threadSettings.m_cpuAffinity = Thread_HardwareThreadId_All;
|
|
|
|
ThreadPtr threadPtr = Thread::create(testEventThreadFunc, &testEventParams, threadSettings);
|
|
|
|
// Waiting for the thread to set my event, and then reset it
|
|
Synchronize::waitEvent(&mainEvent);
|
|
if (!_autoresetEvents)
|
|
{
|
|
Synchronize::resetEvent(&mainEvent);
|
|
}
|
|
|
|
// The variable must be unchanged for the moment
|
|
EXPECT_EQ(variable, 0);
|
|
|
|
// Set the thread event to unlock it
|
|
Synchronize::setEvent(&threadEvent);
|
|
|
|
// Waiting for the thread to set my event again
|
|
Synchronize::waitEvent(&mainEvent);
|
|
|
|
// The variable must have been changed now
|
|
EXPECT_EQ(variable, 1);
|
|
|
|
Synchronize::destroyEvent(&threadEvent);
|
|
Synchronize::destroyEvent(&mainEvent);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
TEST(Synchronize, test_event)
|
|
{
|
|
testEvent(bfalse);
|
|
}
|
|
|
|
|
|
TEST(Synchronize, test_autoresetEvent)
|
|
{
|
|
testEvent(btrue);
|
|
}
|
|
|
|
|
|
namespace
|
|
{
|
|
|
|
struct TestCriticalSectionLockParams
|
|
{
|
|
ITF_THREAD_EVENT* m_readyEvent;
|
|
ITF_THREAD_EVENT* m_startEvent;
|
|
CriticalSection* m_cs;
|
|
volatile int* m_variable;
|
|
};
|
|
|
|
|
|
u32 WINAPI testCriticalSectionLockFunc(void* _param)
|
|
{
|
|
TestCriticalSectionLockParams* params = reinterpret_cast<TestCriticalSectionLockParams*>(_param);
|
|
|
|
Synchronize::setEvent(params->m_readyEvent);
|
|
Synchronize::waitEvent(params->m_startEvent);
|
|
|
|
CriticalSection* cs = params->m_cs;
|
|
|
|
const int nbLoops = 5 * 1000 * 1000;
|
|
|
|
// Increment
|
|
for (int loopInd = 1; loopInd < nbLoops; loopInd++)
|
|
{
|
|
cs->lock();
|
|
*params->m_variable += loopInd;
|
|
cs->unlock();
|
|
}
|
|
|
|
// Decrement
|
|
for (int loopInd = 1; loopInd < nbLoops; loopInd++)
|
|
{
|
|
cs->lock();
|
|
*params->m_variable -= loopInd;
|
|
cs->unlock();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
TEST(Synchronize, test_criticalSectionLock)
|
|
{
|
|
ITF_THREAD_EVENT startEvent;
|
|
Synchronize::createEvent(&startEvent, "startEvent");
|
|
|
|
CriticalSection cs;
|
|
volatile int variable = 0;
|
|
|
|
ThreadPtr threadPtr [2];
|
|
TestCriticalSectionLockParams threadParams [ITF_ARRAY_SIZE(threadPtr)];
|
|
ITF_THREAD_EVENT readyEvents [ITF_ARRAY_SIZE(threadPtr)];
|
|
|
|
for (u32 threadInd = 0; threadInd < ITF_ARRAY_SIZE(threadPtr); threadInd++)
|
|
{
|
|
TestCriticalSectionLockParams* testCriticalSectionParams = &threadParams[threadInd];
|
|
testCriticalSectionParams->m_startEvent = &startEvent;
|
|
testCriticalSectionParams->m_cs = &cs;
|
|
testCriticalSectionParams->m_variable = &variable;
|
|
|
|
Synchronize::createEvent(&readyEvents[threadInd], String8::createTextFormat("readyEvent%u", threadInd).cStr());
|
|
testCriticalSectionParams->m_readyEvent = &readyEvents[threadInd];
|
|
|
|
ThreadSettings threadSettings;
|
|
threadSettings.m_cpuAffinity = Thread_HardwareThreadId_All;
|
|
|
|
threadPtr[threadInd] = Thread::create(testCriticalSectionLockFunc, testCriticalSectionParams, threadSettings);
|
|
}
|
|
|
|
// Wait for all threads to be ready
|
|
for (u32 threadInd = 0; threadInd < ITF_ARRAY_SIZE(threadPtr); threadInd++)
|
|
{
|
|
Synchronize::waitEvent(&readyEvents[threadInd]);
|
|
}
|
|
|
|
// Send the threads the start signal
|
|
Synchronize::setEvent(&startEvent);
|
|
|
|
// Wait for all threads to be done and destroy their associated events
|
|
for (u32 threadInd = 0; threadInd < ITF_ARRAY_SIZE(threadPtr); threadInd++)
|
|
{
|
|
threadPtr[threadInd]->join();
|
|
Synchronize::destroyEvent(&readyEvents[threadInd]);
|
|
}
|
|
|
|
Synchronize::destroyEvent(&startEvent);
|
|
|
|
EXPECT_EQ(variable, 0);
|
|
}
|
|
|
|
|
|
namespace
|
|
{
|
|
|
|
struct TestCriticalSectionTryLockParams
|
|
{
|
|
ITF_THREAD_EVENT* m_testReadyEvent;
|
|
ITF_THREAD_EVENT* m_testDoneEvent;
|
|
CriticalSection* m_cs;
|
|
};
|
|
|
|
|
|
u32 WINAPI testCriticalSectionTryLockFunc(void* _param)
|
|
{
|
|
TestCriticalSectionTryLockParams* params = reinterpret_cast<TestCriticalSectionTryLockParams*>(_param);
|
|
|
|
CriticalSection* cs = params->m_cs;
|
|
|
|
cs->lock();
|
|
Synchronize::setEvent(params->m_testReadyEvent);
|
|
Synchronize::waitEvent(params->m_testDoneEvent);
|
|
|
|
cs->unlock();
|
|
Synchronize::setEvent(params->m_testReadyEvent);
|
|
|
|
return 0;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
TEST(Synchronize, test_criticalSectionTryLock)
|
|
{
|
|
ITF_THREAD_EVENT testReadyEvent, testDoneEvent;
|
|
Synchronize::createEvent(&testReadyEvent, "testReadyEvent", btrue);
|
|
Synchronize::createEvent(&testDoneEvent, "testDoneEvent");
|
|
|
|
CriticalSection cs;
|
|
|
|
TestCriticalSectionTryLockParams threadParams;
|
|
threadParams.m_testReadyEvent = &testReadyEvent;
|
|
threadParams.m_testDoneEvent = &testDoneEvent;
|
|
threadParams.m_cs = &cs;
|
|
|
|
ThreadSettings threadSettings;
|
|
threadSettings.m_cpuAffinity = Thread_HardwareThreadId_All;
|
|
|
|
ThreadPtr threadPtr = Thread::create(testCriticalSectionTryLockFunc, &threadParams, threadSettings);
|
|
|
|
// Wait for the test to be ready
|
|
Synchronize::waitEvent(&testReadyEvent);
|
|
|
|
bool tryLockSucceeded = cs.tryLock();
|
|
EXPECT_FALSE(tryLockSucceeded);
|
|
|
|
// Send the thread the end signal
|
|
Synchronize::setEvent(&testDoneEvent);
|
|
|
|
// Wait for the second test to be ready
|
|
Synchronize::waitEvent(&testReadyEvent);
|
|
|
|
tryLockSucceeded = cs.tryLock();
|
|
EXPECT_TRUE(tryLockSucceeded);
|
|
|
|
if (tryLockSucceeded)
|
|
{
|
|
cs.unlock();
|
|
}
|
|
|
|
threadPtr->join();
|
|
|
|
Synchronize::destroyEvent(&testDoneEvent);
|
|
Synchronize::destroyEvent(&testReadyEvent);
|
|
}
|
|
|
|
}
|