Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

545 lines
14 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1991 - 2000.
  5. //
  6. // File: CiSem.Hxx
  7. //
  8. // Contents: Semaphore classes
  9. //
  10. // Classes: CMutexSem - Mutex semaphore class
  11. // CStaticMutexSem - statically allocated Mutex semaphore class
  12. // CEventSem - Event semaphore
  13. //
  14. // History: 21-Jun-91 AlexT Created.
  15. //
  16. //----------------------------------------------------------------------------
  17. #pragma once
  18. //+---------------------------------------------------------------------------
  19. //
  20. // Class: CMutexSem (mxs)
  21. //
  22. // Purpose: Mutex Semaphore services
  23. //
  24. // Interface: Request - acquire semaphore
  25. // Release - release semaphore
  26. //
  27. // History: 14-Jun-91 AlexT Created.
  28. // 30-oct-91 SethuR 32 bit implementation
  29. //
  30. // Notes: This class wraps a mutex semaphore. Mutex semaphores protect
  31. // access to resources by only allowing one client through at a
  32. // time. The client Requests the semaphore before accessing the
  33. // resource and Releases the semaphore when it is done. The
  34. // same client can Request the semaphore multiple times (a nest
  35. // count is maintained).
  36. //
  37. //----------------------------------------------------------------------------
  38. class CMutexSem
  39. {
  40. public:
  41. CMutexSem()
  42. {
  43. InitializeCriticalSection( &_cs );
  44. _fInitedCS = TRUE;
  45. }
  46. CMutexSem(BOOL fInit)
  47. {
  48. if (fInit)
  49. {
  50. InitializeCriticalSection( &_cs );
  51. _fInitedCS = TRUE;
  52. }
  53. else
  54. {
  55. memset( &_cs, 0, sizeof _cs );
  56. _fInitedCS = FALSE;
  57. }
  58. }
  59. ~CMutexSem()
  60. {
  61. if (_fInitedCS)
  62. {
  63. DeleteCriticalSection( &_cs );
  64. _fInitedCS = FALSE;
  65. }
  66. }
  67. void Init()
  68. {
  69. InitializeCriticalSection(&_cs);
  70. _fInitedCS = TRUE;
  71. }
  72. void Request()
  73. {
  74. #if DBG == 1
  75. if (!_fInitedCS)
  76. DbgPrint( "CMutexSem not initialized!\n" );
  77. #endif
  78. EnterCriticalSection( &_cs );
  79. }
  80. void Release()
  81. {
  82. LeaveCriticalSection( &_cs );
  83. }
  84. BOOL Try()
  85. {
  86. return TryEnterCriticalSection( &_cs );
  87. }
  88. BOOL IsHeld()
  89. {
  90. return ( LongToHandle( GetCurrentThreadId() ) == _cs.OwningThread );
  91. }
  92. protected:
  93. BOOL _fInitedCS;
  94. CRITICAL_SECTION _cs;
  95. };
  96. //+---------------------------------------------------------------------------
  97. //
  98. // Class: CStaticMutexSem
  99. //
  100. // Purpose: Mutex Semaphore services
  101. //
  102. // Interface: Init - initializer (two-step)
  103. // Request - acquire semaphore
  104. // Release - release semaphore
  105. //
  106. // History: 20 May 99 AlawW Created.
  107. //
  108. // Notes: Like a CMutexSem, but initialization is deferred. Useful
  109. // for statically allocated critical sections where there is
  110. // the (unlikely) potential to get a STATUS_NO_MEMORY exception
  111. // thrown from the InitializeCriticalSection call.
  112. //
  113. //----------------------------------------------------------------------------
  114. class CStaticMutexSem : public CMutexSem
  115. {
  116. public:
  117. CStaticMutexSem( ) : CMutexSem( FALSE ) {}
  118. };
  119. //+---------------------------------------------------------------------------
  120. //
  121. // Class: CLock (lck)
  122. //
  123. // Purpose: Lock using a Mutex Semaphore
  124. //
  125. // History: 02-Oct-91 BartoszM Created.
  126. //
  127. // Notes: Simple lock object to be created on the stack.
  128. // The constructor acquires the semaphor, the destructor
  129. // (called when lock is going out of scope) releases it.
  130. //
  131. //----------------------------------------------------------------------------
  132. class CLock
  133. {
  134. public:
  135. CLock( CMutexSem& mxs ) : _mxs ( mxs )
  136. {
  137. _mxs.Request();
  138. }
  139. ~CLock()
  140. {
  141. _mxs.Release();
  142. }
  143. private:
  144. CMutexSem & _mxs;
  145. };
  146. #define CPriLock CLock
  147. //+---------------------------------------------------------------------------
  148. //
  149. // Class: CReleasableLock
  150. //
  151. // Purpose: Lock using a Mutex Semaphore that can be released/requested
  152. //
  153. // History: 16-Sep-96 dlee Created.
  154. //
  155. //----------------------------------------------------------------------------
  156. class CReleasableLock
  157. {
  158. public:
  159. CReleasableLock( CMutexSem& mxs, BOOL fHeld = TRUE ) :
  160. _fHeld( fHeld ), _mxs(mxs)
  161. {
  162. if ( fHeld )
  163. _mxs.Request();
  164. }
  165. ~CReleasableLock()
  166. {
  167. if ( _fHeld )
  168. _mxs.Release();
  169. }
  170. void Release()
  171. {
  172. Win4Assert( _fHeld );
  173. _mxs.Release();
  174. _fHeld = FALSE;
  175. }
  176. void Request()
  177. {
  178. Win4Assert( !_fHeld );
  179. _mxs.Request();
  180. _fHeld = TRUE;
  181. }
  182. BOOL Try()
  183. {
  184. Win4Assert( !_fHeld );
  185. return ( _fHeld = _mxs.Try() );
  186. }
  187. BOOL IsHeld() const { return _fHeld; }
  188. private:
  189. CMutexSem & _mxs;
  190. BOOL _fHeld;
  191. };
  192. //+---------------------------------------------------------------------------
  193. //
  194. // Class: CEventSem (evs)
  195. //
  196. // Purpose: Event Semaphore services
  197. //
  198. // Interface: Wait - wait for semaphore to be signalled
  199. // Set - set signalled state
  200. // Reset - clear signalled state
  201. // Pulse - set and clear semaphore
  202. //
  203. // History: 21-Jun-91 AlexT Created.
  204. // 27-Feb-92 BartoszM Use exceptions for errors
  205. //
  206. // Notes: Used for communication between consumers and producers.
  207. // Consumer threads block by calling Wait. A producer
  208. // calls Set waking up all the consumers who go ahead
  209. // and consume until there's nothing left. They call
  210. // Reset, release whatever lock protected the resources,
  211. // and call Wait. There has to be a separate lock
  212. // to protect the shared resources.
  213. // Remember: call Reset under lock.
  214. // don't call Wait under lock.
  215. //
  216. //----------------------------------------------------------------------------
  217. class CEventSem
  218. {
  219. public:
  220. inline CEventSem( BOOL fInitState=FALSE, const LPSECURITY_ATTRIBUTES lpsa=NULL );
  221. inline CEventSem( HANDLE hEvent );
  222. inline CEventSem( DWORD dwMustBeZero, WCHAR const * pwszName,
  223. DWORD dwAccess = EVENT_ALL_ACCESS | EVENT_MODIFY_STATE | SYNCHRONIZE );
  224. inline CEventSem( WCHAR const * pwszName,
  225. BOOL fInitState = FALSE,
  226. const LPSECURITY_ATTRIBUTES lpsa = NULL );
  227. HANDLE AcquireHandle()
  228. {
  229. HANDLE hVal = _hEvent;
  230. _hEvent = 0;
  231. return hVal;
  232. }
  233. void Create()
  234. {
  235. Win4Assert( 0 == _hEvent );
  236. _hEvent = CreateEventW( 0, TRUE, FALSE, 0 );
  237. if ( 0 == _hEvent )
  238. THROW( CException() );
  239. }
  240. inline ~CEventSem();
  241. inline ULONG Wait(DWORD dwMilliseconds = INFINITE,
  242. BOOL fAlertable = FALSE );
  243. inline void Set();
  244. inline void Reset();
  245. inline void Pulse();
  246. inline const HANDLE GetHandle() const { return _hEvent; }
  247. private:
  248. HANDLE _hEvent;
  249. };
  250. //+---------------------------------------------------------------------------
  251. //
  252. // Class: CAutoEventSem
  253. //
  254. // Purpose: Auto-reset version of CEventSem
  255. //
  256. // History: 16-Sep-96 dlee Created.
  257. //
  258. //----------------------------------------------------------------------------
  259. class CAutoEventSem
  260. {
  261. public:
  262. CAutoEventSem()
  263. {
  264. _hEvent = CreateEventW( 0, FALSE, FALSE, 0 );
  265. if ( 0 == _hEvent )
  266. THROW( CException() );
  267. }
  268. ~CAutoEventSem()
  269. {
  270. if ( 0 != _hEvent )
  271. {
  272. BOOL f = CloseHandle ( _hEvent );
  273. Win4Assert( f && "can't close event handle" );
  274. }
  275. }
  276. void Set()
  277. {
  278. if ( !SetEvent ( _hEvent ) )
  279. THROW( CException() );
  280. }
  281. void Wait()
  282. {
  283. WaitForSingleObject( _hEvent, INFINITE );
  284. }
  285. const HANDLE GetHandle() const { return _hEvent; }
  286. private:
  287. HANDLE _hEvent;
  288. };
  289. //+---------------------------------------------------------------------------
  290. //
  291. // Class: CEventSetter
  292. //
  293. // Purpose: Sets an event when exiting scope
  294. //
  295. // History: 16-Sep-96 dlee Created.
  296. //
  297. //----------------------------------------------------------------------------
  298. class CEventSetter
  299. {
  300. public:
  301. CEventSetter( CAutoEventSem &event ) : _event( event )
  302. { }
  303. ~CEventSetter() { _event.Set(); }
  304. private:
  305. CAutoEventSem & _event;
  306. };
  307. //+---------------------------------------------------------------------------
  308. //
  309. // Member: CEventSem::CEventSem
  310. //
  311. // Synopsis: Creates an event
  312. //
  313. // Arguments: [bInitState] -- TRUE: signaled state, FALSE non-signaled
  314. // [lpsa] -- security attributes
  315. //
  316. // History: 27-Feb-92 BartoszM Created
  317. //
  318. //----------------------------------------------------------------------------
  319. inline CEventSem::CEventSem ( BOOL bInitState, const LPSECURITY_ATTRIBUTES lpsa )
  320. {
  321. _hEvent = CreateEventW( lpsa, TRUE, bInitState, 0 );
  322. if ( _hEvent == 0 )
  323. {
  324. THROW( CException() );
  325. }
  326. }
  327. //+---------------------------------------------------------------------------
  328. //
  329. // Member: CEventSem::CEventSem
  330. //
  331. // Synopsis: Opens an event
  332. //
  333. // Arguments: [hEvent] -- handle of event to open
  334. // [bInitState] -- TRUE: signaled state, FALSE non-signaled
  335. //
  336. // History: 02-Jul-94 DwightKr Created
  337. //
  338. //----------------------------------------------------------------------------
  339. inline CEventSem::CEventSem ( HANDLE hEvent ) : _hEvent( hEvent )
  340. {
  341. }
  342. //+---------------------------------------------------------------------------
  343. //
  344. // Member: CEventSem::CEventSem
  345. //
  346. // Synopsis: Constructor to "open" an already existing event sem.
  347. //
  348. // Arguments: [dwMustBeZero] - Just to distinguish from the constructor
  349. // used to "create" named event semaphores.
  350. // [pwszName] - Name of the semaphore
  351. // [dwAccess] - Access.
  352. //
  353. // History: 2-15-96 srikants Created
  354. //
  355. // Notes:
  356. //
  357. //----------------------------------------------------------------------------
  358. inline CEventSem::CEventSem( DWORD dwMustBeZero, WCHAR const * pwszName, DWORD dwAccess )
  359. {
  360. Win4Assert( 0 == dwMustBeZero && 0 != pwszName );
  361. _hEvent = OpenEventW( dwAccess, TRUE, pwszName );
  362. if ( 0 == _hEvent )
  363. {
  364. THROW( CException() );
  365. }
  366. }
  367. //+---------------------------------------------------------------------------
  368. //
  369. // Member: CEventSem::CEventSem
  370. //
  371. // Synopsis: Constructor to "create" a named event semaphore.
  372. //
  373. // Arguments: [pwszName] - Name of the event semaphore.
  374. // [fInitState] -
  375. // [lpsa] -
  376. //
  377. // History: 2-15-96 srikants Created
  378. //
  379. // Notes:
  380. //
  381. //----------------------------------------------------------------------------
  382. inline CEventSem::CEventSem( WCHAR const * pwszName, BOOL fInitState,
  383. const LPSECURITY_ATTRIBUTES lpsa )
  384. {
  385. _hEvent = CreateEventW( lpsa, TRUE, fInitState, pwszName );
  386. if ( _hEvent == 0 )
  387. {
  388. THROW( CException() );
  389. }
  390. }
  391. //+---------------------------------------------------------------------------
  392. //
  393. // Member: CEventSem::~CEventSem
  394. //
  395. // Synopsis: Releases event
  396. //
  397. // History: 27-Feb-92 BartoszM Created
  398. //
  399. //----------------------------------------------------------------------------
  400. inline CEventSem::~CEventSem ()
  401. {
  402. if ( 0 != _hEvent )
  403. {
  404. BOOL f = CloseHandle( _hEvent );
  405. Win4Assert( f && "can't close event handle" );
  406. }
  407. }
  408. //+---------------------------------------------------------------------------
  409. //
  410. // Member: CEventSem::Set
  411. //
  412. // Synopsis: Set the state to signaled. Wake up waiting threads.
  413. // For manual events the state remains set
  414. // until Reset is called
  415. //
  416. // History: 27-Feb-92 BartoszM Created
  417. //
  418. //----------------------------------------------------------------------------
  419. inline void CEventSem::Set()
  420. {
  421. if ( !SetEvent ( _hEvent ) )
  422. {
  423. THROW( CException() );
  424. }
  425. }
  426. //+---------------------------------------------------------------------------
  427. //
  428. // Member: CEventSem::Reset
  429. //
  430. // Synopsis: Reset the state to non-signaled. Threads will block.
  431. //
  432. // History: 27-Feb-92 BartoszM Created
  433. //
  434. //----------------------------------------------------------------------------
  435. inline void CEventSem::Reset()
  436. {
  437. if ( !ResetEvent ( _hEvent ) )
  438. {
  439. THROW( CException() );
  440. }
  441. }
  442. //+---------------------------------------------------------------------------
  443. //
  444. // Member: CEventSem::Wait
  445. //
  446. // Synopsis: Block until event set
  447. //
  448. // History: 27-Feb-92 BartoszM Created
  449. //
  450. //----------------------------------------------------------------------------
  451. inline ULONG CEventSem::Wait( DWORD msec, BOOL fAlertable )
  452. {
  453. DWORD res = WaitForSingleObjectEx ( _hEvent, msec, fAlertable );
  454. if ( 0xffffffff == res )
  455. {
  456. THROW( CException() );
  457. }
  458. return res;
  459. }
  460. //+---------------------------------------------------------------------------
  461. //
  462. // Member: CEventSem::Pulse
  463. //
  464. // Synopsis: Set the state to signaled. Wake up waiting threads.
  465. //
  466. // History: 27-Feb-92 BartoszM Created
  467. //
  468. //----------------------------------------------------------------------------
  469. inline void CEventSem::Pulse()
  470. {
  471. if ( !PulseEvent ( _hEvent ) )
  472. {
  473. THROW( CException() );
  474. }
  475. }