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 "../Profiler/Profiler.h" 25 #include <UnitTest++.h> 26 #include <MTScheduler.h> 27 28 SUITE(PlatformTests) 29 { 30 static const intptr_t DATA_VALUE = 13; 31 32 intptr_t g_Variable = 0; 33 34 void MyThreadFunc(void* userData) 35 { 36 intptr_t data = (intptr_t)userData; 37 38 CHECK(data == DATA_VALUE); 39 40 g_Variable = data; 41 } 42 43 TEST(ThreadTest) 44 { 45 intptr_t data = DATA_VALUE; 46 47 MT::Thread thread; 48 thread.Start(32768, MyThreadFunc, (void*)data); 49 thread.Join(); 50 51 CHECK(g_Variable == DATA_VALUE); 52 } 53 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 54 55 MT::Event *pEvent1 = nullptr; 56 MT::Event *pEvent2 = nullptr; 57 58 void MyThreadFunc2(void*) 59 { 60 MT::SpinSleepMilliSeconds(300); 61 pEvent1->Signal(); 62 } 63 64 TEST(EventTest) 65 { 66 MT::Event event1; 67 event1.Create(MT::EventReset::MANUAL, false); 68 pEvent1 = &event1; 69 70 MT::Event event2; 71 event2.Create(MT::EventReset::AUTOMATIC, false); 72 pEvent2 = &event2; 73 74 MT::Thread thread; 75 thread.Start(32768, MyThreadFunc2, nullptr); 76 77 bool res0 = event1.Wait(100); 78 bool res1 = event1.Wait(1000); 79 bool res2 = event1.Wait(1000); 80 event1.Reset(); 81 bool res3 = event1.Wait(100); 82 83 CHECK(!res0); 84 CHECK(res1); 85 CHECK(res2); 86 CHECK(!res3); 87 88 bool res4 = event2.Wait(100); 89 CHECK(!res4); 90 bool res5 = event2.Wait(100); 91 CHECK(!res5); 92 bool res6 = event2.Wait(100); 93 CHECK(!res6); 94 95 thread.Join(); 96 } 97 98 99 100 MT::AtomicPtrBase<MT::Event> pStressEvent = { nullptr }; 101 MT::Atomic32Base<uint32> needExitSignal = { 0 }; 102 MT::Atomic32Base<uint32> needExitWait = { 0 }; 103 MT::Atomic32Base<uint32> needStartWork = { 0 }; 104 105 void EventStressTestSignalThreadFunc(void*) 106 { BROFILER_THREAD("SignalThread"); 107 108 while (needStartWork.Load() == 0) 109 { BROFILER_CATEGORY("Signal prepare", 0xFFFF00FF); 110 MT::SpinSleepMicroSeconds(300); 111 } 112 113 while (needExitSignal.Load() == 0) 114 { BROFILER_CATEGORY("Signal Loop", 0xFF556B2F); 115 MT::SpinSleepMicroSeconds(300); 116 MT::Event * pEvent = pStressEvent.Load(); 117 pEvent->Signal(); 118 } 119 } 120 121 void EventStressTestWaitThreadFunc(void*) 122 { BROFILER_THREAD("WaitThread"); 123 124 while (needStartWork.Load() == 0) 125 { BROFILER_CATEGORY("Wait prepare", 0xFFFF00FF); 126 MT::SpinSleepMicroSeconds(300); 127 } 128 129 while (needExitWait.Load() == 0) 130 { BROFILER_CATEGORY("Wait Loop", 0xFFF0F8FF); 131 MT::Event* pEvent = pStressEvent.Load(); 132 bool res = pEvent->Wait(1000); 133 MT::SpinSleepMicroSeconds(300); 134 CHECK(res == true); 135 } 136 } 137 138 139 140 141 142 TEST(EventStressTest) 143 { 144 #if defined(MT_ENABLE_LEGACY_WINDOWSXP_SUPPORT) && defined(MT_PLATFORM_WINDOWS) 145 printf("Kernel mode events\n"); 146 #else 147 printf("User mode events\n"); 148 #endif 149 150 151 MT::Event stressEvent; 152 MT::Thread signalThreads[3]; 153 MT::Thread waitThreads[3]; 154 needStartWork.Store(0); 155 156 { 157 BROFILER_NEXT_FRAME(); 158 stressEvent.Create(MT::EventReset::AUTOMATIC, false); 159 pStressEvent.Store( &stressEvent ); 160 161 needExitSignal.Store(0); 162 needExitWait.Store(0); 163 164 for(uint32 i = 0; i < MT_ARRAY_SIZE(signalThreads); i++) 165 { 166 signalThreads[i].Start(32768, EventStressTestSignalThreadFunc, nullptr); 167 } 168 169 for(uint32 i = 0; i < MT_ARRAY_SIZE(waitThreads); i++) 170 { 171 waitThreads[i].Start(32768, EventStressTestWaitThreadFunc, nullptr); 172 } 173 174 printf("Signal threads num = %d\n", (uint32)MT_ARRAY_SIZE(signalThreads)); 175 printf("Wait threads num = %d\n", (uint32)MT_ARRAY_SIZE(waitThreads)); 176 } 177 178 179 #if defined(MT_INSTRUMENTED_BUILD) && defined(MT_ENABLE_BROFILER_SUPPORT) 180 BROFILER_FRAME("EventStressTest"); 181 { 182 printf("Waiting for 'Brofiler' connection.\n"); 183 for(;;) 184 { 185 BROFILER_NEXT_FRAME(); 186 MT::Thread::Sleep(150); 187 if (Brofiler::IsActive()) 188 { 189 break; 190 } 191 } 192 } 193 #endif 194 needStartWork.Store(1); 195 196 const int iterationsCount = 5000; 197 198 int64 startTimeSignal = MT::GetTimeMicroSeconds(); 199 { BROFILER_NEXT_FRAME(); 200 BROFILER_CATEGORY("Signal Loop", 0xFF556B2F); 201 for(int i = 0; i < iterationsCount; i++) 202 { 203 stressEvent.Signal(); 204 } 205 } 206 int64 endTimeSignal = MT::GetTimeMicroSeconds(); 207 208 209 int64 startTimeWait = MT::GetTimeMicroSeconds(); 210 { BROFILER_NEXT_FRAME(); 211 BROFILER_CATEGORY("Wait Loop", 0xFFF0F8FF); 212 for(int i = 0; i < iterationsCount; i++) 213 { 214 bool res = stressEvent.Wait(1000); 215 CHECK(res == true); 216 } 217 } 218 int64 endTimeWait = MT::GetTimeMicroSeconds(); 219 220 double microSecondsPerWait = (double)((endTimeWait - startTimeWait) / (double)iterationsCount); 221 double microSecondsPerSignal = (double)((endTimeSignal - startTimeSignal) / (double)iterationsCount); 222 223 printf("microseconds per signal = %3.2f, iterations = %d\n", microSecondsPerSignal, iterationsCount); 224 printf("microseconds per wait = %3.2f, iterations = %d\n", microSecondsPerWait, iterationsCount); 225 226 #if defined(MT_INSTRUMENTED_BUILD) && defined(MT_ENABLE_BROFILER_SUPPORT) 227 { 228 printf("Waiting for the 'Brofiler' to be disconnected\n"); 229 for(;;) 230 { 231 BROFILER_NEXT_FRAME(); 232 MT::Thread::Sleep(150); 233 if (!Brofiler::IsActive()) 234 { 235 break; 236 } 237 } 238 } 239 240 printf("Done\n"); 241 #endif 242 243 needExitWait.Store(1); 244 for(uint32 i = 0; i < MT_ARRAY_SIZE(waitThreads); i++) 245 { 246 waitThreads[i].Join(); 247 } 248 249 MT::Thread::Sleep(100); 250 251 needExitSignal.Store(1); 252 for(uint32 i = 0; i < MT_ARRAY_SIZE(signalThreads); i++) 253 { 254 signalThreads[i].Join(); 255 } 256 257 bool res = stressEvent.Wait(300); 258 CHECK(res == true); 259 260 res = stressEvent.Wait(300); 261 CHECK(res == false); 262 263 } 264 265 266 TEST(SleepTest) 267 { 268 269 MT::Timer timer; 270 271 MT::SpinSleepMilliSeconds(100); 272 273 CHECK( timer.GetPastMilliSeconds() >= 100 ); 274 } 275 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 276 } 277