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 #pragma once
24 
25 
26 namespace MT
27 {
28 
29 	// Hybrid spin wait
30 	//
31 	// http://www.1024cores.net/home/lock-free-algorithms/tricks/spinning
32 	//
33 	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
34 	class SpinWait
35 	{
36 		int32 iteration;
37 
38 	public:
39 
40 		static const int32 YIELD_CPU_THRESHOLD = 10;
41 		static const int32 YIELD_CPU_THRESHOLD2 = 20;
42 		static const int32 YIELD_THREAD_THRESHOLD = 40;
43 		static const int32 YIELD_SLEEP0_THRESHOLD = 200;
44 
45 
SpinWait()46 		SpinWait()
47 			: iteration(0)
48 		{
49 		}
50 
Reset()51 		void Reset()
52 		{
53 			iteration = 0;
54 		}
55 
IsActive()56 		bool IsActive() const
57 		{
58 			return (iteration != 0);
59 		}
60 
SpinOnce()61 		int32 SpinOnce()
62 		{
63 			if (iteration <= YIELD_CPU_THRESHOLD)
64 			{
65 				MT::YieldProcessor();
66 			} else
67 			{
68 				if (iteration <= YIELD_CPU_THRESHOLD2)
69 				{
70 					for (int32 i = 0; i < 50; i++)
71 					{
72 						MT::YieldProcessor();
73 					}
74 				} else
75 				{
76 					if (iteration <= YIELD_THREAD_THRESHOLD)
77 					{
78 						MT::YieldThread();
79 					} else
80 					{
81 						if (iteration <= YIELD_SLEEP0_THRESHOLD)
82 						{
83 							MT::Thread::Sleep(0);
84 						} else
85 						{
86 							MT::Thread::Sleep(1);
87 						}
88 					}
89 				}
90 			}
91 
92 			int32 retValue = iteration;
93 			if (iteration < INT_MAX)
94 			{
95 				iteration++;
96 			}
97 			return retValue;
98 		}
99 	};
100 
101 
102 	/*
103 
104 	Brute force spin wait.  For testing purposes only!
105 
106 	*/
SpinSleepMicroSeconds(uint32 microseconds)107 	inline void SpinSleepMicroSeconds(uint32 microseconds)
108 	{
109 		int64 desiredTime = GetTimeMicroSeconds() + microseconds;
110 		for(;;)
111 		{
112 			int64 timeNow = GetTimeMicroSeconds();
113 			if (timeNow > desiredTime)
114 			{
115 				break;
116 			}
117 			YieldProcessor();
118 		}
119 	}
120 
121 	/*
122 
123 	Brute force spin wait. For testing purposes only!
124 
125 	*/
SpinSleepMilliSeconds(uint32 milliseconds)126 	inline void SpinSleepMilliSeconds(uint32 milliseconds)
127 	{
128 		SpinSleepMicroSeconds(milliseconds * 1000);
129 	}
130 
131 }
132