1*2f083884Ss.makeev_local // The MIT License (MIT)
2*2f083884Ss.makeev_local //
3*2f083884Ss.makeev_local // 	Copyright (c) 2015 Sergey Makeev, Vadim Slyusarev
4*2f083884Ss.makeev_local //
5*2f083884Ss.makeev_local // 	Permission is hereby granted, free of charge, to any person obtaining a copy
6*2f083884Ss.makeev_local // 	of this software and associated documentation files (the "Software"), to deal
7*2f083884Ss.makeev_local // 	in the Software without restriction, including without limitation the rights
8*2f083884Ss.makeev_local // 	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9*2f083884Ss.makeev_local // 	copies of the Software, and to permit persons to whom the Software is
10*2f083884Ss.makeev_local // 	furnished to do so, subject to the following conditions:
11*2f083884Ss.makeev_local //
12*2f083884Ss.makeev_local //  The above copyright notice and this permission notice shall be included in
13*2f083884Ss.makeev_local // 	all copies or substantial portions of the Software.
14*2f083884Ss.makeev_local //
15*2f083884Ss.makeev_local // 	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*2f083884Ss.makeev_local // 	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*2f083884Ss.makeev_local // 	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18*2f083884Ss.makeev_local // 	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19*2f083884Ss.makeev_local // 	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20*2f083884Ss.makeev_local // 	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21*2f083884Ss.makeev_local // 	THE SOFTWARE.
22*2f083884Ss.makeev_local 
23*2f083884Ss.makeev_local #include "Tests.h"
24*2f083884Ss.makeev_local #include <UnitTest++.h>
25*2f083884Ss.makeev_local #include <MTScheduler.h>
26*2f083884Ss.makeev_local 
27*2f083884Ss.makeev_local SUITE(PlatformTests)
28*2f083884Ss.makeev_local {
29*2f083884Ss.makeev_local 	static const intptr_t DATA_VALUE = 13;
30*2f083884Ss.makeev_local 
31*2f083884Ss.makeev_local 	intptr_t g_Variable = 0;
32*2f083884Ss.makeev_local 
33*2f083884Ss.makeev_local 	void MyThreadFunc(void* userData)
34*2f083884Ss.makeev_local 	{
35*2f083884Ss.makeev_local 		intptr_t data = (intptr_t)userData;
36*2f083884Ss.makeev_local 
37*2f083884Ss.makeev_local 		CHECK(data == DATA_VALUE);
38*2f083884Ss.makeev_local 
39*2f083884Ss.makeev_local 		g_Variable = data;
40*2f083884Ss.makeev_local 	}
41*2f083884Ss.makeev_local 
42*2f083884Ss.makeev_local 	TEST(ThreadTest)
43*2f083884Ss.makeev_local 	{
44*2f083884Ss.makeev_local 		intptr_t data = DATA_VALUE;
45*2f083884Ss.makeev_local 
46*2f083884Ss.makeev_local 		MT::Thread thread;
47*2f083884Ss.makeev_local 		thread.Start(32768, MyThreadFunc, (void*)data);
48*2f083884Ss.makeev_local 		thread.Join();
49*2f083884Ss.makeev_local 
50*2f083884Ss.makeev_local 		CHECK(g_Variable == DATA_VALUE);
51*2f083884Ss.makeev_local 	}
52*2f083884Ss.makeev_local 	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
53*2f083884Ss.makeev_local 
54*2f083884Ss.makeev_local 	MT::Event *pEvent1 = nullptr;
55*2f083884Ss.makeev_local 	MT::Event *pEvent2 = nullptr;
56*2f083884Ss.makeev_local 
57*2f083884Ss.makeev_local 	void MyThreadFunc2(void*)
58*2f083884Ss.makeev_local 	{
59*2f083884Ss.makeev_local 		MT::Thread::SpinSleepMilliSeconds(300);
60*2f083884Ss.makeev_local 		pEvent1->Signal();
61*2f083884Ss.makeev_local 	}
62*2f083884Ss.makeev_local 
63*2f083884Ss.makeev_local 	TEST(EventTest)
64*2f083884Ss.makeev_local 	{
65*2f083884Ss.makeev_local 		MT::Event event1;
66*2f083884Ss.makeev_local 		event1.Create(MT::EventReset::MANUAL, false);
67*2f083884Ss.makeev_local 		pEvent1 = &event1;
68*2f083884Ss.makeev_local 
69*2f083884Ss.makeev_local 		MT::Event event2;
70*2f083884Ss.makeev_local 		event2.Create(MT::EventReset::AUTOMATIC, false);
71*2f083884Ss.makeev_local 		pEvent2 = &event2;
72*2f083884Ss.makeev_local 
73*2f083884Ss.makeev_local 		MT::Thread thread;
74*2f083884Ss.makeev_local 		thread.Start(32768, MyThreadFunc2, nullptr);
75*2f083884Ss.makeev_local 
76*2f083884Ss.makeev_local 		bool res0 = event1.Wait(100);
77*2f083884Ss.makeev_local 		bool res1 = event1.Wait(1000);
78*2f083884Ss.makeev_local 		bool res2 = event1.Wait(1000);
79*2f083884Ss.makeev_local 		event1.Reset();
80*2f083884Ss.makeev_local 		bool res3 = event1.Wait(100);
81*2f083884Ss.makeev_local 
82*2f083884Ss.makeev_local 		CHECK(!res0);
83*2f083884Ss.makeev_local 		CHECK(res1);
84*2f083884Ss.makeev_local 		CHECK(res2);
85*2f083884Ss.makeev_local 		CHECK(!res3);
86*2f083884Ss.makeev_local 
87*2f083884Ss.makeev_local 		bool res4 = event2.Wait(100);
88*2f083884Ss.makeev_local 		CHECK(!res4);
89*2f083884Ss.makeev_local 		bool res5 = event2.Wait(100);
90*2f083884Ss.makeev_local 		CHECK(!res5);
91*2f083884Ss.makeev_local 		bool res6 = event2.Wait(100);
92*2f083884Ss.makeev_local 		CHECK(!res6);
93*2f083884Ss.makeev_local 
94*2f083884Ss.makeev_local 		thread.Join();
95*2f083884Ss.makeev_local 	}
96*2f083884Ss.makeev_local 
97*2f083884Ss.makeev_local 
98*2f083884Ss.makeev_local 
99*2f083884Ss.makeev_local 	MT::AtomicPtrBase<MT::Event> pStressEvent = { nullptr };
100*2f083884Ss.makeev_local 	MT::Atomic32Base<uint32> needExitSignal = { 0 };
101*2f083884Ss.makeev_local 	MT::Atomic32Base<uint32> needExitWait = { 0 };
102*2f083884Ss.makeev_local 
103*2f083884Ss.makeev_local 	void EventStressTestSignalThreadFunc(void*)
104*2f083884Ss.makeev_local 	{
105*2f083884Ss.makeev_local 		while (needExitSignal.Load() == 0)
106*2f083884Ss.makeev_local 		{
107*2f083884Ss.makeev_local 			MT::Thread::SpinSleepMicroSeconds(50);
108*2f083884Ss.makeev_local 			MT::Event * pEvent = pStressEvent.Load();
109*2f083884Ss.makeev_local 			pEvent->Signal();
110*2f083884Ss.makeev_local 		}
111*2f083884Ss.makeev_local 	}
112*2f083884Ss.makeev_local 
113*2f083884Ss.makeev_local 	void EventStressTestWaitThreadFunc(void*)
114*2f083884Ss.makeev_local 	{
115*2f083884Ss.makeev_local 		while (needExitWait.Load() == 0)
116*2f083884Ss.makeev_local 		{
117*2f083884Ss.makeev_local 			MT::Event * pEvent = pStressEvent.Load();
118*2f083884Ss.makeev_local 			bool res = pEvent->Wait(100);
119*2f083884Ss.makeev_local 			CHECK(res == true);
120*2f083884Ss.makeev_local 		}
121*2f083884Ss.makeev_local 	}
122*2f083884Ss.makeev_local 
123*2f083884Ss.makeev_local 
124*2f083884Ss.makeev_local 
125*2f083884Ss.makeev_local 
126*2f083884Ss.makeev_local 	TEST(EventStressTest)
127*2f083884Ss.makeev_local 	{
128*2f083884Ss.makeev_local 		MT::Event stressEvent;
129*2f083884Ss.makeev_local 		stressEvent.Create(MT::EventReset::AUTOMATIC, false);
130*2f083884Ss.makeev_local 		pStressEvent.Store( &stressEvent );
131*2f083884Ss.makeev_local 
132*2f083884Ss.makeev_local 		needExitSignal.Store(0);
133*2f083884Ss.makeev_local 		needExitWait.Store(0);
134*2f083884Ss.makeev_local 
135*2f083884Ss.makeev_local 		MT::Thread signalThreads[6];
136*2f083884Ss.makeev_local 		for(uint32 i = 0; i < MT_ARRAY_SIZE(signalThreads); i++)
137*2f083884Ss.makeev_local 		{
138*2f083884Ss.makeev_local 			signalThreads[i].Start(32768, EventStressTestSignalThreadFunc, nullptr);
139*2f083884Ss.makeev_local 		}
140*2f083884Ss.makeev_local 
141*2f083884Ss.makeev_local 		MT::Thread waitThreads[2];
142*2f083884Ss.makeev_local 		for(uint32 i = 0; i < MT_ARRAY_SIZE(waitThreads); i++)
143*2f083884Ss.makeev_local 		{
144*2f083884Ss.makeev_local 			waitThreads[i].Start(32768, EventStressTestWaitThreadFunc, nullptr);
145*2f083884Ss.makeev_local 		}
146*2f083884Ss.makeev_local 
147*2f083884Ss.makeev_local 
148*2f083884Ss.makeev_local 
149*2f083884Ss.makeev_local 		int64 startTime = MT::GetTimeMicroSeconds();
150*2f083884Ss.makeev_local 
151*2f083884Ss.makeev_local 		const int iterationsCount = 5000;
152*2f083884Ss.makeev_local 		for(int i = 0; i < iterationsCount; i++)
153*2f083884Ss.makeev_local 		{
154*2f083884Ss.makeev_local 			bool res = stressEvent.Wait(100);
155*2f083884Ss.makeev_local 			CHECK(res == true);
156*2f083884Ss.makeev_local 		}
157*2f083884Ss.makeev_local 
158*2f083884Ss.makeev_local 		int64 endTime = MT::GetTimeMicroSeconds();
159*2f083884Ss.makeev_local 
160*2f083884Ss.makeev_local 		int microSecondsPerWait = (int)((endTime - startTime) / (int64)iterationsCount);
161*2f083884Ss.makeev_local 
162*2f083884Ss.makeev_local 		printf("microseconds per wait = %d iterations(%d)\n", microSecondsPerWait, iterationsCount);
163*2f083884Ss.makeev_local 
164*2f083884Ss.makeev_local 		needExitWait.Store(1);
165*2f083884Ss.makeev_local 		for(uint32 i = 0; i < MT_ARRAY_SIZE(waitThreads); i++)
166*2f083884Ss.makeev_local 		{
167*2f083884Ss.makeev_local 			waitThreads[i].Join();
168*2f083884Ss.makeev_local 		}
169*2f083884Ss.makeev_local 
170*2f083884Ss.makeev_local 		MT::Thread::Sleep(100);
171*2f083884Ss.makeev_local 
172*2f083884Ss.makeev_local 		needExitSignal.Store(1);
173*2f083884Ss.makeev_local 		for(uint32 i = 0; i < MT_ARRAY_SIZE(signalThreads); i++)
174*2f083884Ss.makeev_local 		{
175*2f083884Ss.makeev_local 			signalThreads[i].Join();
176*2f083884Ss.makeev_local 		}
177*2f083884Ss.makeev_local 
178*2f083884Ss.makeev_local 		bool res = stressEvent.Wait(300);
179*2f083884Ss.makeev_local 		CHECK(res == true);
180*2f083884Ss.makeev_local 
181*2f083884Ss.makeev_local 		res = stressEvent.Wait(300);
182*2f083884Ss.makeev_local 		CHECK(res == false);
183*2f083884Ss.makeev_local 
184*2f083884Ss.makeev_local 
185*2f083884Ss.makeev_local 	}
186*2f083884Ss.makeev_local 
187*2f083884Ss.makeev_local 
188*2f083884Ss.makeev_local 	TEST(SleepTest)
189*2f083884Ss.makeev_local 	{
190*2f083884Ss.makeev_local 
191*2f083884Ss.makeev_local 		MT::Timer timer;
192*2f083884Ss.makeev_local 
193*2f083884Ss.makeev_local 		MT::Thread::SpinSleepMilliSeconds(100);
194*2f083884Ss.makeev_local 
195*2f083884Ss.makeev_local 		CHECK( timer.GetPastMilliSeconds() >= 100 );
196*2f083884Ss.makeev_local 	}
197*2f083884Ss.makeev_local 	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
198*2f083884Ss.makeev_local }
199