JD2022-TU1/main/unittests/core/system/Synchronize.cpp

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);
}
}