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.

864 lines
18 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1996 - 1999
  3. Module Name:
  4. Locks
  5. Abstract:
  6. The following three classes implement a simple single writer, multiple
  7. readers lock. CAccessLock is the lock, then the CLockRead and CLockWrite
  8. objects envoke the lock while they are in scope. They are all implemented
  9. inline.
  10. The CMultiEvent class implements an automatic waitable object that will
  11. release all threads waiting on it when signaled.
  12. Author:
  13. Doug Barlow (dbarlow) 10/24/1996
  14. Environment:
  15. Win32, C++ w/ exceptions
  16. Notes:
  17. ?Notes?
  18. --*/
  19. #ifndef _LOCKS_H_
  20. #define _LOCKS_H_
  21. #include <WinSCard.h>
  22. #include "CalMsgs.h"
  23. #include <SCardLib.h>
  24. #ifdef DBG
  25. #define REASONABLE_TIME 2 * 60 * 1000 // Two minutes
  26. #else
  27. #define REASONABLE_TIME INFINITE
  28. #endif
  29. extern DWORD
  30. WaitForAnyObject(
  31. DWORD dwTimeout,
  32. ...);
  33. extern DWORD
  34. WaitForAnObject(
  35. HANDLE hWaitOn,
  36. DWORD dwTimeout);
  37. #ifdef DBG
  38. #undef __SUBROUTINE__
  39. #define __SUBROUTINE__ DBGT("WaitForEverObject")
  40. inline void
  41. WaitForEverObject(
  42. HANDLE hWaitOn,
  43. DWORD dwTimeout,
  44. DEBUG_TEXT szReason,
  45. LPCTSTR szObject = NULL)
  46. {
  47. DWORD dwSts;
  48. while (ERROR_SUCCESS != (dwSts = WaitForAnObject(hWaitOn, dwTimeout)))
  49. CalaisWarning(__SUBROUTINE__, szReason, dwSts, szObject);
  50. }
  51. inline void
  52. WaitForEverObject(
  53. HANDLE hWaitOn,
  54. DWORD dwTimeout,
  55. DEBUG_TEXT szReason,
  56. DWORD dwObject)
  57. {
  58. DWORD dwSts;
  59. TCHAR szNum[16];
  60. wsprintf(szNum, TEXT("0x%08x"), dwObject);
  61. while (ERROR_SUCCESS != (dwSts = WaitForAnObject(hWaitOn, dwTimeout)))
  62. CalaisWarning(__SUBROUTINE__, szReason, dwSts, szNum);
  63. }
  64. #define WaitForever(hWaitOn, dwTimeout, szReason, szObject) \
  65. WaitForEverObject(hWaitOn, dwTimeout, szReason, szObject)
  66. #else
  67. inline void
  68. WaitForEverObject(
  69. HANDLE hWaitOn)
  70. {
  71. while (ERROR_SUCCESS != WaitForAnObject(hWaitOn, INFINITE));
  72. // Empty body
  73. }
  74. #define WaitForever(hWaitOn, dwTimeout, szReason, szObject) \
  75. WaitForEverObject(hWaitOn)
  76. #endif
  77. //
  78. // Critical Section Support.
  79. //
  80. // The following Classes and Macros aid in debugging Critical Section
  81. // Conflicts.
  82. //
  83. //
  84. // Critical section Ids. Locks must be obtained in the order from lowest
  85. // to highest. An attempt to access a lower-numbered lock while holding a
  86. // higher numbered lock will result in an ASSERT.
  87. //
  88. // Server side lock IDs
  89. #define CSID_SERVICE_STATUS 0 // Service Status Critical Section
  90. #define CSID_CONTROL_LOCK 1 // Lock for Calais control commands.
  91. #define CSID_SERVER_THREADS 2 // Lock for server thread enumeration.
  92. #define CSID_MULTIEVENT 3 // MultiEvent Critical Access Section
  93. #define CSID_MUTEX 4 // Mutex critical access section
  94. #define CSID_ACCESSCONTROL 5 // Access Lock control
  95. #define CSID_TRACEOUTPUT 6 // Lock for tracing output.
  96. // Client side lock IDs
  97. #define CSID_USER_CONTEXT 0 // User context lock
  98. #define CSID_SUBCONTEXT 1 // Subcontext lock
  99. //
  100. //==============================================================================
  101. //
  102. // CCriticalSectionObject
  103. //
  104. class CCriticalSectionObject
  105. {
  106. public:
  107. // Constructors & Destructor
  108. CCriticalSectionObject(DWORD dwCsid);
  109. ~CCriticalSectionObject();
  110. // Properties
  111. // Methods
  112. virtual void Enter(DEBUG_TEXT szOwner, DEBUG_TEXT szComment);
  113. virtual void Leave(void);
  114. virtual BOOL InitFailed(void) { return m_fInitFailed; }
  115. #ifdef DBG
  116. LPCTSTR Description(void) const;
  117. #undef __SUBROUTINE__
  118. #define __SUBROUTINE__ DBGT("CCriticalSectionObject::Owner")
  119. LPCTSTR Owner(void) const
  120. { return (LPCTSTR)m_bfOwner.Access(); };
  121. #undef __SUBROUTINE__
  122. #define __SUBROUTINE__ DBGT("CCriticalSectionObject::Comment")
  123. LPCTSTR Comment(void) const
  124. { return (LPCTSTR)m_bfComment.Access(); };
  125. #undef __SUBROUTINE__
  126. #define __SUBROUTINE__ DBGT("CCriticalSectionObject::IsOwnedByMe")
  127. BOOL IsOwnedByMe(void) const
  128. { return (GetCurrentThreadId() == m_dwOwnerThread); };
  129. #endif
  130. // Operators
  131. protected:
  132. // Properties
  133. CRITICAL_SECTION m_csLock;
  134. BOOL m_fInitFailed;
  135. #ifdef DBG
  136. DWORD m_dwCsid;
  137. CBuffer m_bfOwner;
  138. CBuffer m_bfComment;
  139. DWORD m_dwOwnerThread;
  140. DWORD m_dwRecursion;
  141. #endif
  142. // Methods
  143. };
  144. //
  145. //==============================================================================
  146. //
  147. // COwnCriticalSection
  148. //
  149. class COwnCriticalSection
  150. {
  151. public:
  152. // Constructors & Destructor
  153. #undef __SUBROUTINE__
  154. #define __SUBROUTINE__ DBGT("COwnCriticalSection::COwnCriticalSection")
  155. COwnCriticalSection(
  156. CCriticalSectionObject *pcs,
  157. DEBUG_TEXT szSubroutine,
  158. DEBUG_TEXT szComment)
  159. {
  160. m_pcsLock = pcs;
  161. m_pcsLock->Enter(szSubroutine, szComment);
  162. };
  163. #undef __SUBROUTINE__
  164. #define __SUBROUTINE__ DBGT("COwnCriticalSection::~COwnCriticalSection")
  165. ~COwnCriticalSection()
  166. {
  167. m_pcsLock->Leave();
  168. };
  169. // Properties
  170. // Methods
  171. // Operators
  172. protected:
  173. // Properties
  174. CCriticalSectionObject *m_pcsLock;
  175. // Methods
  176. };
  177. #define LockSection(cx, reason) \
  178. COwnCriticalSection csLock(cx, __SUBROUTINE__, reason)
  179. #define LockSection2(cx, reason) \
  180. COwnCriticalSection csLock2(cx, __SUBROUTINE__, reason)
  181. #ifndef DBG
  182. //
  183. //In-line the simple Critical Section calls.
  184. //
  185. #undef __SUBROUTINE__
  186. #define __SUBROUTINE__ DBGT("CCriticalSectionObject::CCriticalSectionObject")
  187. inline
  188. CCriticalSectionObject::CCriticalSectionObject(
  189. DWORD dwCsid)
  190. {
  191. m_fInitFailed = FALSE;
  192. try {
  193. // Preallocate the event used by the EnterCriticalSection
  194. // function to prevent an exception from being thrown in
  195. // CCriticalSectionObject::Enter
  196. if (! InitializeCriticalSectionAndSpinCount(
  197. &m_csLock, 0x80000000))
  198. m_fInitFailed = TRUE;
  199. }
  200. catch (HRESULT hr) {
  201. m_fInitFailed = TRUE;
  202. }
  203. }
  204. #undef __SUBROUTINE__
  205. #define __SUBROUTINE__ DBGT("CCriticalSectionObject::~CCriticalSectionObject")
  206. inline
  207. CCriticalSectionObject::~CCriticalSectionObject()
  208. {
  209. if (m_fInitFailed)
  210. return;
  211. DeleteCriticalSection(&m_csLock);
  212. }
  213. #undef __SUBROUTINE__
  214. #define __SUBROUTINE__ DBGT("CCriticalSectionObject::Enter")
  215. inline void
  216. CCriticalSectionObject::Enter(
  217. DEBUG_TEXT szOwner,
  218. DEBUG_TEXT szComment)
  219. {
  220. if (m_fInitFailed)
  221. throw (DWORD)SCARD_E_NO_MEMORY;
  222. EnterCriticalSection(&m_csLock);
  223. }
  224. #undef __SUBROUTINE__
  225. #define __SUBROUTINE__ DBGT("CCriticalSectionObject::Leave")
  226. inline void
  227. CCriticalSectionObject::Leave(
  228. void)
  229. {
  230. LeaveCriticalSection(&m_csLock);
  231. }
  232. #endif // !DBG
  233. //
  234. //==============================================================================
  235. //
  236. // CHandleObject
  237. //
  238. class CHandleObject
  239. {
  240. public:
  241. // Constructors & Destructor
  242. #undef __SUBROUTINE__
  243. #define __SUBROUTINE__ DBGT("CHandleObject::CHandleObject")
  244. CHandleObject(DEBUG_TEXT szName)
  245. #ifdef DBG
  246. : m_bfName((LPCBYTE)szName, (lstrlen(szName) + 1) * sizeof(TCHAR))
  247. #endif
  248. {
  249. m_hHandle = NULL;
  250. m_dwError = ERROR_SUCCESS;
  251. };
  252. #undef __SUBROUTINE__
  253. #define __SUBROUTINE__ DBGT("CHandleObject::~CHandleObject")
  254. ~CHandleObject()
  255. {
  256. if (IsValid())
  257. {
  258. #ifdef _DEBUG
  259. CalaisWarning(
  260. __SUBROUTINE__,
  261. DBGT("Unclosed handle '%1' -- fixing."),
  262. (DEBUG_TEXT)m_bfName.Access());
  263. #endif
  264. Close();
  265. }
  266. };
  267. // Properties
  268. // Methods
  269. #undef __SUBROUTINE__
  270. #define __SUBROUTINE__ DBGT("CHandleObject::IsValid")
  271. BOOL IsValid(void) const
  272. {
  273. return (NULL != m_hHandle) && (INVALID_HANDLE_VALUE != m_hHandle);
  274. };
  275. #undef __SUBROUTINE__
  276. #define __SUBROUTINE__ DBGT("CHandleObject::Value")
  277. HANDLE Value(void) const
  278. {
  279. #ifdef _DEBUG
  280. if (!IsValid())
  281. CalaisWarning(
  282. __SUBROUTINE__,
  283. DBGT("Accessing invalid '%1' handle value."),
  284. (DEBUG_TEXT)m_bfName.Access());
  285. #endif
  286. return m_hHandle;
  287. };
  288. #undef __SUBROUTINE__
  289. #define __SUBROUTINE__ DBGT("CHandleObject::GetLastError")
  290. DWORD GetLastError(void) const
  291. {
  292. return m_dwError;
  293. };
  294. #undef __SUBROUTINE__
  295. #define __SUBROUTINE__ DBGT("CHandleObject::Open")
  296. HANDLE Open(HANDLE h)
  297. {
  298. if ((NULL == h) || (INVALID_HANDLE_VALUE == h))
  299. {
  300. m_dwError = ::GetLastError();
  301. #ifdef _DEBUG
  302. CalaisWarning(
  303. __SUBROUTINE__,
  304. DBGT("Attempt to assign invalid handle value to '%1'."),
  305. (DEBUG_TEXT)m_bfName.Access());
  306. #endif
  307. }
  308. else
  309. m_dwError = ERROR_SUCCESS;
  310. if (IsValid())
  311. {
  312. #ifdef _DEBUG
  313. CalaisWarning(
  314. __SUBROUTINE__,
  315. DBGT("Overwriting handle '%1' -- fixing"),
  316. (DEBUG_TEXT)m_bfName.Access());
  317. #endif
  318. Close();
  319. }
  320. m_hHandle = h;
  321. return m_hHandle;
  322. };
  323. #undef __SUBROUTINE__
  324. #define __SUBROUTINE__ DBGT("CHandleObject::Close")
  325. DWORD Close(void)
  326. {
  327. DWORD dwSts = ERROR_SUCCESS;
  328. if (IsValid())
  329. {
  330. BOOL fSts;
  331. fSts = CloseHandle(m_hHandle);
  332. #ifdef DBG
  333. if (!fSts)
  334. {
  335. dwSts = GetLastError();
  336. CalaisWarning(
  337. __SUBROUTINE__,
  338. DBGT("Failed to close handle '%2': %1"),
  339. dwSts,
  340. (DEBUG_TEXT)m_bfName.Access());
  341. }
  342. #endif
  343. m_hHandle = NULL;
  344. }
  345. #ifdef DBG
  346. else
  347. {
  348. CalaisWarning(
  349. __SUBROUTINE__,
  350. DBGT("Attempt to re-close handle '%1'"),
  351. (DEBUG_TEXT)m_bfName.Access());
  352. }
  353. #endif
  354. return dwSts;
  355. };
  356. #undef __SUBROUTINE__
  357. #define __SUBROUTINE__ DBGT("CHandleObject::Relinquish")
  358. HANDLE Relinquish(void)
  359. {
  360. HANDLE hTmp = m_hHandle;
  361. #ifdef _DEBUG
  362. if (!IsValid())
  363. CalaisWarning(
  364. __SUBROUTINE__,
  365. DBGT("Relinquishing invalid '%1' handle"),
  366. (DEBUG_TEXT)m_bfName.Access());
  367. #endif
  368. m_hHandle = NULL;
  369. return hTmp;
  370. };
  371. // Operators
  372. #undef __SUBROUTINE__
  373. #define __SUBROUTINE__ DBGT("CHandleObject::operator HANDLE")
  374. operator HANDLE(void) const
  375. {
  376. #ifdef _DEBUG
  377. ASSERT(IsValid()); // Assert should be in callers
  378. #endif
  379. return Value();
  380. };
  381. #undef __SUBROUTINE__
  382. #define __SUBROUTINE__ DBGT("CHandleObject::operator=")
  383. HANDLE operator=(HANDLE h)
  384. {
  385. return Open(h);
  386. };
  387. protected:
  388. // Properties
  389. HANDLE m_hHandle;
  390. DWORD m_dwError;
  391. #ifdef DBG
  392. CBuffer m_bfName;
  393. #endif
  394. // Methods
  395. };
  396. #ifdef DBG
  397. //
  398. //==============================================================================
  399. //
  400. // CDynamicArray
  401. //
  402. template <class T>
  403. class CDynamicValArray
  404. {
  405. public:
  406. // Constructors & Destructor
  407. CDynamicValArray(void)
  408. { m_Max = m_Mac = 0; m_pvList = NULL; };
  409. virtual ~CDynamicValArray()
  410. { Clear(); };
  411. // Properties
  412. // Methods
  413. void
  414. Clear(void)
  415. {
  416. if (NULL != m_pvList)
  417. {
  418. delete[] m_pvList;
  419. m_pvList = NULL;
  420. m_Max = 0;
  421. m_Mac = 0;
  422. }
  423. };
  424. void
  425. Empty(void)
  426. { m_Mac = 0; };
  427. T
  428. Set(
  429. IN int nItem,
  430. IN T pvItem);
  431. T const
  432. Get(
  433. IN int nItem)
  434. const;
  435. DWORD
  436. Count(void) const
  437. { return m_Mac; };
  438. // Operators
  439. T const
  440. operator[](int nItem) const
  441. { return Get(nItem); };
  442. protected:
  443. // Properties
  444. DWORD
  445. m_Max, // Number of element slots available.
  446. m_Mac; // Number of element slots used.
  447. T *
  448. m_pvList; // The elements.
  449. // Methods
  450. };
  451. /*++
  452. Set:
  453. This routine sets an item in the collection array. If the array isn't that
  454. big, it is expanded with NULL elements to become that big.
  455. Arguments:
  456. nItem - Supplies the index value to be set.
  457. pvItem - Supplies the value to be set into the given index.
  458. Return Value:
  459. The value of the inserted value, or NULL on errors.
  460. Author:
  461. Doug Barlow (dbarlow) 7/13/1995
  462. --*/
  463. template<class T>
  464. inline T
  465. CDynamicValArray<T>::Set(
  466. IN int nItem,
  467. IN T pvItem)
  468. {
  469. DWORD index;
  470. //
  471. // Make sure the array is big enough.
  472. //
  473. if ((DWORD)nItem >= m_Max)
  474. {
  475. int newSize = (0 == m_Max ? 4 : m_Max);
  476. while (nItem >= newSize)
  477. newSize *= 2;
  478. T *newList = new T[newSize];
  479. if (NULL == newList)
  480. throw (DWORD)ERROR_OUTOFMEMORY;
  481. for (index = 0; index < m_Mac; index += 1)
  482. newList[index] = m_pvList[index];
  483. if (NULL != m_pvList)
  484. delete[] m_pvList;
  485. m_pvList = newList;
  486. m_Max = newSize;
  487. }
  488. //
  489. // Make sure intermediate elements are filled in.
  490. //
  491. if ((DWORD)nItem >= m_Mac)
  492. {
  493. for (index = m_Mac; index < (DWORD)nItem; index += 1)
  494. m_pvList[index] = NULL;
  495. m_Mac = (DWORD)nItem + 1;
  496. }
  497. //
  498. // Fill in the list element.
  499. //
  500. m_pvList[(DWORD)nItem] = pvItem;
  501. return pvItem;
  502. }
  503. /*++
  504. Get:
  505. This method returns the element at the given index. If there is no element
  506. previously stored at that element, it returns NULL. It does not expand the
  507. array.
  508. Arguments:
  509. nItem - Supplies the index into the list.
  510. Return Value:
  511. The value stored at that index in the list, or NULL if nothing has ever been
  512. stored there.
  513. Author:
  514. Doug Barlow (dbarlow) 7/13/1995
  515. --*/
  516. template <class T>
  517. inline T const
  518. CDynamicValArray<T>::Get(
  519. int nItem)
  520. const
  521. {
  522. if (m_Mac <= (DWORD)nItem)
  523. return 0;
  524. else
  525. return m_pvList[nItem];
  526. }
  527. #endif
  528. //
  529. //==============================================================================
  530. //
  531. // CAccessLock
  532. //
  533. class CAccessLock
  534. {
  535. public:
  536. // Constructors & Destructor
  537. CAccessLock(DWORD dwTimeout = CALAIS_LOCK_TIMEOUT);
  538. ~CAccessLock();
  539. BOOL InitFailed(void) { return m_csLock.InitFailed(); }
  540. #ifdef DBG
  541. BOOL NotReadLocked(void);
  542. BOOL IsReadLocked(void);
  543. BOOL NotWriteLocked(void);
  544. BOOL IsWriteLocked(void);
  545. #endif
  546. protected:
  547. // Properties
  548. CCriticalSectionObject m_csLock;
  549. DWORD m_dwReadCount;
  550. DWORD m_dwWriteCount;
  551. DWORD m_dwTimeout;
  552. CHandleObject m_hSignalNoReaders;
  553. CHandleObject m_hSignalNoWriters;
  554. DWORD m_dwOwner;
  555. #ifdef DBG
  556. CDynamicValArray<DWORD> m_rgdwReaders;
  557. #endif
  558. // Methods
  559. void Wait(HANDLE hSignal);
  560. void Signal(HANDLE hSignal);
  561. void Unsignal(HANDLE hSignal);
  562. void WaitOnReaders(void)
  563. {
  564. Wait(m_hSignalNoReaders);
  565. };
  566. void WaitOnWriters(void)
  567. {
  568. Wait(m_hSignalNoWriters);
  569. };
  570. void SignalNoReaders(void)
  571. {
  572. Signal(m_hSignalNoReaders);
  573. };
  574. void SignalNoWriters(void)
  575. {
  576. Signal(m_hSignalNoWriters);
  577. };
  578. void UnsignalNoReaders(void)
  579. {
  580. Unsignal(m_hSignalNoReaders);
  581. };
  582. void UnsignalNoWriters(void)
  583. {
  584. Unsignal(m_hSignalNoWriters);
  585. };
  586. friend class CLockRead;
  587. friend class CLockWrite;
  588. };
  589. //
  590. //==============================================================================
  591. //
  592. // CLockRead
  593. //
  594. class CLockRead
  595. {
  596. public:
  597. // Constructors & Destructor
  598. CLockRead(CAccessLock *pLock);
  599. ~CLockRead();
  600. BOOL InitFailed(void) { return m_pLock->InitFailed(); }
  601. // Properties
  602. // Methods
  603. // Operators
  604. protected:
  605. // Properties
  606. CAccessLock * m_pLock;
  607. // Methods
  608. };
  609. //
  610. //==============================================================================
  611. //
  612. // CLockWrite
  613. //
  614. class CLockWrite
  615. {
  616. public:
  617. // Constructors & Destructor
  618. CLockWrite(CAccessLock *pLock);
  619. ~CLockWrite();
  620. BOOL InitFailed(void) { return m_pLock->InitFailed(); }
  621. // Properties
  622. // Methods
  623. // Operators
  624. protected:
  625. // Properties
  626. CAccessLock *m_pLock;
  627. // Methods
  628. };
  629. //
  630. //==============================================================================
  631. //
  632. // CMutex
  633. //
  634. class CMutex
  635. {
  636. public:
  637. // Constructors & Destructor
  638. CMutex();
  639. ~CMutex();
  640. // Properties
  641. // Methods
  642. void Grab(void);
  643. BOOL Share(void);
  644. void Invalidate(void);
  645. void Take(void);
  646. BOOL IsGrabbed(void);
  647. BOOL IsGrabbedByMe(void);
  648. BOOL IsGrabbedBy(DWORD dwThreadId);
  649. BOOL InitFailed(void) { return m_csAccessLock.InitFailed(); }
  650. // Operators
  651. protected:
  652. // Properties
  653. CCriticalSectionObject m_csAccessLock;
  654. DWORD m_dwOwnerThreadId;
  655. DWORD m_dwGrabCount;
  656. DWORD m_dwValidityCount;
  657. CHandleObject m_hAvailableEvent;
  658. // Methods
  659. };
  660. //
  661. //==============================================================================
  662. //
  663. // CMultiEvent
  664. //
  665. class CMultiEvent
  666. {
  667. public:
  668. // Constructors & Destructor
  669. CMultiEvent();
  670. ~CMultiEvent();
  671. // Properties
  672. // Methods
  673. HANDLE WaitHandle(void);
  674. void Signal(void);
  675. BOOL InitFailed(void) { return m_csLock.InitFailed(); }
  676. // Operators
  677. protected:
  678. // Properties
  679. CCriticalSectionObject m_csLock;
  680. HANDLE m_rghEvents[4]; // Adjust this as necessary.
  681. DWORD m_dwEventIndex;
  682. // Methods
  683. };
  684. #endif // _LOCKS_H_