-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathUnitTestConditionVariable.cpp
127 lines (104 loc) · 3.22 KB
/
UnitTestConditionVariable.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#include "mg/common/Atomic.h"
#include "mg/common/ConditionVariable.h"
#include "mg/common/ThreadFunc.h"
#include "UnitTest.h"
#define UNIT_TEST_CONDVAR_TIMEOUT 10000
namespace mg {
namespace unittests {
// The tests require some synchronization between threads to
// make the tests stable and reproducible. And it should not
// be cond vars, since they are being tested here. This is a
// simple ping-pong a couple of functions to sync threads
// using only CPU means.
static inline void
UnitTestCondVarSend(
mg::common::AtomicU32& aCounter,
uint32_t& aOutNextCounter)
{
aOutNextCounter = aCounter.IncrementFetchRelaxed() + 1;
}
static inline void
UnitTestCondVarReceive(
mg::common::AtomicU32& aCounter,
uint32_t& aNextCounter)
{
while (aCounter.LoadRelaxed() != aNextCounter)
continue;
++aNextCounter;
}
static void
UnitTestConditionVariableBasic()
{
mg::common::ConditionVariable var;
mg::common::Mutex mutex;
mg::common::AtomicU32 stepCounter(0);
uint32_t next = 0;
mg::common::ThreadFunc worker([&]() {
uint32_t workerNext = 1;
// Test that simple lock/unlock work correct.
UnitTestCondVarReceive(stepCounter, workerNext);
mutex.Lock();
UnitTestCondVarSend(stepCounter, workerNext);
var.Wait(mutex);
MG_COMMON_ASSERT(mutex.IsOwnedByThisThread());
mutex.Unlock();
mutex.Lock();
UnitTestCondVarSend(stepCounter, workerNext);
// Test that timed wait correctly returns a timeout
// error.
UnitTestCondVarReceive(stepCounter, workerNext);
bool isTimedOut = false;
var.TimedWait(mutex, 100, &isTimedOut);
MG_COMMON_ASSERT(isTimedOut);
MG_COMMON_ASSERT(mutex.IsOwnedByThisThread());
UnitTestCondVarSend(stepCounter, workerNext);
// Test that timed wait does not set the flag if
// there was no a timeout.
UnitTestCondVarReceive(stepCounter, workerNext);
UnitTestCondVarSend(stepCounter, workerNext);
// Wait signal.
var.TimedWait(mutex, UNIT_TEST_CONDVAR_TIMEOUT, &isTimedOut);
MG_COMMON_ASSERT(!isTimedOut);
MG_COMMON_ASSERT(mutex.IsOwnedByThisThread());
UnitTestCondVarReceive(stepCounter, workerNext);
UnitTestCondVarSend(stepCounter, workerNext);
// Wait broadcast.
var.TimedWait(mutex, UNIT_TEST_CONDVAR_TIMEOUT, &isTimedOut);
MG_COMMON_ASSERT(!isTimedOut);
MG_COMMON_ASSERT(mutex.IsOwnedByThisThread());
mutex.Unlock();
});
worker.Start();
// Test that simple lock/unlock work correct.
UnitTestCondVarSend(stepCounter, next);
UnitTestCondVarReceive(stepCounter, next);
mutex.Lock();
var.Signal();
mutex.Unlock();
UnitTestCondVarReceive(stepCounter, next);
// Test that timed wait correctly returns a timeout
// error.
UnitTestCondVarSend(stepCounter, next);
UnitTestCondVarReceive(stepCounter, next);
// Test that timed wait does not set the flag if
// was no a timeout.
UnitTestCondVarSend(stepCounter, next);
UnitTestCondVarReceive(stepCounter, next);
mutex.Lock();
var.Signal();
mutex.Unlock();
UnitTestCondVarSend(stepCounter, next);
UnitTestCondVarReceive(stepCounter, next);
mutex.Lock();
var.Broadcast();
mutex.Unlock();
worker.BlockingStop();
}
void
UnitTestConditionVariable()
{
TestSuiteGuard suite("ConditionVariable");
UnitTestConditionVariableBasic();
}
}
}