1436acff3Ss.makeev_local // The MIT License (MIT) 2436acff3Ss.makeev_local // 3436acff3Ss.makeev_local // Copyright (c) 2015 Sergey Makeev, Vadim Slyusarev 4436acff3Ss.makeev_local // 5436acff3Ss.makeev_local // Permission is hereby granted, free of charge, to any person obtaining a copy 6436acff3Ss.makeev_local // of this software and associated documentation files (the "Software"), to deal 7436acff3Ss.makeev_local // in the Software without restriction, including without limitation the rights 8436acff3Ss.makeev_local // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9436acff3Ss.makeev_local // copies of the Software, and to permit persons to whom the Software is 10436acff3Ss.makeev_local // furnished to do so, subject to the following conditions: 11436acff3Ss.makeev_local // 12436acff3Ss.makeev_local // The above copyright notice and this permission notice shall be included in 13436acff3Ss.makeev_local // all copies or substantial portions of the Software. 14436acff3Ss.makeev_local // 15436acff3Ss.makeev_local // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16436acff3Ss.makeev_local // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17436acff3Ss.makeev_local // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18436acff3Ss.makeev_local // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19436acff3Ss.makeev_local // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20436acff3Ss.makeev_local // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21436acff3Ss.makeev_local // THE SOFTWARE. 22436acff3Ss.makeev_local 23436acff3Ss.makeev_local #pragma once 24436acff3Ss.makeev_local 25436acff3Ss.makeev_local #ifndef __MT_EVENT_USER__ 26436acff3Ss.makeev_local #define __MT_EVENT_USER__ 27436acff3Ss.makeev_local 28436acff3Ss.makeev_local namespace MT 29436acff3Ss.makeev_local { 30436acff3Ss.makeev_local // 31436acff3Ss.makeev_local // 32436acff3Ss.makeev_local // 33436acff3Ss.makeev_local class Event 34436acff3Ss.makeev_local { 35436acff3Ss.makeev_local static const int NOT_SIGNALED = 0; 36436acff3Ss.makeev_local static const int SIGNALED = 1; 37436acff3Ss.makeev_local 38436acff3Ss.makeev_local ::MW_CRITICAL_SECTION criticalSection; 39436acff3Ss.makeev_local ::MW_CONDITION_VARIABLE condition; 40436acff3Ss.makeev_local 41436acff3Ss.makeev_local EventReset::Type resetType; 42436acff3Ss.makeev_local 43436acff3Ss.makeev_local volatile uint32 numOfWaitingThreads; 44436acff3Ss.makeev_local volatile int32 value; 45436acff3Ss.makeev_local volatile bool isInitialized; 46436acff3Ss.makeev_local 47436acff3Ss.makeev_local private: 48436acff3Ss.makeev_local AutoResetIfNeed()49436acff3Ss.makeev_local void AutoResetIfNeed() 50436acff3Ss.makeev_local { 51436acff3Ss.makeev_local if (resetType == EventReset::MANUAL) 52436acff3Ss.makeev_local { 53436acff3Ss.makeev_local return; 54436acff3Ss.makeev_local } 55436acff3Ss.makeev_local value = NOT_SIGNALED; 56436acff3Ss.makeev_local } 57436acff3Ss.makeev_local 58436acff3Ss.makeev_local 59436acff3Ss.makeev_local public: 60436acff3Ss.makeev_local 61436acff3Ss.makeev_local MT_NOCOPYABLE(Event); 62436acff3Ss.makeev_local Event()63436acff3Ss.makeev_local Event() 64436acff3Ss.makeev_local : numOfWaitingThreads(0) 65436acff3Ss.makeev_local , isInitialized(false) 66436acff3Ss.makeev_local { 67436acff3Ss.makeev_local } 68436acff3Ss.makeev_local Event(EventReset::Type resetType_,bool initialState)69*ca588010SDmitry Tsarevich Event(EventReset::Type resetType_, bool initialState) 70436acff3Ss.makeev_local : numOfWaitingThreads(0) 71436acff3Ss.makeev_local , isInitialized(false) 72436acff3Ss.makeev_local { 73*ca588010SDmitry Tsarevich Create(resetType_, initialState); 74436acff3Ss.makeev_local } 75436acff3Ss.makeev_local ~Event()76436acff3Ss.makeev_local ~Event() 77436acff3Ss.makeev_local { 78436acff3Ss.makeev_local if (isInitialized) 79436acff3Ss.makeev_local { 80436acff3Ss.makeev_local ::DeleteCriticalSection(&criticalSection); 81436acff3Ss.makeev_local isInitialized = false; 82436acff3Ss.makeev_local } 83436acff3Ss.makeev_local } 84436acff3Ss.makeev_local Create(EventReset::Type resetType_,bool initialState)85*ca588010SDmitry Tsarevich void Create(EventReset::Type resetType_, bool initialState) 86436acff3Ss.makeev_local { 87436acff3Ss.makeev_local MT_ASSERT (!isInitialized, "Event already initialized"); 88*ca588010SDmitry Tsarevich resetType = resetType_; 89436acff3Ss.makeev_local 90436acff3Ss.makeev_local ::InitializeCriticalSectionAndSpinCount( &criticalSection, 16 ); 91436acff3Ss.makeev_local ::InitializeConditionVariable( &condition ); 92436acff3Ss.makeev_local 93436acff3Ss.makeev_local value = initialState ? SIGNALED : NOT_SIGNALED; 94436acff3Ss.makeev_local isInitialized = true; 95436acff3Ss.makeev_local numOfWaitingThreads = 0; 96436acff3Ss.makeev_local } 97436acff3Ss.makeev_local Signal()98436acff3Ss.makeev_local void Signal() 99436acff3Ss.makeev_local { 100436acff3Ss.makeev_local MT_ASSERT (isInitialized, "Event not initialized"); 101436acff3Ss.makeev_local ::EnterCriticalSection( &criticalSection ); 102436acff3Ss.makeev_local value = SIGNALED; 103436acff3Ss.makeev_local if (numOfWaitingThreads > 0) 104436acff3Ss.makeev_local { 105436acff3Ss.makeev_local if (resetType == EventReset::MANUAL) 106436acff3Ss.makeev_local { 107436acff3Ss.makeev_local ::WakeAllConditionVariable( &condition ); 108436acff3Ss.makeev_local } else 109436acff3Ss.makeev_local { 110436acff3Ss.makeev_local ::WakeConditionVariable( &condition ); 111436acff3Ss.makeev_local } 112436acff3Ss.makeev_local } 113436acff3Ss.makeev_local ::LeaveCriticalSection( &criticalSection ); 114436acff3Ss.makeev_local } 115436acff3Ss.makeev_local Reset()116436acff3Ss.makeev_local void Reset() 117436acff3Ss.makeev_local { 118436acff3Ss.makeev_local MT_ASSERT (isInitialized, "Event not initialized"); 119436acff3Ss.makeev_local MT_ASSERT(resetType == EventReset::MANUAL, "Can't reset, auto reset event"); 120436acff3Ss.makeev_local 121436acff3Ss.makeev_local ::EnterCriticalSection( &criticalSection ); 122436acff3Ss.makeev_local value = NOT_SIGNALED; 123436acff3Ss.makeev_local ::LeaveCriticalSection( &criticalSection ); 124436acff3Ss.makeev_local } 125436acff3Ss.makeev_local Wait(uint32 milliseconds)126436acff3Ss.makeev_local bool Wait(uint32 milliseconds) 127436acff3Ss.makeev_local { 128436acff3Ss.makeev_local MT_ASSERT (isInitialized, "Event not initialized"); 129436acff3Ss.makeev_local 130436acff3Ss.makeev_local ::EnterCriticalSection( &criticalSection ); 131436acff3Ss.makeev_local // early exit if event already signaled 132436acff3Ss.makeev_local if ( value != NOT_SIGNALED ) 133436acff3Ss.makeev_local { 134436acff3Ss.makeev_local AutoResetIfNeed(); 135436acff3Ss.makeev_local ::LeaveCriticalSection( &criticalSection ); 136436acff3Ss.makeev_local return true; 137436acff3Ss.makeev_local } 138436acff3Ss.makeev_local 139436acff3Ss.makeev_local numOfWaitingThreads++; 140436acff3Ss.makeev_local 141436acff3Ss.makeev_local for(;;) 142436acff3Ss.makeev_local { 143436acff3Ss.makeev_local MW_BOOL ret = ::SleepConditionVariableCS(&condition, &criticalSection, (MW_DWORD)milliseconds); 144436acff3Ss.makeev_local 145436acff3Ss.makeev_local #if defined(MT_DEBUG) || defined(MT_INSTRUMENTED_BUILD) 146436acff3Ss.makeev_local if (ret == 0) 147436acff3Ss.makeev_local { 148436acff3Ss.makeev_local MW_DWORD err = ::GetLastError(); 149436acff3Ss.makeev_local MT_USED_IN_ASSERT(err); 150436acff3Ss.makeev_local MT_ASSERT(err == MW_ERROR_TIMEOUT, "Unexpected return value from SleepConditionVariable"); 151436acff3Ss.makeev_local } 152436acff3Ss.makeev_local #endif 153436acff3Ss.makeev_local 154436acff3Ss.makeev_local /* 155436acff3Ss.makeev_local https://msdn.microsoft.com/en-us/library/windows/desktop/ms686301(v=vs.85).aspx 156436acff3Ss.makeev_local 157436acff3Ss.makeev_local Condition variables are subject to spurious wakeups (those not associated with an explicit wake) and stolen wakeups (another thread manages to run before the woken thread). 158436acff3Ss.makeev_local Therefore, you should recheck a predicate (typically in a while loop) after a sleep operation returns. 159436acff3Ss.makeev_local */ 160436acff3Ss.makeev_local if (value == SIGNALED || ret == 0) 161436acff3Ss.makeev_local { 162436acff3Ss.makeev_local break; 163436acff3Ss.makeev_local } 164436acff3Ss.makeev_local } 165436acff3Ss.makeev_local 166436acff3Ss.makeev_local numOfWaitingThreads--; 167436acff3Ss.makeev_local bool isSignaled = (value != NOT_SIGNALED); 168436acff3Ss.makeev_local if (isSignaled) 169436acff3Ss.makeev_local { 170436acff3Ss.makeev_local AutoResetIfNeed(); 171436acff3Ss.makeev_local } 172436acff3Ss.makeev_local 173436acff3Ss.makeev_local ::LeaveCriticalSection( &criticalSection ); 174436acff3Ss.makeev_local return isSignaled; 175436acff3Ss.makeev_local } 176436acff3Ss.makeev_local 177436acff3Ss.makeev_local }; 178436acff3Ss.makeev_local 179436acff3Ss.makeev_local } 180436acff3Ss.makeev_local 181436acff3Ss.makeev_local 182436acff3Ss.makeev_local #endif 183