uLib  User mode C/C++ extended API library for Win32 programmers.
SyncObj.cpp
Go to the documentation of this file.
1 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 // Project: uLib - User mode library.
3 // Module: Class wraps for standard IPC sychronization objects.
4 // Author: Copyright (c) Love Nystrom
5 // License: NNOSL (BSD descendant, see NNOSL.txt in the base directory).
6 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7 
8 #include <uLib/SyncObj.h>
9 #include <uLib/Debug.h>
10 
11 #if defined(_DEBUG) && defined( HAVE_STRUCTURED_EH )
12  #define SYNCOBJ_DBG_SEH 1
13  static ACSTR GetCritSecExcName( DWORD xCode )
14  {
15  return (xCode == STATUS_NO_MEMORY)
16  ? "STATUS_NO_MEMORY" : GetExceptionName( xCode );
17  }
18  //#ifdef _MSC_VER
19  // #define __FUNC __FUNCTION__
20  //#else // gcc
21  // #define __FUNC __func__
22  //#endif
23 #else
24  #define SYNCOBJ_DBG_SEH 0
25 #endif
26 
27 //==---------------------------------------------------------------------------
28 
30 {
31  memset( &_cSec, 0, sizeof(CRITICAL_SECTION) ); // Make dbg easier
32  // WinSrv2k3 & WinXP/2k: InitializeCriticalSection can raise STATUS_NO_MEMORY!
33  #if SYNCOBJ_DBG_SEH
34  __try { InitializeCriticalSection( &_cSec ); }
36  {
37  ACSTR xName = GetCritSecExcName( GetExceptionCode());
38  TRACE( DP_FATAL, _F("InitializeCriticalSection: %s\n"), xName );
39  BREAK();
40  }
41  #else
42  InitializeCriticalSection( &_cSec );
43  #endif
44 }
45 
47 {
48  memset( &_cSec, 0, sizeof(CRITICAL_SECTION) );
49  #if SYNCOBJ_DBG_SEH
50  __try { InitializeCriticalSectionAndSpinCount( &_cSec, SpinCount ); }
52  {
53  ACSTR xName = GetCritSecExcName( GetExceptionCode());
54  TRACE( DP_FATAL, _F("InitializeCriticalSection: %s\n"), xName );
55  BREAK();
56  }
57  #else
58  InitializeCriticalSectionAndSpinCount( &_cSec, SpinCount );
59  #endif
60 }
61 
63 {
64  DeleteCriticalSection( &_cSec );
65 }
66 
68 {
69  return SetCriticalSectionSpinCount( &_cSec, SpinCount );
70 }
71 
72 #if SYNCOBJ_DBG_SEH
73 
74 // [MSDN] EnterCriticalSection() can raise EXCEPTION_POSSIBLE_DEADLOCK
75 // if a wait operation on the critical section times out.
76 // Win2k/NT: In low memory situations, EnterCriticalSection can raise an exception.
77 // Do *not* handle these exceptions; instead, debug the application.
78 
79 static DWORD __csectExFilter( IN PEXCEPTION_POINTERS pexPtr, CSTR Where )
80 {
81  // Capture, but don't handle, a possible EXCEPTION_POSSIBLE_DEADLOCK or STATUS_NO_MEMORY.
82  ACSTR xName = GetCritSecExcName( pexPtr->ExceptionRecord->ExceptionCode );
83  // Hmm.. It's kinda impressive that we can raise other exceptions,
84  // (DBG_PRINTEXCEPTION_C and EXCEPTION_BREAKPOINT), inside the exception filter,
85  // that is, before the stack is unwound. I'll call that solid :)
86  DPrint( DP_ERROR, _F("%s in %s. Debug Your program!\n"), xName, Where );
87  BREAK(); // Break if a debugger is present, else show MsgBox.
88  // Proceed to the "unhandled exception" filter in *all cases*.
89  return EXCEPTION_CONTINUE_SEARCH;
90 }
91 #endif //SYNCOBJ_DBG_SEH
92 
94 {
95  #if SYNCOBJ_DBG_SEH
96  __try { EnterCriticalSection( &_cSec ); }
97  __except( __csectExFilter( GetExceptionInformation(), (CSTR)__FUNCTION__ ))
98  {
99  // Agh.. We said EXCEPTION_CONTINUE_SEARCH, so if we get here
100  // something is *broken* in the system or in the compiler !!
101  DWORD xCode = GetExceptionCode();
102  ACSTR xName = GetCritSecExcName( xCode );
103  DPrint( DP_ERROR, _F("SERIOUS ERROR: Broken handling of %s!\n"), xName );
104  BREAK();
105  }
106  #else
107  EnterCriticalSection( &_cSec );
108  #endif
109 }
110 
112 {
113  return bool_cast( TryEnterCriticalSection( &_cSec ));
114 }
115 
117 {
118  LeaveCriticalSection( &_cSec );
119 }
120 
121 //==---------------------------------------------------------------------------
122 
124 : _hSync( NULL )
125 {}
126 
127 TSyncObj::TSyncObj( const HANDLE& Src )
128 : _hSync( Src )
129 {}
130 
132 {
133  Close();
134 }
135 
137 {
139  return (_hSync == NULL);
140 }
141 
142 static bool __CheckWaitResult( DWORD rc )
143 {
144  bool ok = (rc == WAIT_OBJECT_0);
145 
146  // In case of WAIT_FAILED, the error has already been set.
147  // If not, then store the wait result.
148 
149  if (!ok && (rc != WAIT_FAILED)) SetLastError( rc );
150  return ok;
151 }
152 
153 bool TSyncObj::Wait( DWORD msWait )
154 {
155  bool ok = Initialized();
156  if (!ok) SetLastError( ERROR_INVALID_HANDLE );
157  else
158  {
159  DWORD rc = WaitForSingleObject( _hSync, msWait );
160  ok = __CheckWaitResult( rc );
161  }
162  return ok;
163 }
164 
165 bool TSyncObj::WaitEx( DWORD msWait, bool Alertable )
166 {
167  bool ok = Initialized();
168  if (!ok) SetLastError( ERROR_INVALID_HANDLE );
169  else
170  {
171  DWORD rc = WaitForSingleObjectEx( _hSync, msWait, Alertable );
172  ok = __CheckWaitResult( rc );
173  }
174  return ok;
175 }
176 
177 bool TSyncObj::SignalAndWait( HANDLE hWaitFor, DWORD msWait, bool Alertable )
178 {
179  bool ok = Initialized();
180  if (!ok) SetLastError( ERROR_INVALID_HANDLE );
181  else
182  {
183  DWORD rc = SignalObjectAndWait( _hSync, hWaitFor, msWait, Alertable );
184  ok = __CheckWaitResult( rc );
185  }
186  return ok;
187 }
188 
189 HANDLE TSyncObj::RegisterWait( WAITORTIMERCALLBACK Callback, PVOID Context, DWORD msWait, DWORD Flags )
190 {
191  HANDLE hWaitObj = NULL;
192  if (!Initialized()) SetLastError( ERROR_INVALID_HANDLE );
193  else
194  {
195  RegisterWaitForSingleObject( &hWaitObj, _hSync, Callback, Context, msWait, Flags );
196  }
197  return hWaitObj;
198 }
199 
200 bool TSyncObj::UnregisterWait( HANDLE hWait )
201 {
202  return bool_cast( ::UnregisterWait( hWait ));
203 }
204 
205 HANDLE TSyncObj::Duplicate( HANDLE TargetProc, bool Inherit, ACCESS_MASK Access, DWORD Opt )
206 {
207  HANDLE hTrg = NULL, hProc = GetCurrentProcess();
208  if (!Initialized()) SetLastError( ERROR_INVALID_HANDLE );
209  else
210  {
211  Opt &= ~DUPLICATE_CLOSE_SOURCE; // Prevent suicide
212  DuplicateHandle( hProc, _hSync, TargetProc, &hTrg, Access, Inherit, Opt );
213  }
214  return hTrg;
215 }
216 
217 //==---------------------------------------------------------------------------
218 
219 TEvent::TEvent( LPSECURITY_ATTRIBUTES SecAttr, bool Manual, bool Init, CSTR Name )
220 : TSyncObj()
221 {
222  _hSync = CreateEvent( SecAttr, Manual, Init, Name );
223 }
224 
225 TEvent::TEvent( DWORD Access, bool Inherit, CSTR Name )
226 : TSyncObj()
227 {
228  _hSync = OpenEvent( Access, Inherit, Name );
229 }
230 
232 {
233  Set(); // Schedule any pending waiter before dying.
234 }
235 
237 {
238  return bool_cast( SetEvent( _hSync ));
239 }
240 
242 {
243  return bool_cast( ResetEvent( _hSync ));
244 }
245 
247 {
248  return bool_cast( PulseEvent( _hSync ));
249 }
250 
251 //==---------------------------------------------------------------------------
252 
253 TMutex::TMutex( LPSECURITY_ATTRIBUTES SecAttr, bool Own, CSTR Name )
254 : TSyncObj()
255 {
256  _hSync = CreateMutex( SecAttr, Own, Name );
257 }
258 
259 TMutex::TMutex( DWORD Access, bool Inherit, CSTR Name )
260 : TSyncObj()
261 {
262  _hSync = OpenMutex( Access, Inherit, Name );
263 }
264 
266 {
267  Release(); // Schedule any pending waiter before dying.
268 }
269 
271 {
272  return bool_cast( ReleaseMutex( _hSync ));
273 }
274 
275 //==---------------------------------------------------------------------------
276 
277 TSemaphore::TSemaphore( LPSECURITY_ATTRIBUTES SecAttr, LONG Count, LONG MaxCount, CSTR Name )
278 : TSyncObj()
279 {
280  _hSync = CreateSemaphore( SecAttr, Count, MaxCount, Name );
281 }
282 
283 TSemaphore::TSemaphore( DWORD Access, bool Inherit, CSTR Name )
284 : TSyncObj()
285 {
286  _hSync = OpenSemaphore( Access, Inherit, Name );
287 }
288 
290 {
291  ReleaseAll(); // Schedule pending waiters before dying.
292 }
293 
294 bool TSemaphore::Release( LONG Count, LPLONG OldCount )
295 {
296  if (OldCount) *OldCount = 0;
297  return bool_cast( ReleaseSemaphore( _hSync, Count, OldCount ));
298 }
299 
301 {
302  LONG Count = 0;
303 
304  // Release to the hilt.
305 
306  if (!_hSync) SetLastError( ERROR_INVALID_HANDLE );
307  else if (ReleaseSemaphore( _hSync, 1, &Count ) && (Count > 1))
308  ReleaseSemaphore( _hSync, Count-1, NULL );
309  return Count; // Nr released
310 }
311 
313 {
314  LONG Count = 0;
315 
316  // Eat up all available to set it to unsignaled.
317 
318  if (!_hSync) SetLastError( ERROR_INVALID_HANDLE );
319  else while (WaitFor( _hSync,0 )) Count++;
320  return Count; // Nr consumed
321 }
322 
323 //==---------------------------------------------------------------------------
324 
325 TWaitTimer::TWaitTimer( LPSECURITY_ATTRIBUTES SecAttr, bool Manual, CSTR Name )
326 {
327  _hSync = CreateWaitableTimer( SecAttr, Manual, Name );
328 }
329 
330 TWaitTimer::TWaitTimer( DWORD Access, bool Inherit, CSTR Name )
331 {
332  _hSync = OpenWaitableTimer( Access, Inherit, Name );
333 }
334 
336 {
337  Cancel(); // Hmm.. Not releasing waiters like the other sync objects.
338 }
339 
340 bool TWaitTimer::Set( FILETIME Due, LONG Period, PTIMERAPCROUTINE Action, PVOID Context, bool Resume )
341 {
342  ULARGE_INTEGER due = { Due.dwLowDateTime, Due.dwHighDateTime }; // Since FILETIME might have different alignment!
343  return bool_cast( SetWaitableTimer( _hSync, (LARGE_INTEGER*)&due, Period, Action, Context, Resume ));
344 }
345 
346 
347 bool TWaitTimer::Set( INT64 Due, LONG Period, PTIMERAPCROUTINE Action, PVOID Context, bool Resume )
348 {
349  LARGE_INTEGER due;
350  due.QuadPart = (Due < 0) ? Due : -Due;
351  bool ok = bool_cast( SetWaitableTimer( _hSync, &due, Period, Action, Context, Resume ));
352  //if (ok) WaitForSingleObject( _hSync,0 );
353  return ok;
354 }
355 
357 {
358  return bool_cast( CancelWaitableTimer( _hSync ));
359 }
360 
361 //==---------------------------------------------------------------------------
362 #undef SYNCOBJ_DBG_SEH
363 // EOF
CRITICAL_SECTION _cSec
Definition: SyncObj.h:51
HANDLE CloseHandleEx(HANDLE H)
Definition: KernelUtil.cpp:80
unsigned long DWORD
Definition: Common.h:414
TSemaphore(LPSECURITY_ATTRIBUTES SecAttr, LONG Count, LONG MaxCount, CSTR Name=NULL)
Definition: SyncObj.cpp:277
bool Initialized()
Definition: SyncObj.h:99
const char * ACSTR
Definition: Common.h:345
bool UnregisterWait(HANDLE hWait)
Definition: SyncObj.cpp:200
#define CSTR
Definition: Common.h:329
bool WaitFor(HANDLE hObj, DWORD msWait)
Definition: KernelUtil.cpp:95
bool Release(LONG Count, OPTOUT LPLONG OldCount=NULL)
Definition: SyncObj.cpp:294
~TCritSec()
Definition: SyncObj.cpp:62
~TMutex()
Definition: SyncObj.cpp:265
TSyncObj()
Definition: SyncObj.cpp:123
bool WaitEx(DWORD msWait, bool Alertable)
Definition: SyncObj.cpp:165
bool Cancel()
Definition: SyncObj.cpp:356
void __cdecl DPrint(int Level, CSTR Fmt,...)
Definition: Debug.cpp:134
bool Reset()
Definition: SyncObj.cpp:241
bool Wait(DWORD msWait)
Definition: SyncObj.cpp:153
~TEvent()
Definition: SyncObj.cpp:231
UINT Count
Definition: StrFunc.h:785
#define TRACE(_lvl,...)
Definition: Debug.h:216
bool Release()
Definition: SyncObj.cpp:270
#define __except_execute
Definition: Common.h:647
~TSyncObj()
Definition: SyncObj.cpp:131
#define BREAK()
Definition: Debug.h:208
TWaitTimer(LPSECURITY_ATTRIBUTES SecAttr, bool Manual, CSTR Name=NULL)
Definition: SyncObj.cpp:325
void Leave()
Definition: SyncObj.cpp:116
HANDLE RegisterWait(WAITORTIMERCALLBACK Callback, PVOID Context, DWORD msWait, DWORD Flags)
Definition: SyncObj.cpp:189
bool Set(FILETIME Due, LONG Period, PTIMERAPCROUTINE Action, PVOID Context, bool Resume)
Definition: SyncObj.cpp:340
HANDLE _hSync
Definition: SyncObj.h:79
signed __int64 INT64
Definition: Common.h:401
LONG ReleaseAll()
Definition: SyncObj.cpp:300
bool __forceinline bool_cast(BOOL B52)
Definition: Common.h:767
LONG Lock()
Definition: SyncObj.cpp:312
bool TryEnter()
Definition: SyncObj.cpp:111
#define DP_FATAL
Definition: Debug.h:80
#define DP_ERROR
Definition: Debug.h:82
Debug and error handling support.
TCritSec()
Definition: SyncObj.cpp:29
TEvent(LPSECURITY_ATTRIBUTES SecAttr, bool Manual, bool Init, CSTR Name=NULL)
Definition: SyncObj.cpp:219
bool SignalAndWait(HANDLE hWaitFor, DWORD msWait, bool Alertable)
Definition: SyncObj.cpp:177
bool Pulse()
Note: Documented as unreliable. Included just for completeness.
Definition: SyncObj.cpp:246
#define _F(s)
Definition: Debug.h:49
bool Close()
Definition: SyncObj.cpp:136
bool Set()
Definition: SyncObj.cpp:236
ACSTR GetExceptionName(DWORD xCode)
Definition: MsgTbl.cpp:641
HANDLE Duplicate(HANDLE TargetProc, bool Inherit, ACCESS_MASK Access=0, DWORD Opt=DUPLICATE_SAME_ACCESS)
Definition: SyncObj.cpp:205
DWORD SetSpinCount(DWORD SpinCount)
Definition: SyncObj.cpp:67
TMutex(LPSECURITY_ATTRIBUTES SecAttr, bool Own, CSTR Name=NULL)
Definition: SyncObj.cpp:253
void Enter()
Definition: SyncObj.cpp:93