12f083884Ss.makeev_local // The MIT License (MIT)
22f083884Ss.makeev_local //
32f083884Ss.makeev_local // 	Copyright (c) 2015 Sergey Makeev, Vadim Slyusarev
42f083884Ss.makeev_local //
52f083884Ss.makeev_local // 	Permission is hereby granted, free of charge, to any person obtaining a copy
62f083884Ss.makeev_local // 	of this software and associated documentation files (the "Software"), to deal
72f083884Ss.makeev_local // 	in the Software without restriction, including without limitation the rights
82f083884Ss.makeev_local // 	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
92f083884Ss.makeev_local // 	copies of the Software, and to permit persons to whom the Software is
102f083884Ss.makeev_local // 	furnished to do so, subject to the following conditions:
112f083884Ss.makeev_local //
122f083884Ss.makeev_local //  The above copyright notice and this permission notice shall be included in
132f083884Ss.makeev_local // 	all copies or substantial portions of the Software.
142f083884Ss.makeev_local //
152f083884Ss.makeev_local // 	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
162f083884Ss.makeev_local // 	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
172f083884Ss.makeev_local // 	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
182f083884Ss.makeev_local // 	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
192f083884Ss.makeev_local // 	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
202f083884Ss.makeev_local // 	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
212f083884Ss.makeev_local // 	THE SOFTWARE.
222f083884Ss.makeev_local 
232f083884Ss.makeev_local #include "Tests.h"
24*01616bcfSs.makeev_local #include "../Profiler/Profiler.h"
252f083884Ss.makeev_local #include <UnitTest++.h>
262f083884Ss.makeev_local #include <MTScheduler.h>
272f083884Ss.makeev_local 
SUITE(PlatformTests)282f083884Ss.makeev_local SUITE(PlatformTests)
292f083884Ss.makeev_local {
302f083884Ss.makeev_local 	static const intptr_t DATA_VALUE = 13;
312f083884Ss.makeev_local 
322f083884Ss.makeev_local 	intptr_t g_Variable = 0;
332f083884Ss.makeev_local 
342f083884Ss.makeev_local 	void MyThreadFunc(void* userData)
352f083884Ss.makeev_local 	{
362f083884Ss.makeev_local 		intptr_t data = (intptr_t)userData;
372f083884Ss.makeev_local 
382f083884Ss.makeev_local 		CHECK(data == DATA_VALUE);
392f083884Ss.makeev_local 
402f083884Ss.makeev_local 		g_Variable = data;
412f083884Ss.makeev_local 	}
422f083884Ss.makeev_local 
432f083884Ss.makeev_local 	TEST(ThreadTest)
442f083884Ss.makeev_local 	{
452f083884Ss.makeev_local 		intptr_t data = DATA_VALUE;
462f083884Ss.makeev_local 
472f083884Ss.makeev_local 		MT::Thread thread;
482f083884Ss.makeev_local 		thread.Start(32768, MyThreadFunc, (void*)data);
492f083884Ss.makeev_local 		thread.Join();
502f083884Ss.makeev_local 
512f083884Ss.makeev_local 		CHECK(g_Variable == DATA_VALUE);
522f083884Ss.makeev_local 	}
532f083884Ss.makeev_local 	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
542f083884Ss.makeev_local 
552f083884Ss.makeev_local 	MT::Event *pEvent1 = nullptr;
562f083884Ss.makeev_local 	MT::Event *pEvent2 = nullptr;
572f083884Ss.makeev_local 
582f083884Ss.makeev_local 	void MyThreadFunc2(void*)
592f083884Ss.makeev_local 	{
603cb1fd8eSs.makeev_local 		MT::SpinSleepMilliSeconds(300);
612f083884Ss.makeev_local 		pEvent1->Signal();
622f083884Ss.makeev_local 	}
632f083884Ss.makeev_local 
642f083884Ss.makeev_local 	TEST(EventTest)
652f083884Ss.makeev_local 	{
662f083884Ss.makeev_local 		MT::Event event1;
672f083884Ss.makeev_local 		event1.Create(MT::EventReset::MANUAL, false);
682f083884Ss.makeev_local 		pEvent1 = &event1;
692f083884Ss.makeev_local 
702f083884Ss.makeev_local 		MT::Event event2;
712f083884Ss.makeev_local 		event2.Create(MT::EventReset::AUTOMATIC, false);
722f083884Ss.makeev_local 		pEvent2 = &event2;
732f083884Ss.makeev_local 
742f083884Ss.makeev_local 		MT::Thread thread;
752f083884Ss.makeev_local 		thread.Start(32768, MyThreadFunc2, nullptr);
762f083884Ss.makeev_local 
772f083884Ss.makeev_local 		bool res0 = event1.Wait(100);
782f083884Ss.makeev_local 		bool res1 = event1.Wait(1000);
792f083884Ss.makeev_local 		bool res2 = event1.Wait(1000);
802f083884Ss.makeev_local 		event1.Reset();
812f083884Ss.makeev_local 		bool res3 = event1.Wait(100);
822f083884Ss.makeev_local 
832f083884Ss.makeev_local 		CHECK(!res0);
842f083884Ss.makeev_local 		CHECK(res1);
852f083884Ss.makeev_local 		CHECK(res2);
862f083884Ss.makeev_local 		CHECK(!res3);
872f083884Ss.makeev_local 
882f083884Ss.makeev_local 		bool res4 = event2.Wait(100);
892f083884Ss.makeev_local 		CHECK(!res4);
902f083884Ss.makeev_local 		bool res5 = event2.Wait(100);
912f083884Ss.makeev_local 		CHECK(!res5);
922f083884Ss.makeev_local 		bool res6 = event2.Wait(100);
932f083884Ss.makeev_local 		CHECK(!res6);
942f083884Ss.makeev_local 
952f083884Ss.makeev_local 		thread.Join();
962f083884Ss.makeev_local 	}
972f083884Ss.makeev_local 
982f083884Ss.makeev_local 
992f083884Ss.makeev_local 
1002f083884Ss.makeev_local 	MT::AtomicPtrBase<MT::Event> pStressEvent = { nullptr };
1012f083884Ss.makeev_local 	MT::Atomic32Base<uint32> needExitSignal = { 0 };
1022f083884Ss.makeev_local 	MT::Atomic32Base<uint32> needExitWait = { 0 };
103*01616bcfSs.makeev_local 	MT::Atomic32Base<uint32> needStartWork = { 0 };
1042f083884Ss.makeev_local 
1052f083884Ss.makeev_local 	void EventStressTestSignalThreadFunc(void*)
106*01616bcfSs.makeev_local 	{ BROFILER_THREAD("SignalThread");
107*01616bcfSs.makeev_local 
108*01616bcfSs.makeev_local 		while (needStartWork.Load() == 0)
109*01616bcfSs.makeev_local 		{ BROFILER_CATEGORY("Signal prepare", 0xFFFF00FF);
110*01616bcfSs.makeev_local 			MT::SpinSleepMicroSeconds(300);
111*01616bcfSs.makeev_local 		}
112*01616bcfSs.makeev_local 
1132f083884Ss.makeev_local 		while (needExitSignal.Load() == 0)
114*01616bcfSs.makeev_local 		{ BROFILER_CATEGORY("Signal Loop", 0xFF556B2F);
115*01616bcfSs.makeev_local 			MT::SpinSleepMicroSeconds(300);
1162f083884Ss.makeev_local 			MT::Event * pEvent = pStressEvent.Load();
1172f083884Ss.makeev_local 			pEvent->Signal();
1182f083884Ss.makeev_local 		}
1192f083884Ss.makeev_local 	}
1202f083884Ss.makeev_local 
1212f083884Ss.makeev_local 	void EventStressTestWaitThreadFunc(void*)
122*01616bcfSs.makeev_local 	{ BROFILER_THREAD("WaitThread");
123*01616bcfSs.makeev_local 
124*01616bcfSs.makeev_local 		while (needStartWork.Load() == 0)
125*01616bcfSs.makeev_local 		{ BROFILER_CATEGORY("Wait prepare", 0xFFFF00FF);
126*01616bcfSs.makeev_local 			MT::SpinSleepMicroSeconds(300);
127*01616bcfSs.makeev_local 		}
128*01616bcfSs.makeev_local 
1292f083884Ss.makeev_local 		while (needExitWait.Load() == 0)
130*01616bcfSs.makeev_local 		{ BROFILER_CATEGORY("Wait Loop", 0xFFF0F8FF);
1312f083884Ss.makeev_local 			MT::Event* pEvent = pStressEvent.Load();
132ea599e92Ss.makeev_local 			bool res = pEvent->Wait(1000);
133*01616bcfSs.makeev_local 			MT::SpinSleepMicroSeconds(300);
1342f083884Ss.makeev_local 			CHECK(res == true);
1352f083884Ss.makeev_local 		}
1362f083884Ss.makeev_local 	}
1372f083884Ss.makeev_local 
1382f083884Ss.makeev_local 
1392f083884Ss.makeev_local 
1402f083884Ss.makeev_local 
141*01616bcfSs.makeev_local 
1422f083884Ss.makeev_local 	TEST(EventStressTest)
1432f083884Ss.makeev_local 	{
144*01616bcfSs.makeev_local #if defined(MT_ENABLE_LEGACY_WINDOWSXP_SUPPORT) && defined(MT_PLATFORM_WINDOWS)
145*01616bcfSs.makeev_local 		printf("Kernel mode events\n");
146*01616bcfSs.makeev_local #else
147*01616bcfSs.makeev_local 		printf("User mode events\n");
148*01616bcfSs.makeev_local #endif
149*01616bcfSs.makeev_local 
150*01616bcfSs.makeev_local 
1512f083884Ss.makeev_local 		MT::Event stressEvent;
152*01616bcfSs.makeev_local 		MT::Thread signalThreads[3];
153*01616bcfSs.makeev_local 		MT::Thread waitThreads[3];
154*01616bcfSs.makeev_local 		needStartWork.Store(0);
155*01616bcfSs.makeev_local 
156*01616bcfSs.makeev_local 		{
157*01616bcfSs.makeev_local 			BROFILER_NEXT_FRAME();
1582f083884Ss.makeev_local 			stressEvent.Create(MT::EventReset::AUTOMATIC, false);
1592f083884Ss.makeev_local 			pStressEvent.Store( &stressEvent );
1602f083884Ss.makeev_local 
1612f083884Ss.makeev_local 			needExitSignal.Store(0);
1622f083884Ss.makeev_local 			needExitWait.Store(0);
1632f083884Ss.makeev_local 
1642f083884Ss.makeev_local 			for(uint32 i = 0; i < MT_ARRAY_SIZE(signalThreads); i++)
1652f083884Ss.makeev_local 			{
1662f083884Ss.makeev_local 				signalThreads[i].Start(32768, EventStressTestSignalThreadFunc, nullptr);
1672f083884Ss.makeev_local 			}
1682f083884Ss.makeev_local 
1692f083884Ss.makeev_local 			for(uint32 i = 0; i < MT_ARRAY_SIZE(waitThreads); i++)
1702f083884Ss.makeev_local 			{
1712f083884Ss.makeev_local 				waitThreads[i].Start(32768, EventStressTestWaitThreadFunc, nullptr);
1722f083884Ss.makeev_local 			}
1732f083884Ss.makeev_local 
174*01616bcfSs.makeev_local 			printf("Signal threads num = %d\n", (uint32)MT_ARRAY_SIZE(signalThreads));
175*01616bcfSs.makeev_local 			printf("Wait threads num = %d\n", (uint32)MT_ARRAY_SIZE(waitThreads));
176*01616bcfSs.makeev_local 		}
1772f083884Ss.makeev_local 
1782f083884Ss.makeev_local 
179*01616bcfSs.makeev_local #if defined(MT_INSTRUMENTED_BUILD) && defined(MT_ENABLE_BROFILER_SUPPORT)
180*01616bcfSs.makeev_local 		BROFILER_FRAME("EventStressTest");
181*01616bcfSs.makeev_local 		{
182*01616bcfSs.makeev_local 			printf("Waiting for 'Brofiler' connection.\n");
183*01616bcfSs.makeev_local 			for(;;)
184*01616bcfSs.makeev_local 			{
185*01616bcfSs.makeev_local 				BROFILER_NEXT_FRAME();
186*01616bcfSs.makeev_local 				MT::Thread::Sleep(150);
187*01616bcfSs.makeev_local 				if (Brofiler::IsActive())
188*01616bcfSs.makeev_local 				{
189*01616bcfSs.makeev_local 					break;
190*01616bcfSs.makeev_local 				}
191*01616bcfSs.makeev_local 			}
192*01616bcfSs.makeev_local 		}
193*01616bcfSs.makeev_local #endif
194*01616bcfSs.makeev_local 		needStartWork.Store(1);
1952f083884Ss.makeev_local 
1962f083884Ss.makeev_local 		const int iterationsCount = 5000;
197*01616bcfSs.makeev_local 
198*01616bcfSs.makeev_local 		int64 startTimeSignal = MT::GetTimeMicroSeconds();
199*01616bcfSs.makeev_local 		{ BROFILER_NEXT_FRAME();
200*01616bcfSs.makeev_local 		  BROFILER_CATEGORY("Signal Loop", 0xFF556B2F);
201*01616bcfSs.makeev_local 			for(int i = 0; i < iterationsCount; i++)
202*01616bcfSs.makeev_local 			{
203*01616bcfSs.makeev_local 				stressEvent.Signal();
204*01616bcfSs.makeev_local 			}
205*01616bcfSs.makeev_local 		}
206*01616bcfSs.makeev_local 		int64 endTimeSignal = MT::GetTimeMicroSeconds();
207*01616bcfSs.makeev_local 
208*01616bcfSs.makeev_local 
209*01616bcfSs.makeev_local 		int64 startTimeWait = MT::GetTimeMicroSeconds();
210*01616bcfSs.makeev_local 		{ BROFILER_NEXT_FRAME();
211*01616bcfSs.makeev_local 		  BROFILER_CATEGORY("Wait Loop", 0xFFF0F8FF);
2122f083884Ss.makeev_local 			for(int i = 0; i < iterationsCount; i++)
2132f083884Ss.makeev_local 			{
214ea599e92Ss.makeev_local 				bool res = stressEvent.Wait(1000);
2152f083884Ss.makeev_local 				CHECK(res == true);
2162f083884Ss.makeev_local 			}
217*01616bcfSs.makeev_local 		}
218*01616bcfSs.makeev_local 		int64 endTimeWait = MT::GetTimeMicroSeconds();
2192f083884Ss.makeev_local 
220*01616bcfSs.makeev_local 		double microSecondsPerWait = (double)((endTimeWait - startTimeWait) / (double)iterationsCount);
221*01616bcfSs.makeev_local 		double microSecondsPerSignal = (double)((endTimeSignal - startTimeSignal) / (double)iterationsCount);
2222f083884Ss.makeev_local 
223*01616bcfSs.makeev_local 		printf("microseconds per signal = %3.2f, iterations = %d\n", microSecondsPerSignal, iterationsCount);
224*01616bcfSs.makeev_local 		printf("microseconds per wait = %3.2f, iterations = %d\n", microSecondsPerWait, iterationsCount);
2252f083884Ss.makeev_local 
226*01616bcfSs.makeev_local #if defined(MT_INSTRUMENTED_BUILD) && defined(MT_ENABLE_BROFILER_SUPPORT)
227*01616bcfSs.makeev_local 		{
228*01616bcfSs.makeev_local 			printf("Waiting for the 'Brofiler' to be disconnected\n");
229*01616bcfSs.makeev_local 			for(;;)
230*01616bcfSs.makeev_local 			{
231*01616bcfSs.makeev_local 				BROFILER_NEXT_FRAME();
232*01616bcfSs.makeev_local 				MT::Thread::Sleep(150);
233*01616bcfSs.makeev_local 				if (!Brofiler::IsActive())
234*01616bcfSs.makeev_local 				{
235*01616bcfSs.makeev_local 					break;
236*01616bcfSs.makeev_local 				}
237*01616bcfSs.makeev_local 			}
238*01616bcfSs.makeev_local 		}
239*01616bcfSs.makeev_local 
240*01616bcfSs.makeev_local 		printf("Done\n");
241*01616bcfSs.makeev_local #endif
2422f083884Ss.makeev_local 
2432f083884Ss.makeev_local 		needExitWait.Store(1);
2442f083884Ss.makeev_local 		for(uint32 i = 0; i < MT_ARRAY_SIZE(waitThreads); i++)
2452f083884Ss.makeev_local 		{
2462f083884Ss.makeev_local 			waitThreads[i].Join();
2472f083884Ss.makeev_local 		}
2482f083884Ss.makeev_local 
2492f083884Ss.makeev_local 		MT::Thread::Sleep(100);
2502f083884Ss.makeev_local 
2512f083884Ss.makeev_local 		needExitSignal.Store(1);
2522f083884Ss.makeev_local 		for(uint32 i = 0; i < MT_ARRAY_SIZE(signalThreads); i++)
2532f083884Ss.makeev_local 		{
2542f083884Ss.makeev_local 			signalThreads[i].Join();
2552f083884Ss.makeev_local 		}
2562f083884Ss.makeev_local 
2572f083884Ss.makeev_local 		bool res = stressEvent.Wait(300);
2582f083884Ss.makeev_local 		CHECK(res == true);
2592f083884Ss.makeev_local 
2602f083884Ss.makeev_local 		res = stressEvent.Wait(300);
2612f083884Ss.makeev_local 		CHECK(res == false);
2622f083884Ss.makeev_local 
2632f083884Ss.makeev_local 	}
2642f083884Ss.makeev_local 
2652f083884Ss.makeev_local 
2662f083884Ss.makeev_local 	TEST(SleepTest)
2672f083884Ss.makeev_local 	{
2682f083884Ss.makeev_local 
2692f083884Ss.makeev_local 		MT::Timer timer;
2702f083884Ss.makeev_local 
2713cb1fd8eSs.makeev_local 		MT::SpinSleepMilliSeconds(100);
2722f083884Ss.makeev_local 
2732f083884Ss.makeev_local 		CHECK( timer.GetPastMilliSeconds() >= 100 );
2742f083884Ss.makeev_local 	}
2752f083884Ss.makeev_local 	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2762f083884Ss.makeev_local }
277