Nebula
Loading...
Searching...
No Matches
win32criticalsection.h
Go to the documentation of this file.
1#pragma once
2//------------------------------------------------------------------------------
16#include "core/types.h"
17#include "core/sysfunc.h"
18
19// user implementation bases on "Fast critical sections with timeout" by Vladislav Gelfer
20#define NEBULA_USER_CRITICAL_SECTION 1
21
22#if NEBULA_USER_CRITICAL_SECTION
23extern "C" void _WriteBarrier();
24extern "C" void _ReadWriteBarrier();
25#pragma intrinsic(_WriteBarrier)
26#pragma intrinsic(_ReadWriteBarrier)
27#endif
28//------------------------------------------------------------------------------
29namespace Win32
30{
32{
33public:
39 void Enter() const;
41 void Leave() const;
42private:
43
44#if NEBULA_USER_CRITICAL_SECTION
46 bool PerfLockImmediate(DWORD dwThreadID) const;
48 bool PerfLock(DWORD dwThreadID) const;
50 bool PerfLockKernel(DWORD dwThreadID) const;
52 void PerfUnlock() const;
54 void WaiterPlus() const;
56 void WaiterMinus() const;
58 void AllocateKernelSemaphore() const;
59
60 // Declare all variables volatile, so that the compiler won't
61 // try to optimize something important.
62 mutable volatile DWORD lockerThread;
63 volatile DWORD spinMax;
64 mutable volatile long waiterCount;
65 mutable volatile HANDLE semaphore;
66 mutable uint recursiveLockCount;
67#else
68 mutable CRITICAL_SECTION criticalSection;
69#endif
70};
71
72#if !NEBULA_USER_CRITICAL_SECTION
73//------------------------------------------------------------------------------
76inline
78{
79 InitializeCriticalSectionAndSpinCount(&this->criticalSection, 4096);
80}
81
82//------------------------------------------------------------------------------
85inline
87{
88 DeleteCriticalSection(&this->criticalSection);
89}
90
91//------------------------------------------------------------------------------
94inline void
96{
97 EnterCriticalSection(&this->criticalSection);
98}
99
100//------------------------------------------------------------------------------
103inline void
105{
106 LeaveCriticalSection(&this->criticalSection);
107}
108
109#else
110//------------------------------------------------------------------------------
113inline void
114Win32CriticalSection::WaiterPlus() const
115{
116 _InterlockedIncrement(&this->waiterCount);
117}
118
119//------------------------------------------------------------------------------
122inline void
123Win32CriticalSection::WaiterMinus() const
124{
125 _InterlockedDecrement(&this->waiterCount);
126}
127
128//------------------------------------------------------------------------------
131inline bool
132Win32CriticalSection::PerfLockImmediate(DWORD dwThreadID) const
133{
134 return (0 == InterlockedCompareExchange((long*) &this->lockerThread, dwThreadID, 0));
135}
136
137//------------------------------------------------------------------------------
140inline void
142{
143 DWORD threadId = GetCurrentThreadId();
144 if (threadId != this->lockerThread)
145 {
146 if ((this->lockerThread == 0) &&
147 this->PerfLockImmediate(threadId))
148 {
149 // single instruction atomic quick-lock was successful
150 }
151 else
152 {
153 // potentially locked elsewhere, so do a more expensive lock with system critical section
154 this->PerfLock(threadId);
155 }
156 }
157 this->recursiveLockCount++;
158}
159
160//------------------------------------------------------------------------------
163inline void
164Win32CriticalSection::AllocateKernelSemaphore() const
165{
166 if (!this->semaphore)
167 {
168 HANDLE handle = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL);
169 n_assert(NULL != handle);
170 if (InterlockedCompareExchangePointer(&this->semaphore, handle, NULL))
171 CloseHandle(handle); // we're late
172 }
173}
174
175//------------------------------------------------------------------------------
178inline bool
179Win32CriticalSection::PerfLock(DWORD dwThreadID) const
180{
181 // Attempt spin-lock
182 for (DWORD dwSpin = 0; dwSpin < spinMax; dwSpin++)
183 {
184 if (this->PerfLockImmediate(dwThreadID))
185 return true;
186
187 YieldProcessor();
188 }
189
190 // Ensure we have the kernel event created
191 this->AllocateKernelSemaphore();
192
193 // do a more expensive lock
194 bool result = this->PerfLockKernel(dwThreadID);
195 this->WaiterMinus();
196
197 return result;
198}
199
200//------------------------------------------------------------------------------
203inline bool
204Win32CriticalSection::PerfLockKernel(DWORD dwThreadID) const
205{
206 bool waiter = false;
207
208 for (;;)
209 {
210 if (!waiter)
211 this->WaiterPlus();
212
213 if (PerfLockImmediate(dwThreadID))
214 return true;
215
216 n_assert(this->semaphore);
217 switch (WaitForSingleObject(this->semaphore, INFINITE))
218 {
219 case WAIT_OBJECT_0:
220 waiter = false;
221 break;
222 case WAIT_TIMEOUT:
223 waiter = true;
224 break;
225 default:
226 break;
227 };
228 }
229 // unreachable
230 //return false;
231}
232
233//------------------------------------------------------------------------------
236inline void
238{
239 if (--recursiveLockCount == 0)
240 {
241 this->PerfUnlock();
242 }
243}
244
245//------------------------------------------------------------------------------
248inline void
249Win32CriticalSection::PerfUnlock() const
250{
251 _WriteBarrier(); // changes done to the shared resource are committed.
252
253 this->lockerThread = 0;
254
255 _ReadWriteBarrier(); // The CS is released.
256
257 if (this->waiterCount > 0) // AFTER it is released we check if there're waiters.
258 {
259 WaiterMinus();
260 ReleaseSemaphore(this->semaphore, 1, NULL);
261 }
262}
263#endif
264};
265//------------------------------------------------------------------------------
Win32-implementation of critical section.
Definition win32criticalsection.h:32
~Win32CriticalSection()
destructor
Definition win32criticalsection.h:86
Win32CriticalSection()
constructor
Definition win32criticalsection.h:77
CRITICAL_SECTION criticalSection
Definition win32criticalsection.h:68
void Leave() const
leave the critical section
Definition win32criticalsection.h:104
void Enter() const
enter the critical section
Definition win32criticalsection.h:95
#define n_assert(exp)
Definition debug.h:50
SemaphoreId CreateSemaphore(const SemaphoreCreateInfo &info)
create semaphore
Definition vksemaphore.cc:37
[TODO: Describe Win32 subsystem]
unsigned int uint
Definition types.h:31