blob: 1dba4eb0bdb0006d06faa111854d55a42cdbab01 (
plain) (
blame)
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
128
129
|
#include "mutex.h"
#include "atomic.h"
#include <library/cpp/testing/unittest/registar.h>
#include <util/thread/pool.h>
#include <util/random/random.h>
class TMutexTest: public TTestBase {
UNIT_TEST_SUITE(TMutexTest);
UNIT_TEST(TestBasics)
UNIT_TEST(TestFake)
UNIT_TEST(TestRecursive)
UNIT_TEST_SUITE_END();
struct TSharedData {
TSharedData()
: sharedCounter(0)
, failed(false)
{
}
volatile ui32 sharedCounter;
TMutex mutex;
TFakeMutex fakeMutex;
bool failed;
};
class TThreadTask: public IObjectInQueue {
public:
using PFunc = void (TThreadTask::*)(void);
TThreadTask(PFunc func, TSharedData& data, size_t id)
: Func_(func)
, Data_(data)
, Id_(id)
{
}
void Process(void*) override {
THolder<TThreadTask> This(this);
(this->*Func_)();
}
#define FAIL_ASSERT(cond) \
if (!(cond)) { \
Data_.failed = true; \
}
void RunBasics() {
Data_.mutex.Acquire();
ui32 oldCounter = ui32(Data_.sharedCounter + Id_);
Data_.sharedCounter = oldCounter;
usleep(10 + RandomNumber<ui32>() % 10);
FAIL_ASSERT(Data_.sharedCounter == oldCounter);
Data_.mutex.Release();
}
void RunFakeMutex() {
bool res = Data_.fakeMutex.TryAcquire();
FAIL_ASSERT(res);
}
void RunRecursiveMutex() {
for (size_t i = 0; i < Id_ + 1; ++i) {
Data_.mutex.Acquire();
++Data_.sharedCounter;
usleep(1);
}
FAIL_ASSERT(Data_.sharedCounter == Id_ + 1);
bool res = Data_.mutex.TryAcquire();
FAIL_ASSERT(res);
Data_.mutex.Release();
for (size_t i = 0; i < Id_; ++i) {
--Data_.sharedCounter;
Data_.mutex.Release();
}
FAIL_ASSERT(Data_.sharedCounter == 1);
--Data_.sharedCounter;
Data_.mutex.Release();
}
#undef FAIL_ASSERT
private:
PFunc Func_;
TSharedData& Data_;
size_t Id_;
};
private:
#define RUN_CYCLE(what, count) \
Q_.Start(count); \
for (size_t i = 0; i < count; ++i) { \
UNIT_ASSERT(Q_.Add(new TThreadTask(&TThreadTask::what, Data_, i))); \
} \
Q_.Stop(); \
bool b = Data_.failed; \
Data_.failed = false; \
UNIT_ASSERT(!b);
void TestBasics() {
RUN_CYCLE(RunBasics, 5);
UNIT_ASSERT(Data_.sharedCounter == 10);
Data_.sharedCounter = 0;
}
void TestFake() {
RUN_CYCLE(RunFakeMutex, 3);
}
void TestRecursive() {
RUN_CYCLE(RunRecursiveMutex, 4);
}
#undef RUN_CYCLE
private:
TSharedData Data_;
TThreadPool Q_;
};
UNIT_TEST_SUITE_REGISTRATION(TMutexTest)
|