13cb1fd8eSs.makeev_local // The MIT License (MIT)
23cb1fd8eSs.makeev_local //
33cb1fd8eSs.makeev_local // 	Copyright (c) 2015 Sergey Makeev, Vadim Slyusarev
43cb1fd8eSs.makeev_local //
53cb1fd8eSs.makeev_local // 	Permission is hereby granted, free of charge, to any person obtaining a copy
63cb1fd8eSs.makeev_local // 	of this software and associated documentation files (the "Software"), to deal
73cb1fd8eSs.makeev_local // 	in the Software without restriction, including without limitation the rights
83cb1fd8eSs.makeev_local // 	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
93cb1fd8eSs.makeev_local // 	copies of the Software, and to permit persons to whom the Software is
103cb1fd8eSs.makeev_local // 	furnished to do so, subject to the following conditions:
113cb1fd8eSs.makeev_local //
123cb1fd8eSs.makeev_local //  The above copyright notice and this permission notice shall be included in
133cb1fd8eSs.makeev_local // 	all copies or substantial portions of the Software.
143cb1fd8eSs.makeev_local //
153cb1fd8eSs.makeev_local // 	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
163cb1fd8eSs.makeev_local // 	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
173cb1fd8eSs.makeev_local // 	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
183cb1fd8eSs.makeev_local // 	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
193cb1fd8eSs.makeev_local // 	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
203cb1fd8eSs.makeev_local // 	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
213cb1fd8eSs.makeev_local // 	THE SOFTWARE.
223cb1fd8eSs.makeev_local 
233cb1fd8eSs.makeev_local #pragma once
243cb1fd8eSs.makeev_local 
253cb1fd8eSs.makeev_local 
263cb1fd8eSs.makeev_local namespace MT
273cb1fd8eSs.makeev_local {
283cb1fd8eSs.makeev_local 
293cb1fd8eSs.makeev_local 	// Hybrid spin wait
303cb1fd8eSs.makeev_local 	//
313cb1fd8eSs.makeev_local 	// http://www.1024cores.net/home/lock-free-algorithms/tricks/spinning
323cb1fd8eSs.makeev_local 	//
333cb1fd8eSs.makeev_local 	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
343cb1fd8eSs.makeev_local 	class SpinWait
353cb1fd8eSs.makeev_local 	{
363cb1fd8eSs.makeev_local 		int32 iteration;
373cb1fd8eSs.makeev_local 
383cb1fd8eSs.makeev_local 	public:
393cb1fd8eSs.makeev_local 
403cb1fd8eSs.makeev_local 		static const int32 YIELD_CPU_THRESHOLD = 10;
413cb1fd8eSs.makeev_local 		static const int32 YIELD_CPU_THRESHOLD2 = 20;
423cb1fd8eSs.makeev_local 		static const int32 YIELD_THREAD_THRESHOLD = 40;
433cb1fd8eSs.makeev_local 		static const int32 YIELD_SLEEP0_THRESHOLD = 200;
443cb1fd8eSs.makeev_local 
453cb1fd8eSs.makeev_local 
SpinWait()463cb1fd8eSs.makeev_local 		SpinWait()
473cb1fd8eSs.makeev_local 			: iteration(0)
483cb1fd8eSs.makeev_local 		{
493cb1fd8eSs.makeev_local 		}
503cb1fd8eSs.makeev_local 
Reset()513cb1fd8eSs.makeev_local 		void Reset()
523cb1fd8eSs.makeev_local 		{
533cb1fd8eSs.makeev_local 			iteration = 0;
543cb1fd8eSs.makeev_local 		}
553cb1fd8eSs.makeev_local 
IsActive()563cb1fd8eSs.makeev_local 		bool IsActive() const
573cb1fd8eSs.makeev_local 		{
583cb1fd8eSs.makeev_local 			return (iteration != 0);
593cb1fd8eSs.makeev_local 		}
603cb1fd8eSs.makeev_local 
SpinOnce()613cb1fd8eSs.makeev_local 		int32 SpinOnce()
623cb1fd8eSs.makeev_local 		{
633cb1fd8eSs.makeev_local 			if (iteration <= YIELD_CPU_THRESHOLD)
643cb1fd8eSs.makeev_local 			{
65*b086e50bSSergey Makeev 				MT::YieldProcessor();
663cb1fd8eSs.makeev_local 			} else
673cb1fd8eSs.makeev_local 			{
683cb1fd8eSs.makeev_local 				if (iteration <= YIELD_CPU_THRESHOLD2)
693cb1fd8eSs.makeev_local 				{
703cb1fd8eSs.makeev_local 					for (int32 i = 0; i < 50; i++)
713cb1fd8eSs.makeev_local 					{
72*b086e50bSSergey Makeev 						MT::YieldProcessor();
733cb1fd8eSs.makeev_local 					}
743cb1fd8eSs.makeev_local 				} else
753cb1fd8eSs.makeev_local 				{
763cb1fd8eSs.makeev_local 					if (iteration <= YIELD_THREAD_THRESHOLD)
773cb1fd8eSs.makeev_local 					{
783cb1fd8eSs.makeev_local 						MT::YieldThread();
793cb1fd8eSs.makeev_local 					} else
803cb1fd8eSs.makeev_local 					{
813cb1fd8eSs.makeev_local 						if (iteration <= YIELD_SLEEP0_THRESHOLD)
823cb1fd8eSs.makeev_local 						{
833cb1fd8eSs.makeev_local 							MT::Thread::Sleep(0);
843cb1fd8eSs.makeev_local 						} else
853cb1fd8eSs.makeev_local 						{
863cb1fd8eSs.makeev_local 							MT::Thread::Sleep(1);
873cb1fd8eSs.makeev_local 						}
883cb1fd8eSs.makeev_local 					}
893cb1fd8eSs.makeev_local 				}
903cb1fd8eSs.makeev_local 			}
913cb1fd8eSs.makeev_local 
923cb1fd8eSs.makeev_local 			int32 retValue = iteration;
933cb1fd8eSs.makeev_local 			if (iteration < INT_MAX)
943cb1fd8eSs.makeev_local 			{
953cb1fd8eSs.makeev_local 				iteration++;
963cb1fd8eSs.makeev_local 			}
973cb1fd8eSs.makeev_local 			return retValue;
983cb1fd8eSs.makeev_local 		}
993cb1fd8eSs.makeev_local 	};
1003cb1fd8eSs.makeev_local 
1013cb1fd8eSs.makeev_local 
1023cb1fd8eSs.makeev_local 	/*
1033cb1fd8eSs.makeev_local 
1043cb1fd8eSs.makeev_local 	Brute force spin wait.  For testing purposes only!
1053cb1fd8eSs.makeev_local 
1063cb1fd8eSs.makeev_local 	*/
SpinSleepMicroSeconds(uint32 microseconds)1073cb1fd8eSs.makeev_local 	inline void SpinSleepMicroSeconds(uint32 microseconds)
1083cb1fd8eSs.makeev_local 	{
1093cb1fd8eSs.makeev_local 		int64 desiredTime = GetTimeMicroSeconds() + microseconds;
1103cb1fd8eSs.makeev_local 		for(;;)
1113cb1fd8eSs.makeev_local 		{
1123cb1fd8eSs.makeev_local 			int64 timeNow = GetTimeMicroSeconds();
1133cb1fd8eSs.makeev_local 			if (timeNow > desiredTime)
1143cb1fd8eSs.makeev_local 			{
1153cb1fd8eSs.makeev_local 				break;
1163cb1fd8eSs.makeev_local 			}
117*b086e50bSSergey Makeev 			YieldProcessor();
1183cb1fd8eSs.makeev_local 		}
1193cb1fd8eSs.makeev_local 	}
1203cb1fd8eSs.makeev_local 
1213cb1fd8eSs.makeev_local 	/*
1223cb1fd8eSs.makeev_local 
1233cb1fd8eSs.makeev_local 	Brute force spin wait. For testing purposes only!
1243cb1fd8eSs.makeev_local 
1253cb1fd8eSs.makeev_local 	*/
SpinSleepMilliSeconds(uint32 milliseconds)1263cb1fd8eSs.makeev_local 	inline void SpinSleepMilliSeconds(uint32 milliseconds)
1273cb1fd8eSs.makeev_local 	{
1283cb1fd8eSs.makeev_local 		SpinSleepMicroSeconds(milliseconds * 1000);
1293cb1fd8eSs.makeev_local 	}
1303cb1fd8eSs.makeev_local 
1313cb1fd8eSs.makeev_local }
132