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.

612 lines
12 KiB

  1. /*++
  2. Copyright (c) 1999-2000 Microsoft Corporation
  3. Module Name:
  4. locks.h
  5. Abstract:
  6. Various C++ class for sync. object
  7. Author:
  8. HueiWang 2/17/2000
  9. --*/
  10. #ifndef __LOCKS_H
  11. #define __LOCKS_H
  12. #include <windows.h>
  13. #include <winbase.h>
  14. #include "assert.h"
  15. #define ARRAY_COUNT(a) sizeof(a) / sizeof(a[0])
  16. //
  17. // Semaphore template
  18. //
  19. template <int init_count, int max_count>
  20. class CTSemaphore
  21. {
  22. private:
  23. HANDLE m_semaphore;
  24. public:
  25. CTSemaphore() : m_semaphore(NULL)
  26. {
  27. m_semaphore = CreateSemaphore(
  28. NULL,
  29. init_count,
  30. max_count,
  31. NULL
  32. );
  33. assert(m_semaphore != NULL);
  34. }
  35. ~CTSemaphore()
  36. {
  37. if(m_semaphore)
  38. {
  39. CloseHandle(m_semaphore);
  40. }
  41. }
  42. DWORD
  43. Acquire(
  44. int WaitTime=INFINITE,
  45. BOOL bAlertable=FALSE
  46. )
  47. /*++
  48. --*/
  49. {
  50. return WaitForSingleObjectEx(
  51. m_semaphore,
  52. WaitTime,
  53. bAlertable
  54. );
  55. }
  56. BOOL
  57. AcquireEx(
  58. HANDLE hHandle,
  59. int dwWaitTime=INFINITE,
  60. BOOL bAlertable=FALSE
  61. )
  62. /*++
  63. --*/
  64. {
  65. BOOL bSuccess = TRUE;
  66. DWORD dwStatus;
  67. HANDLE hHandles[] = {m_semaphore, hHandle};
  68. if(hHandle == NULL || hHandle == INVALID_HANDLE_VALUE)
  69. {
  70. SetLastError(ERROR_INVALID_PARAMETER);
  71. bSuccess = FALSE;
  72. }
  73. else
  74. {
  75. dwStatus = WaitForMultipleObjectsEx(
  76. sizeof(hHandles)/sizeof(hHandles[0]),
  77. hHandles,
  78. FALSE,
  79. dwWaitTime,
  80. bAlertable
  81. );
  82. if(dwStatus != WAIT_OBJECT_0)
  83. {
  84. bSuccess = FALSE;
  85. }
  86. }
  87. return bSuccess;
  88. }
  89. BOOL Release(long count=1)
  90. {
  91. return ReleaseSemaphore(m_semaphore, count, NULL);
  92. }
  93. BOOL IsGood()
  94. {
  95. return m_semaphore != NULL;
  96. }
  97. };
  98. //
  99. // Critical section C++ class.
  100. //
  101. class CCriticalSection
  102. {
  103. CRITICAL_SECTION m_CS;
  104. BOOL m_bGood;
  105. public:
  106. CCriticalSection(
  107. DWORD dwSpinCount = 4000 // see InitializeCriticalSection...
  108. ) : m_bGood(TRUE)
  109. {
  110. __try {
  111. InitializeCriticalSectionAndSpinCount(&m_CS, dwSpinCount);
  112. }
  113. __except(EXCEPTION_EXECUTE_HANDLER)
  114. {
  115. SetLastError(GetExceptionCode());
  116. m_bGood = FALSE;
  117. }
  118. }
  119. ~CCriticalSection()
  120. {
  121. if(IsGood() == TRUE)
  122. {
  123. DeleteCriticalSection(&m_CS);
  124. m_bGood = FALSE;
  125. }
  126. }
  127. BOOL
  128. IsGood()
  129. {
  130. return m_bGood;
  131. }
  132. void Lock()
  133. {
  134. EnterCriticalSection(&m_CS);
  135. }
  136. void UnLock()
  137. {
  138. LeaveCriticalSection(&m_CS);
  139. }
  140. BOOL TryLock()
  141. {
  142. return TryEnterCriticalSection(&m_CS);
  143. }
  144. };
  145. //
  146. // Critical section locker, this class lock the critical section
  147. // at object constructor and release object at destructor, purpose is to
  148. // prevent forgoting to release a critical section.
  149. //
  150. // usage is
  151. //
  152. // void
  153. // Foo( void )
  154. // {
  155. // CCriticalSectionLocker l( <some CCriticalSection instance> )
  156. //
  157. // }
  158. //
  159. //
  160. class CCriticalSectionLocker
  161. {
  162. private:
  163. CCriticalSection& m_cs;
  164. public:
  165. CCriticalSectionLocker( CCriticalSection& m ) : m_cs(m)
  166. {
  167. m.Lock();
  168. }
  169. ~CCriticalSectionLocker()
  170. {
  171. m_cs.UnLock();
  172. }
  173. };
  174. //
  175. // Safe counter class.
  176. //
  177. class CSafeCounter
  178. {
  179. private:
  180. long m_Counter;
  181. public:
  182. CSafeCounter(
  183. long init_value=0
  184. ) :
  185. m_Counter(init_value)
  186. /*++
  187. --*/
  188. {
  189. }
  190. ~CSafeCounter()
  191. {
  192. }
  193. operator+=(long dwValue)
  194. {
  195. long dwNewValue;
  196. dwNewValue = InterlockedExchangeAdd(
  197. &m_Counter,
  198. dwValue
  199. );
  200. return dwNewValue += dwValue;
  201. }
  202. operator-=(long dwValue)
  203. {
  204. long dwNewValue;
  205. dwNewValue = InterlockedExchangeAdd(
  206. &m_Counter,
  207. -dwValue
  208. );
  209. return dwNewValue -= dwValue;
  210. }
  211. operator++()
  212. {
  213. return InterlockedIncrement(&m_Counter);
  214. }
  215. operator++(int)
  216. {
  217. long lValue;
  218. lValue = InterlockedIncrement(&m_Counter);
  219. return --lValue;
  220. }
  221. operator--()
  222. {
  223. return InterlockedDecrement(&m_Counter);
  224. }
  225. operator--(int)
  226. {
  227. long lValue;
  228. lValue = InterlockedDecrement(&m_Counter);
  229. return ++lValue;
  230. }
  231. operator long()
  232. {
  233. return InterlockedExchange(&m_Counter, m_Counter);
  234. }
  235. operator=(const long dwValue)
  236. {
  237. InterlockedExchange(&m_Counter, dwValue);
  238. return dwValue;
  239. }
  240. };
  241. //-------------------------------------------------------------------------
  242. //
  243. // Reader/Writer lock, modified from MSDN
  244. //
  245. typedef enum {
  246. WRITER_LOCK,
  247. READER_LOCK,
  248. NO_LOCK
  249. } RWLOCK_TYPE;
  250. class CRWLock
  251. {
  252. private:
  253. HANDLE hMutex;
  254. HANDLE hWriterMutex;
  255. HANDLE hReaderEvent;
  256. long iReadCount;
  257. long iWriteCount;
  258. long iReadEntry;
  259. long iWriteEntry;
  260. public:
  261. CRWLock()
  262. {
  263. BOOL bSuccess=Init();
  264. assert(bSuccess == TRUE);
  265. }
  266. ~CRWLock()
  267. {
  268. Cleanup();
  269. }
  270. //-----------------------------------------------------------
  271. BOOL
  272. Init()
  273. {
  274. hReaderEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
  275. hMutex = CreateEvent(NULL,FALSE,TRUE,NULL);
  276. hWriterMutex = CreateMutex(NULL,FALSE,NULL);
  277. if(!hReaderEvent || !hMutex || !hWriterMutex)
  278. return FALSE;
  279. iReadCount = -1;
  280. iWriteCount = -1;
  281. iReadEntry = 0;
  282. iWriteEntry = 0;
  283. return (TRUE);
  284. }
  285. //-----------------------------------------------------------
  286. void
  287. Cleanup()
  288. {
  289. CloseHandle(hReaderEvent);
  290. CloseHandle(hMutex);
  291. CloseHandle(hWriterMutex);
  292. iReadCount = -1;
  293. iWriteCount = -1;
  294. iReadEntry = 0;
  295. iWriteEntry = 0;
  296. }
  297. //-----------------------------------------------------------
  298. void
  299. Acquire(
  300. RWLOCK_TYPE lockType
  301. )
  302. /*++
  303. ++*/
  304. {
  305. if (lockType == WRITER_LOCK)
  306. {
  307. InterlockedIncrement(&iWriteCount);
  308. WaitForSingleObject(hWriterMutex,INFINITE);
  309. WaitForSingleObject(hMutex, INFINITE);
  310. assert(InterlockedIncrement(&iWriteEntry) == 1);
  311. assert(InterlockedExchange(&iReadEntry, iReadEntry) == 0);
  312. }
  313. else
  314. {
  315. if (InterlockedIncrement(&iReadCount) == 0)
  316. {
  317. WaitForSingleObject(hMutex, INFINITE);
  318. SetEvent(hReaderEvent);
  319. }
  320. WaitForSingleObject(hReaderEvent,INFINITE);
  321. InterlockedIncrement(&iReadEntry);
  322. assert(InterlockedExchange(&iWriteEntry, iWriteEntry) == 0);
  323. }
  324. }
  325. //-----------------------------------------------------------
  326. void
  327. Release(
  328. RWLOCK_TYPE lockType
  329. )
  330. /*++
  331. ++*/
  332. {
  333. if (lockType == WRITER_LOCK)
  334. {
  335. InterlockedDecrement(&iWriteEntry);
  336. InterlockedDecrement(&iWriteCount);
  337. SetEvent(hMutex);
  338. ReleaseMutex(hWriterMutex);
  339. }
  340. else if(lockType == READER_LOCK)
  341. {
  342. InterlockedDecrement(&iReadEntry);
  343. if (InterlockedDecrement(&iReadCount) < 0)
  344. {
  345. ResetEvent(hReaderEvent);
  346. SetEvent(hMutex);
  347. }
  348. }
  349. }
  350. long GetReadCount()
  351. {
  352. return iReadCount+1;
  353. }
  354. long GetWriteCount()
  355. {
  356. return iWriteCount+1;
  357. }
  358. };
  359. //---------------------------------------------------------------------
  360. class CCMutex
  361. {
  362. HANDLE hMutex;
  363. public:
  364. CCMutex() : hMutex(NULL) {
  365. hMutex=CreateMutex(NULL, FALSE, NULL);
  366. }
  367. ~CCMutex() {
  368. CloseHandle(hMutex);
  369. }
  370. DWORD
  371. Lock(
  372. DWORD dwWaitTime=INFINITE,
  373. BOOL bAlertable=FALSE
  374. )
  375. /*++
  376. --*/
  377. {
  378. return WaitForSingleObjectEx(
  379. hMutex,
  380. dwWaitTime,
  381. bAlertable
  382. );
  383. }
  384. BOOL
  385. Unlock()
  386. {
  387. return ReleaseMutex(hMutex);
  388. }
  389. };
  390. //---------------------------------------------------------------------------------
  391. class CCEvent
  392. {
  393. BOOL bManual;
  394. HANDLE hEvent;
  395. public:
  396. CCEvent(
  397. BOOL bManual,
  398. BOOL bInitState
  399. ) :
  400. hEvent(NULL),
  401. bManual(bManual)
  402. /*++
  403. --*/
  404. {
  405. hEvent=CreateEvent(
  406. NULL,
  407. bManual,
  408. bInitState,
  409. NULL
  410. );
  411. }
  412. ~CCEvent()
  413. {
  414. if( NULL != hEvent )
  415. {
  416. CloseHandle(hEvent);
  417. }
  418. }
  419. DWORD
  420. MsgLock(
  421. DWORD dwWaitTime = INFINITE
  422. )
  423. /*++
  424. --*/
  425. {
  426. HANDLE wait_event[1] = {hEvent};
  427. DWORD result ;
  428. MSG msg ;
  429. // The message loop lasts until we get a WM_QUIT message,
  430. // upon which we shall return from the function.
  431. while (TRUE)
  432. {
  433. // block-local variable
  434. // Read all of the messages in this next loop,
  435. // removing each message as we read it.
  436. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  437. {
  438. // If it's a quit message, we're out of here.
  439. if (msg.message == WM_QUIT)
  440. {
  441. return WAIT_ABANDONED;
  442. }
  443. // Otherwise, dispatch the message.
  444. DispatchMessage(&msg);
  445. } // End of PeekMessage while loop.
  446. // Wait for any message sent or posted to this queue
  447. // or for one of the passed handles be set to signaled.
  448. result = MsgWaitForMultipleObjects(
  449. 1,
  450. wait_event,
  451. TRUE,
  452. dwWaitTime,
  453. QS_ALLINPUT | QS_ALLPOSTMESSAGE | QS_ALLEVENTS
  454. );
  455. // The result tells us the type of event we have.
  456. if (result == WAIT_OBJECT_0 + 1)
  457. {
  458. // New messages have arrived.
  459. // Continue to the top of the always while loop to
  460. // dispatch them and resume waiting.
  461. continue;
  462. }
  463. else
  464. {
  465. break;
  466. } // End of else clause.
  467. } // End of the always while loop.
  468. return result;
  469. }
  470. DWORD
  471. Lock(
  472. DWORD dwWaitTime=INFINITE,
  473. BOOL bAlertable=FALSE
  474. )
  475. /*++
  476. --*/
  477. {
  478. return WaitForSingleObjectEx(
  479. hEvent,
  480. dwWaitTime,
  481. bAlertable
  482. );
  483. }
  484. BOOL
  485. SetEvent()
  486. {
  487. return ::SetEvent(hEvent);
  488. }
  489. BOOL
  490. ResetEvent()
  491. {
  492. return ::ResetEvent(hEvent);
  493. }
  494. BOOL
  495. PulseEvent()
  496. {
  497. return ::PulseEvent(hEvent);
  498. }
  499. BOOL
  500. IsManual()
  501. {
  502. return bManual;
  503. }
  504. };
  505. #endif