1//
2// ThreadTest.cpp
3//
4// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
5// and Contributors.
6//
7// SPDX-License-Identifier: BSL-1.0
8//
9
10
11#include "ThreadTest.h"
12#include "Poco/CppUnit/TestCaller.h"
13#include "Poco/CppUnit/TestSuite.h"
14#include "Poco/Thread.h"
15#include "Poco/Runnable.h"
16#include "Poco/ThreadTarget.h"
17#include "Poco/Event.h"
18#include "Poco/Timestamp.h"
19#include "Poco/Timespan.h"
20#include "Poco/Environment.h"
21#if defined(__sun) && defined(__SVR4) && !defined(__EXTENSIONS__)
22#define __EXTENSIONS__
23#endif
24#include <climits>
25#include <vector>
26#include <sstream>
27
28using Poco::Thread;
29using Poco::Runnable;
30using Poco::ThreadTarget;
31using Poco::Event;
32
33
34class MyRunnable: public Runnable
35{
36public:
37 MyRunnable(): _ran(false)
38 {
39 }
40
41 void run()
42 {
43 Thread* pThread = Thread::current();
44 if (pThread)
45 _threadName = pThread->name();
46 _ran = true;
47 _event.wait();
48 }
49
50 bool ran() const
51 {
52 return _ran;
53 }
54
55 const std::string& threadName() const
56 {
57 return _threadName;
58 }
59
60 void notify()
61 {
62 _event.set();
63 }
64
65 static void staticFunc()
66 {
67 ++_staticVar;
68 }
69
70 static int _staticVar;
71
72private:
73 bool _ran;
74 std::string _threadName;
75 Event _event;
76};
77
78
79int MyRunnable::_staticVar = 0;
80
81
82void freeFunc()
83{
84 ++MyRunnable::_staticVar;
85}
86
87
88void freeFunc(void* pData)
89{
90 MyRunnable::_staticVar += *reinterpret_cast<int*>(pData);
91}
92
93
94class NonJoinRunnable : public Runnable
95{
96public:
97 NonJoinRunnable() : _finished(false)
98 {
99 }
100
101 void run()
102 {
103 _finished = true;
104 }
105
106 bool finished() const
107 {
108 return _finished;
109 }
110
111private:
112 bool _finished;
113};
114
115
116class TrySleepRunnable : public Runnable
117{
118public:
119 TrySleepRunnable() : _counter(0), _sleepy(true)
120 {
121 }
122
123 void run()
124 {
125 _sleepy = !Thread::trySleep(300000);
126 ++_counter;
127 _sleepy = !Thread::trySleep(300000);
128 ++_counter;
129 _sleepy = !Thread::trySleep(100);
130 ++_counter;
131 }
132
133 int counter() const
134 {
135 return _counter;
136 }
137
138 bool isSleepy() const
139 {
140 return _sleepy;
141 }
142
143private:
144 int _counter;
145 bool _sleepy;
146};
147
148
149ThreadTest::ThreadTest(const std::string& rName): CppUnit::TestCase(rName)
150{
151}
152
153
154ThreadTest::~ThreadTest()
155{
156}
157
158
159void ThreadTest::testThread()
160{
161 Thread thread;
162 MyRunnable r;
163 assertTrue (!thread.isRunning());
164 thread.start(r);
165 Thread::sleep(200);
166 assertTrue (thread.isRunning());
167 r.notify();
168 thread.join();
169 assertTrue (!thread.isRunning());
170 assertTrue (r.ran());
171 assertTrue (!r.threadName().empty());
172}
173
174
175void ThreadTest::testNamedThread()
176{
177 Thread thread("MyThread");
178 MyRunnable r;
179 thread.start(r);
180 r.notify();
181 thread.join();
182 assertTrue (r.ran());
183 assertTrue (r.threadName() == "MyThread");
184}
185
186
187void ThreadTest::testCurrent()
188{
189 assertNullPtr (Thread::current());
190}
191
192
193void ThreadTest::testThreads()
194{
195 Thread thread1("Thread1");
196 Thread thread2("Thread2");
197 Thread thread3("Thread3");
198 Thread thread4("Thread4");
199
200 MyRunnable r1;
201 MyRunnable r2;
202 MyRunnable r3;
203 MyRunnable r4;
204 assertTrue (!thread1.isRunning());
205 assertTrue (!thread2.isRunning());
206 assertTrue (!thread3.isRunning());
207 assertTrue (!thread4.isRunning());
208 thread1.start(r1);
209 Thread::sleep(200);
210 assertTrue (thread1.isRunning());
211 assertTrue (!thread2.isRunning());
212 assertTrue (!thread3.isRunning());
213 assertTrue (!thread4.isRunning());
214 thread2.start(r2);
215 thread3.start(r3);
216 thread4.start(r4);
217 Thread::sleep(200);
218 assertTrue (thread1.isRunning());
219 assertTrue (thread2.isRunning());
220 assertTrue (thread3.isRunning());
221 assertTrue (thread4.isRunning());
222 r4.notify();
223 thread4.join();
224 assertTrue (!thread4.isRunning());
225 assertTrue (thread1.isRunning());
226 assertTrue (thread2.isRunning());
227 assertTrue (thread3.isRunning());
228 r3.notify();
229 thread3.join();
230 assertTrue (!thread3.isRunning());
231 r2.notify();
232 thread2.join();
233 assertTrue (!thread2.isRunning());
234 r1.notify();
235 thread1.join();
236 assertTrue (!thread1.isRunning());
237 assertTrue (r1.ran());
238 assertTrue (r1.threadName() == "Thread1");
239 assertTrue (r2.ran());
240 assertTrue (r2.threadName() == "Thread2");
241 assertTrue (r3.ran());
242 assertTrue (r3.threadName() == "Thread3");
243 assertTrue (r4.ran());
244 assertTrue (r4.threadName() == "Thread4");
245}
246
247
248void ThreadTest::testJoin()
249{
250 Thread thread;
251 MyRunnable r;
252 assertTrue (!thread.isRunning());
253 thread.start(r);
254 Thread::sleep(200);
255 assertTrue (thread.isRunning());
256 assertTrue (!thread.tryJoin(100));
257 r.notify();
258 assertTrue (thread.tryJoin(500));
259 assertTrue (!thread.isRunning());
260}
261
262
263void ThreadTest::testNotJoin()
264{
265 Thread thread;
266 NonJoinRunnable r;
267 thread.start(r);
268
269 while (!r.finished())
270 {
271 Thread::sleep(10);
272 }
273
274 Thread::sleep(100);
275 assertTrue (!thread.isRunning());
276}
277
278
279void ThreadTest::testTrySleep()
280{
281 Thread thread;
282 TrySleepRunnable r;
283 assertTrue (r.isSleepy());
284 assertTrue (!thread.isRunning());
285 assertTrue (r.counter() == 0);
286 thread.start(r);
287 assertTrue (thread.isRunning());
288 assertTrue (r.counter() == 0);
289 assertTrue (r.isSleepy());
290 Thread::sleep(100);
291 assertTrue (r.counter() == 0);
292 assertTrue (r.isSleepy());
293 thread.wakeUp();
294 Thread::sleep(10);
295 assertTrue (r.counter() == 1);
296 assertTrue (r.isSleepy());
297 Thread::sleep(100);
298 assertTrue (r.counter() == 1);
299 thread.wakeUp();
300 Thread::sleep(10);
301 assertTrue (r.counter() == 2);
302 assertTrue (r.isSleepy());
303 Thread::sleep(200);
304 assertTrue (r.counter() == 3);
305 assertTrue (!r.isSleepy());
306 assertTrue (!thread.isRunning());
307 thread.wakeUp();
308 assertTrue (!thread.isRunning());
309}
310
311
312void ThreadTest::testNotRun()
313{
314 Thread thread;
315}
316
317
318void ThreadTest::testNotRunJoin()
319{
320 Thread thread;
321 thread.join();
322}
323
324
325void ThreadTest::testThreadTarget()
326{
327 ThreadTarget te(&MyRunnable::staticFunc);
328 Thread thread;
329
330 assertTrue (!thread.isRunning());
331
332 int tmp = MyRunnable::_staticVar;
333 thread.start(te);
334 thread.join();
335 assertTrue (tmp + 1 == MyRunnable::_staticVar);
336
337 ThreadTarget te1(freeFunc);
338 assertTrue (!thread.isRunning());
339
340 tmp = MyRunnable::_staticVar;
341 thread.start(te1);
342 thread.join();
343 assertTrue (tmp + 1 == MyRunnable::_staticVar);
344}
345
346
347void ThreadTest::testThreadFunction()
348{
349 Thread thread;
350
351 assertTrue (!thread.isRunning());
352
353 int tmp = MyRunnable::_staticVar;
354 thread.start(freeFunc, &tmp);
355 thread.join();
356 assertTrue (tmp * 2 == MyRunnable::_staticVar);
357
358 assertTrue (!thread.isRunning());
359
360 tmp = MyRunnable::_staticVar = 0;
361 thread.start(freeFunc, &tmp);
362 thread.join();
363 assertTrue (0 == MyRunnable::_staticVar);
364}
365
366
367struct Functor
368{
369 void operator () ()
370 {
371 ++MyRunnable::_staticVar;
372 }
373};
374
375
376void ThreadTest::testThreadFunctor()
377{
378 Thread thread;
379
380 assertTrue (!thread.isRunning());
381
382 MyRunnable::_staticVar = 0;
383 thread.startFunc(Functor());
384 thread.join();
385 assertTrue (1 == MyRunnable::_staticVar);
386
387 assertTrue (!thread.isRunning());
388
389
390 Thread thread2;
391
392 assertTrue (!thread2.isRunning());
393
394 MyRunnable::_staticVar = 0;
395 thread.startFunc([] ()
396 {
397 MyRunnable::_staticVar++;
398 });
399 thread.join();
400 assertTrue (1 == MyRunnable::_staticVar);
401
402 assertTrue (!thread2.isRunning());
403
404}
405
406
407void ThreadTest::testThreadStackSize()
408{
409 int stackSize = 50000000;
410
411 Thread thread;
412
413 assertTrue (0 == thread.getStackSize());
414 thread.setStackSize(stackSize);
415 assertTrue (stackSize <= thread.getStackSize());
416 int tmp = MyRunnable::_staticVar;
417 thread.start(freeFunc, &tmp);
418 thread.join();
419 assertTrue (tmp * 2 == MyRunnable::_staticVar);
420
421 stackSize = 1;
422 thread.setStackSize(stackSize);
423
424#if !defined(POCO_OS_FAMILY_BSD) // on BSD family, stack size is rounded
425 assertTrue (stackSize >= thread.getStackSize());
426#endif
427
428 tmp = MyRunnable::_staticVar;
429 thread.start(freeFunc, &tmp);
430 thread.join();
431 assertTrue (tmp * 2 == MyRunnable::_staticVar);
432
433 thread.setStackSize(0);
434 assertTrue (0 == thread.getStackSize());
435 tmp = MyRunnable::_staticVar;
436 thread.start(freeFunc, &tmp);
437 thread.join();
438 assertTrue (tmp * 2 == MyRunnable::_staticVar);
439}
440
441
442void ThreadTest::testSleep()
443{
444 Poco::Timestamp start;
445 Thread::sleep(200);
446 Poco::Timespan elapsed = start.elapsed();
447 assertTrue (elapsed.totalMilliseconds() >= 190 && elapsed.totalMilliseconds() < 250);
448}
449
450void ThreadTest::testAffinity()
451{
452 std::stringstream ss;
453 unsigned cpuCount = Poco::Environment::processorCount();
454 unsigned usedCpu = 0;
455 std::vector<Thread*> threadList;
456 Thread* thread = NULL;
457 std::vector<MyRunnable*> runnableList;
458 MyRunnable* runbl = NULL;
459
460 for (unsigned i = 0; i < cpuCount; i++)
461 {
462 ss.str("");
463 ss << "Thread" << i;
464 thread = new Thread(ss.str());
465 threadList.push_back(thread);
466 runbl = new MyRunnable();
467 runnableList.push_back(runbl);
468 }
469
470 for (int i = 0; i < cpuCount; i++)
471 {
472 assertTrue (!threadList[i]->isRunning());
473 }
474
475 for (int i = 0; i < cpuCount; i++)
476 {
477 threadList[i]->start(*runnableList[i]);
478 threadList[i]->setAffinity(i);
479 Thread::sleep(100);
480 usedCpu = threadList[i]->getAffinity();
481 assertTrue (usedCpu == i || usedCpu == -1);
482 }
483
484 for (int i = 0; i < cpuCount; i++)
485 {
486 runnableList[i]->notify();
487 threadList[i]->join();
488 delete runnableList[i];
489 delete threadList[i];
490 }
491}
492
493
494void ThreadTest::testJoinNotStarted()
495{
496 Thread thread;
497 thread.join();
498}
499
500
501void ThreadTest::setUp()
502{
503}
504
505
506void ThreadTest::tearDown()
507{
508}
509
510
511CppUnit::Test* ThreadTest::suite()
512{
513 CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("ThreadTest");
514
515 CppUnit_addTest(pSuite, ThreadTest, testThread);
516 CppUnit_addTest(pSuite, ThreadTest, testNamedThread);
517 CppUnit_addTest(pSuite, ThreadTest, testCurrent);
518 CppUnit_addTest(pSuite, ThreadTest, testThreads);
519 CppUnit_addTest(pSuite, ThreadTest, testJoin);
520 CppUnit_addTest(pSuite, ThreadTest, testNotJoin);
521 CppUnit_addTest(pSuite, ThreadTest, testNotRun);
522 CppUnit_addTest(pSuite, ThreadTest, testNotRunJoin);
523 CppUnit_addTest(pSuite, ThreadTest, testTrySleep);
524 CppUnit_addTest(pSuite, ThreadTest, testThreadTarget);
525 CppUnit_addTest(pSuite, ThreadTest, testThreadFunction);
526 CppUnit_addTest(pSuite, ThreadTest, testThreadFunctor);
527 CppUnit_addTest(pSuite, ThreadTest, testThreadStackSize);
528 CppUnit_addTest(pSuite, ThreadTest, testSleep);
529 CppUnit_addTest(pSuite, ThreadTest, testAffinity);
530 CppUnit_addTest(pSuite, ThreadTest, testJoinNotStarted);
531
532 return pSuite;
533}
534