1//
2// MutexTest.cpp
3//
4// Copyright (c) 2007, Applied Informatics Software Engineering GmbH.
5// and Contributors.
6//
7// SPDX-License-Identifier: BSL-1.0
8//
9
10
11#include "MutexTest.h"
12#include "Poco/CppUnit/TestCaller.h"
13#include "Poco/CppUnit/TestSuite.h"
14#include "Poco/Exception.h"
15#include "Poco/Mutex.h"
16#include "Poco/Runnable.h"
17#include "Poco/Thread.h"
18#include "Poco/Timestamp.h"
19
20
21using Poco::Mutex;
22using Poco::SpinlockMutex;
23using Poco::Runnable;
24using Poco::SystemException;
25using Poco::Thread;
26using Poco::Timestamp;
27
28namespace
29{
30 class SelfDeadlockRunnable: public Runnable
31 {
32 public:
33 SelfDeadlockRunnable():
34 _ran(false)
35 {
36 }
37
38 void run()
39 {
40 try
41 {
42 Mutex mtx(Mutex::MUTEX_NONRECURSIVE);
43 mtx.lock();
44 mtx.lock();
45 }
46 catch (...)
47 {
48 }
49
50 _ran = true;
51 }
52
53 bool ran() const
54 {
55 return _ran;
56 }
57
58 private:
59 bool _ran;
60 };
61
62 class SpinlockRunnable: public Runnable
63 {
64 public:
65 SpinlockRunnable(): _ran(false)
66 {
67 }
68
69 void run()
70 {
71 try
72 {
73 _mtx.lock();
74 _mtx.lock();
75 }
76 catch (...)
77 {
78 }
79
80 _ran = true;
81 }
82
83 void unlock()
84 {
85 _mtx.unlock();
86 }
87
88 bool ran() const
89 {
90 return _ran;
91 }
92
93 private:
94 SpinlockMutex _mtx;
95 bool _ran;
96 };
97}
98
99
100MutexTest::MutexTest(const std::string& rName): CppUnit::TestCase(rName)
101{
102}
103
104
105MutexTest::~MutexTest()
106{
107}
108
109
110void MutexTest::testMutexRecursion()
111{
112 Mutex mtx(Mutex::MUTEX_NONRECURSIVE);
113 mtx.lock();
114
115 bool success = mtx.tryLock();
116 assertTrue (!success);
117
118 Timestamp mark;
119 success = mtx.tryLock(2000); // Wait 2 seconds
120 assertTrue (!success);
121
122 // Test that we waited approx. 2 sec
123 Timestamp::TimeDiff elapsed = mark.elapsed();
124 assertTrue (elapsed > 1000000);
125 assertTrue (elapsed < 3000000);
126
127 success = mtx.tryLock(0);
128 assertTrue (!success);
129
130 SelfDeadlockRunnable r;
131 Thread t;
132
133 t.start(r);
134 success = t.tryJoin(2000);
135 assertTrue (!success);
136 assertTrue (!r.ran());
137}
138
139
140void MutexTest::testRecursiveMutexRecursion()
141{
142 Mutex mtx;
143 mtx.lock();
144
145 bool success = mtx.tryLock();
146 assertTrue (success);
147
148 Timestamp mark;
149 success = mtx.tryLock(2000); // Wait 2 seconds
150 assertTrue (success);
151
152 // Test that we completed almost immediately
153 Timestamp::TimeDiff elapsed = mark.elapsed();
154 assertTrue (elapsed < 100000);
155
156 success = mtx.tryLock(0);
157 assertTrue (success);
158}
159
160
161void MutexTest::testSpinlockMutex()
162{
163 SpinlockMutex mtx;
164 mtx.lock();
165
166 bool success = mtx.tryLock();
167 assertTrue (!success);
168
169 Timestamp mark;
170 success = mtx.tryLock(2000); // Wait 2 seconds
171 assertTrue (!success);
172
173 // Test that we waited approx. 2 sec
174 Timestamp::TimeDiff elapsed = mark.elapsed();
175 assertTrue (elapsed > 1000000);
176 assertTrue (elapsed < 3000000);
177
178 success = mtx.tryLock(0);
179 assertTrue (!success);
180
181 mtx.unlock();
182 assertTrue (mtx.tryLock());
183
184 SpinlockRunnable r;
185 Thread t;
186
187 t.start(r);
188 success = t.tryJoin(2000);
189 assertTrue (!success);
190 assertTrue (!r.ran());
191 r.unlock();
192 Thread::sleep(10);
193 assertTrue (r.ran());
194 t.join();
195}
196
197
198void MutexTest::setUp()
199{
200}
201
202
203void MutexTest::tearDown()
204{
205}
206
207
208CppUnit::Test* MutexTest::suite()
209{
210 CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("MutexTest");
211
212 CppUnit_addTest(pSuite, MutexTest, testMutexRecursion);
213 CppUnit_addTest(pSuite, MutexTest, testRecursiveMutexRecursion);
214 CppUnit_addTest(pSuite, MutexTest, testSpinlockMutex);
215
216 return pSuite;
217}
218