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