Leaked source code of windows server 2003
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.

616 lines
21 KiB

  1. //+-------------------------------------------------------------------
  2. //
  3. // File: syncwrap.hxx
  4. //
  5. // Contents: Wrapper classes for Win32 synchronization objects.
  6. //
  7. // Classes: CMutex - Creates/destroys a Mutex object
  8. // CSemaphore - Creates/destroys a Semaphore object
  9. // CEvent - Creates/destroys an Event object
  10. // CCritSec - Creates/destroys a critical section
  11. // CTCLock - Locks/Unlock one of the above
  12. //
  13. // Functions:
  14. //
  15. // History: 31-Jan-92 BryanT Created
  16. // 04-Feb-92 BryanT Added Critical section support
  17. // 23-Feb-92 BryanT Add OS/2 support for a Critical
  18. // section-like synchronization object.
  19. // Code is stolen from tom\dispatcher
  20. // semaphore class.
  21. // 26-Jun-92 DwightKr Added ifndef MIDL
  22. // 29-Jun-93 DwightKr Changed MIDL to MIDL_PASS *
  23. // 08-Nov-93 DarrylA Changed __WIN32__ to WIN32
  24. // 16-Mar-95 NaveenB Changed NO_ERROR to ERROR_SUCCESS
  25. // and added facility to check the
  26. // status of the constructor using
  27. // QueryError functions in CMutex,
  28. // CSemaphone, CEvent and CTCLock
  29. //
  30. //--------------------------------------------------------------------
  31. #ifndef SYNCWRAP_HXX
  32. #define SYNCWRAP_HXX
  33. #ifndef MIDL_PASS
  34. #if defined (WIN32)
  35. // Make sure windows.h has been included prior to this
  36. #if !defined (_WINDOWS_)
  37. #error windows.h must be included prior to syncwrap.hxx... Aborting.
  38. #endif
  39. #define CMUTEX 1
  40. #define CSEMAPHORE 2
  41. #define CEVENT 3
  42. #define CCRITSEC 4
  43. #ifndef STATUS_POSSIBLE_DEADLOCK
  44. typedef LONG NTSTATUS;
  45. #define STATUS_POSSIBLE_DEADLOCK ((NTSTATUS)0xC0000194L)
  46. #endif
  47. //+-------------------------------------------------------------------
  48. //
  49. // Class: CMutex
  50. //
  51. // Purpose: Wrapper for Win32 Mutexes. Creates an un-named, un-owned
  52. // mutex in an un-signaled state and makes sure it is cleaned
  53. // up when destructed.
  54. //
  55. // Interface: CMutex(lpsa, fInitialOwner, lpszMutexName, fCreate) -
  56. // See CreateMutex/OpenMutex in the Win32 api for the
  57. // definition of the first three arguments. The last
  58. // one indicates if a new mutex should be created
  59. // (TRUE) or an existing one opened (FALSE). If no name
  60. // is used, this flag will be ignored and an unnamed
  61. // mutex will be created.
  62. // By default, the arguments are set to NULL, FALSE, NULL,
  63. // and TRUE to create an unowned, unnamed mutex with
  64. // no particular security attributes.
  65. //
  66. // ~CMutex() - Destroys the handle that is created in the
  67. // constructor. If this is the last instance of
  68. // a handle to this Mutex, the OS will destroy
  69. // the mutex.
  70. //
  71. // History: 31-Jan-92 BryanT Created
  72. //
  73. // Notes: The error code of the constructor can be obtained by
  74. // calling the QueryError function and if everything
  75. // goes well, the ERROR_SUCCESS is returned by the call
  76. // to QueryError.
  77. // It is important that no virtual pointers are defined
  78. // in this class and the member varaible _mutex is the first
  79. // variable defined in this class.
  80. //
  81. //--------------------------------------------------------------------
  82. class CMutex
  83. {
  84. friend class CTCLock;
  85. public:
  86. inline CMutex( LPSECURITY_ATTRIBUTES lpsa = NULL,
  87. BOOL fInitialOwner = FALSE,
  88. LPTSTR lpszMutexName = NULL,
  89. BOOL fCreate = TRUE)
  90. {
  91. if ((FALSE == fCreate) && (NULL != lpszMutexName))
  92. {
  93. _mutex = OpenMutex(MUTANT_ALL_ACCESS,
  94. FALSE,
  95. lpszMutexName);
  96. }
  97. else
  98. {
  99. _mutex = CreateMutex(lpsa, fInitialOwner, lpszMutexName);
  100. }
  101. _dwLastError = (_mutex == NULL) ? GetLastError() : ERROR_SUCCESS;
  102. }
  103. inline ~CMutex()
  104. {
  105. CloseHandle(_mutex);
  106. }
  107. inline DWORD QueryError()
  108. {
  109. return _dwLastError;
  110. }
  111. private:
  112. HANDLE _mutex;
  113. DWORD _dwLastError;
  114. };
  115. //+-------------------------------------------------------------------
  116. //
  117. // Class: CSemaphore
  118. //
  119. // Purpose: Wrapper for Win32 semaphores. Creates a semaphore in the
  120. // constructor. Deletes it in the destructor.
  121. //
  122. // Interface: CSemaphore( lpsa, cSemInitial, cSemMax, lpszSemName, fCreate)
  123. // See CreateSemaphore in Win32 API docs for detail
  124. // of the first three arguments. The last indicates
  125. // if a new semaphore should be created (TRUE) or an
  126. // existing one opened (FALSE). In the case of
  127. // opening an existing semaphore, all access rights
  128. // will be requested and the handle will not be
  129. // inherited by any child processes that are created
  130. // by the calling process. By default, an
  131. // unnamed semaphore with a initial count of 1 (not
  132. // used) a maximum count of 1 and no security
  133. // attributes will be created.
  134. //
  135. // ~CSemaphore - Destroys the semaphore
  136. //
  137. // History: 31-Jan-92 BryanT Created
  138. //
  139. // Notes: The error code of the constructor can be obtained by
  140. // calling the QueryError function and if everything
  141. // goes well, the ERROR_SUCCESS is returned by the call
  142. // to QueryError.
  143. // It is important that no virtual pointers are defined
  144. // in this class and the member varaible _semaphore is the first
  145. // variable defined in this class.
  146. //
  147. //--------------------------------------------------------------------
  148. class CSemaphore
  149. {
  150. friend class CTCLock;
  151. public:
  152. inline CSemaphore( LPSECURITY_ATTRIBUTES lpsa = NULL,
  153. LONG cSemInitial = 1,
  154. LONG cSemMax = 1,
  155. LPTSTR lpszSemName = NULL,
  156. BOOL fCreate = TRUE)
  157. {
  158. if ((FALSE == fCreate) && (lpszSemName != NULL))
  159. {
  160. _semaphore = OpenSemaphore(SEMAPHORE_ALL_ACCESS,
  161. FALSE,
  162. lpszSemName);
  163. }
  164. else
  165. {
  166. _semaphore = CreateSemaphore(lpsa,
  167. cSemInitial,
  168. cSemMax,
  169. lpszSemName);
  170. }
  171. _dwLastError = (_semaphore == NULL) ? GetLastError() : ERROR_SUCCESS;
  172. }
  173. inline ~CSemaphore()
  174. {
  175. CloseHandle(_semaphore);
  176. }
  177. inline DWORD QueryError()
  178. {
  179. return _dwLastError;
  180. }
  181. private:
  182. HANDLE _semaphore;
  183. DWORD _dwLastError;
  184. };
  185. //+-------------------------------------------------------------------
  186. //
  187. // Class: CEvent
  188. //
  189. // Purpose: Wrapper for Win32 Events. Creates an event in the constructor.
  190. // deletes it in the destructor.
  191. //
  192. // Interface: CEvent(lpsa, fManualReset, fInitialState, lpszName, fCreate)
  193. // See Win32 API docs for details of first three
  194. // arguments. The last argument inicates whether a new
  195. // event should be created (TRUE) or an existing named
  196. // event should be opened. It no name is specified,
  197. // an unnamed event will be created and this argument is
  198. // ignored. By default, an unnamed, unowned event
  199. // will be created with no security attributes. It
  200. // will automatically reset.
  201. //
  202. // ~CEvent() - Destroys the event.
  203. //
  204. // History: 31-Jan-92 BryanT Created
  205. //
  206. // Notes: The error code of the constructor can be obtained by
  207. // calling the QueryError function and if everything
  208. // goes well, the ERROR_SUCCESS is returned by the call
  209. // to QueryError.
  210. // It is important that no virtual pointers are defined
  211. // in this class and the member varaible _event is the first
  212. // variable defined in this class.
  213. //
  214. //--------------------------------------------------------------------
  215. class CEvent
  216. {
  217. friend class CTCLock;
  218. public:
  219. inline CEvent(LPSECURITY_ATTRIBUTES lpsa = NULL,
  220. BOOL fManualReset = FALSE,
  221. BOOL fInitialState = FALSE,
  222. LPTSTR lpszName = NULL,
  223. BOOL fCreate = TRUE)
  224. {
  225. if ((FALSE == fCreate) && (lpszName != NULL))
  226. {
  227. _event = OpenEvent(EVENT_ALL_ACCESS,
  228. FALSE,
  229. lpszName);
  230. }
  231. else
  232. {
  233. _event = CreateEvent(lpsa,
  234. fManualReset,
  235. fInitialState,
  236. lpszName);
  237. }
  238. _dwLastError = (_event == NULL) ? GetLastError() : ERROR_SUCCESS;
  239. }
  240. inline ~CEvent()
  241. {
  242. CloseHandle(_event);
  243. }
  244. inline DWORD QueryError()
  245. {
  246. return _dwLastError;
  247. }
  248. private:
  249. HANDLE _event;
  250. DWORD _dwLastError;
  251. };
  252. //+-------------------------------------------------------------------
  253. //
  254. // Class: CCritSec
  255. //
  256. // Purpose: Wrapper for Win32 Critical Sections. Creates an critical
  257. // section in the constructor and deletes it in the destructor.
  258. //
  259. // Interface: CCritSec() - Creates a critical section
  260. //
  261. // ~CCritSec() - Destroys the critical section
  262. //
  263. // History: 04-Feb-92 BryanT Created
  264. //
  265. // Notes: For this code, there really isn't any exceptions that
  266. // I can trap (or return). Therefore, this class is finished.
  267. //
  268. //--------------------------------------------------------------------
  269. class CCritSec
  270. {
  271. friend class CTCLock;
  272. public:
  273. inline CCritSec()
  274. {
  275. InitializeCriticalSection(&_CritSec);
  276. }
  277. inline ~CCritSec()
  278. {
  279. DeleteCriticalSection( &_CritSec );
  280. }
  281. private:
  282. CRITICAL_SECTION _CritSec;
  283. };
  284. //+-------------------------------------------------------------------
  285. //
  286. // Class: CTCLock
  287. //
  288. // Purpose: Provide lock/unlock capabilities for one of the
  289. // synchrnization objects (CMutex, CSemaphore, CEvent, or
  290. // CCritSec). If no timeout is specified, INFINITE timeout is
  291. // used. In the case of an event, no lock is actually obtained.
  292. // Instead, we wait till the event occurs. For a critical
  293. // section object, no timeout argument is needed.
  294. //
  295. // Interface: CTCLock(CMutex, dwTimeOut) - Obtain a lock on a mutex.
  296. // CTCLock(CSemaphore, dwTimeOut) - Obtain a lock on a semaphore.
  297. // CTCLock(CEvent, dwTimeOut) - Wait for this event to occur.
  298. // CTCLock(CCritSec) - Enter this critical section.
  299. //
  300. // ~CTCLock() - Release/leave the object
  301. //
  302. // _dwLastError -
  303. // The error code from the last operation on this
  304. // object. If successfully constructed/destructed
  305. // it should be ERROR_SUCCESS.
  306. //
  307. // History: 31-Jan-92 BryanT Created
  308. // 23-Feb-92 BryanT Add _dwLastError in order to be
  309. // compatible with the OS/2 version.
  310. // 29-Jan-93 BryanT Continue the Critical Section if it times
  311. // out (340 does this now).
  312. // 26-Apr-96 MikeW Mac doesn't support SEH so #ifdef out
  313. // the continue.
  314. //
  315. // Notes: The error code of the constructor can be obtained by
  316. // calling the QueryError function and if everything
  317. // goes well, the ERROR_SUCCESS is returned by the call
  318. // to QueryError.
  319. //
  320. //--------------------------------------------------------------------
  321. class CTCLock
  322. {
  323. public:
  324. inline CTCLock(CMutex& cm, DWORD dwTimeOut = INFINITE)
  325. {
  326. if ((_dwLastError = cm.QueryError()) == ERROR_SUCCESS)
  327. {
  328. _lock = cm._mutex;
  329. _idLock = CMUTEX;
  330. _dwLastError = WaitForSingleObject(_lock, dwTimeOut);
  331. }
  332. }
  333. inline CTCLock(CSemaphore& cs, DWORD dwTimeOut = INFINITE)
  334. {
  335. if ((_dwLastError = cs.QueryError()) == ERROR_SUCCESS)
  336. {
  337. _lock = cs._semaphore;
  338. _idLock = CSEMAPHORE;
  339. _dwLastError = WaitForSingleObject(_lock, dwTimeOut);
  340. }
  341. }
  342. inline CTCLock(CEvent& ce, DWORD dwTimeOut = INFINITE)
  343. {
  344. if ((_dwLastError = ce.QueryError()) == ERROR_SUCCESS)
  345. {
  346. _lock = ce._event;
  347. _idLock = CEVENT;
  348. _dwLastError = WaitForSingleObject(_lock, dwTimeOut);
  349. }
  350. }
  351. inline CTCLock(CCritSec& ccs)
  352. {
  353. _idLock = CCRITSEC;
  354. _lpcs = &ccs._CritSec;
  355. #ifndef _MAC
  356. _try
  357. #endif
  358. {
  359. EnterCriticalSection(_lpcs);
  360. }
  361. #ifndef _MAC
  362. _except (GetExceptionCode() == STATUS_POSSIBLE_DEADLOCK ?
  363. EXCEPTION_CONTINUE_EXECUTION :
  364. EXCEPTION_CONTINUE_SEARCH){}
  365. #endif
  366. _dwLastError = ERROR_SUCCESS;
  367. }
  368. inline ~CTCLock()
  369. {
  370. switch (_idLock)
  371. {
  372. case CMUTEX:
  373. if (ReleaseMutex(_lock) == TRUE)
  374. _dwLastError = ERROR_SUCCESS;
  375. else
  376. _dwLastError = GetLastError();
  377. break;
  378. case CSEMAPHORE:
  379. if (ReleaseSemaphore(_lock, 1, NULL) == TRUE)
  380. _dwLastError = ERROR_SUCCESS;
  381. else
  382. _dwLastError = GetLastError();
  383. break;
  384. case CEVENT:
  385. _dwLastError = ERROR_SUCCESS;
  386. break;
  387. case CCRITSEC:
  388. LeaveCriticalSection(_lpcs);
  389. _dwLastError = ERROR_SUCCESS;
  390. break;
  391. }
  392. }
  393. inline DWORD QueryError()
  394. {
  395. return _dwLastError;
  396. }
  397. private:
  398. union
  399. {
  400. HANDLE _lock;
  401. LPCRITICAL_SECTION _lpcs;
  402. };
  403. INT _idLock;
  404. DWORD _dwLastError;
  405. };
  406. #elif defined (__OS2__) // defined (WIN32)
  407. #ifndef SEM_TIMEOUT
  408. #define SEM_TIMEOUT SEM_INDEFINITE_WAIT
  409. #endif
  410. #ifndef _MT
  411. #error ERROR: Must Build for Multi-thread.
  412. #endif
  413. #ifndef _INC_STDDEF
  414. #include <stddef.h> // For _threadid in CTCLock code
  415. #endif
  416. #include <assert.h> // For assert() code
  417. //+-------------------------------------------------------------------
  418. //
  419. // Class: CCritSec
  420. //
  421. // Purpose: Define an OS/2 version of a Win32 critical section. In
  422. // other words, define a synchronization onject that can be
  423. // entered any number of times by one thread without waiting.
  424. // Keeps a count of number of times it is entered and the TID
  425. // of who currently has access.
  426. //
  427. // Interface: CCritSec() - Creates a critical section
  428. //
  429. // ~CCritSec() - Destroys the critical section
  430. //
  431. // History: 23-Feb-92 BryanT Created
  432. //
  433. // Notes: For this code, there really isn't any exceptions that
  434. // I can trap (or return). Therefore, this class is finished.
  435. //
  436. //--------------------------------------------------------------------
  437. class CCritSec
  438. {
  439. friend class CTCLock;
  440. public:
  441. inline CCritSec()
  442. {
  443. // Initialize everything to zero.
  444. hSem = 0;
  445. tid = 0;
  446. cLockCount = 0;
  447. }
  448. inline ~CCritSec()
  449. {
  450. #if defined(TRACE)
  451. if (cLockCount != 0)
  452. {
  453. fprintf(stderr,
  454. "CCritSec object destructed with %d locks",
  455. cLockCount);
  456. fprintf(stderr,
  457. " outstanding by TID: %x\n",
  458. tid);
  459. }
  460. #endif
  461. }
  462. private:
  463. HSEM hSem; // Exclusive use RAM semaphore
  464. TID tid; // The thread owning the semaphore
  465. USHORT cLockCount; // # times semaphore locked
  466. };
  467. //+-------------------------------------------------------------------
  468. //
  469. // Class: CTCLock
  470. //
  471. // Purpose: Provide OS/2 lock/unlock capabilities for a CCritSec
  472. // synchrnization object.
  473. //
  474. // Interface: CTCLock(CCritSec) - Enter this critical section.
  475. //
  476. // ~CTCLock() - Release/leave the object
  477. //
  478. // _usLastError - The error code from the last operation on this
  479. // object. If successfully constructed/destructed
  480. // it should be ERROR_SUCCESS.
  481. //
  482. // History: 23-Feb-92 BryanT Created
  483. //
  484. // Notes: This is the OS/2 version of Win32 critical sections.
  485. // By default, the timeout will be SEM_INDEFINITE_WAIT. If
  486. // you wish to change this, merely define SEM_TIMEOUT before
  487. // including this file.
  488. //
  489. //--------------------------------------------------------------------
  490. class CTCLock
  491. {
  492. public:
  493. inline CTCLock(CCritSec& ccs)
  494. {
  495. // Is the semaphore already in use?
  496. if (ERROR_SEM_TIMEOUT == (_usLastError = DosSemRequest(&ccs.hSem,
  497. SEM_IMMEDIATE_RETURN)))
  498. {
  499. // If it's us, increment the counter and return.
  500. if (ccs.tid == *_threadid)
  501. {
  502. ccs.cLockCount++; // Increment the lock counter
  503. _usLastError = ERROR_SUCCESS;
  504. _pCritSec = &ccs;
  505. return;
  506. }
  507. }
  508. // Either it's not in use or we don't own it. Wait for access.
  509. // Once obtained, store the appropriate data and return.
  510. if ((ERROR_SUCCESS == _usLastError) ||
  511. (ERROR_SUCCESS == (_usLastError = DosSemRequest(&ccs.hSem,SEM_TIMEOUT))))
  512. {
  513. ccs.tid = *_threadid;
  514. ccs.cLockCount = 1;
  515. _pCritSec = &ccs;
  516. }
  517. else
  518. {
  519. _pCritSec = NULL; // Indicate we don't have it
  520. }
  521. return;
  522. }
  523. inline ~CTCLock()
  524. {
  525. //
  526. // The lock counter should always be > 0. If not, then we don't
  527. // have a matching lock for every unlock.
  528. //
  529. if (_pCritSec == NULL)
  530. {
  531. _usLastError = ERROR_SUCCESS;
  532. return;
  533. }
  534. assert (_pCritSec->cLockCount > 0);
  535. _pCritSec->cLockCount--;
  536. if (_pCritSec->cLockCount == 0)
  537. {
  538. _pCritSec->tid = 0;
  539. _usLastError = DosSemClear(&(_pCritSec->hSem));
  540. return;
  541. }
  542. else
  543. {
  544. _usLastError = ERROR_SUCCESS;
  545. return;
  546. }
  547. }
  548. USHORT _usLastError;
  549. private:
  550. CCritSec * _pCritSec;
  551. };
  552. #endif // Defined __OS2__ or WIN32
  553. #endif // ifndef MIDL_PASS
  554. #endif // #ifndef SYNCWRAP_HXX