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