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.

1562 lines
31 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1998 - 1999
  3. Module Name:
  4. locks
  5. Abstract:
  6. This module provides the implementations of the lock objects used in Calais.
  7. Author:
  8. Doug Barlow (dbarlow) 6/2/1998
  9. Notes:
  10. ?Notes?
  11. --*/
  12. #define __SUBROUTINE__
  13. #ifndef WIN32_LEAN_AND_MEAN
  14. #define WIN32_LEAN_AND_MEAN
  15. #endif
  16. #include <windows.h>
  17. #include <stdarg.h>
  18. #include <WinSCard.h>
  19. #include <CalMsgs.h>
  20. #include <calcom.h>
  21. //
  22. //==============================================================================
  23. //
  24. // CAccessLock
  25. //
  26. /*++
  27. CONSTRUCTOR:
  28. A CAccessLock provides a multiple-reader, single writer lock on a structure.
  29. Arguments:
  30. dwTimeout supplies a reasonable timeout value for any lock.
  31. Remarks:
  32. Author:
  33. Doug Barlow (dbarlow) 6/2/1998
  34. --*/
  35. #undef __SUBROUTINE__
  36. #define __SUBROUTINE__ DBGT("CAccessLock::CAccessLock")
  37. CAccessLock::CAccessLock(
  38. DWORD dwTimeout)
  39. : m_csLock(CSID_ACCESSCONTROL),
  40. m_hSignalNoReaders(DBGT("CAccessLock No Readers Event")),
  41. m_hSignalNoWriters(DBGT("CAccessLock No Writers Event"))
  42. #ifdef DBG
  43. , m_rgdwReaders()
  44. #endif
  45. {
  46. m_hSignalNoReaders = CreateEvent(NULL, TRUE, TRUE, NULL);
  47. if (!m_hSignalNoReaders.IsValid())
  48. {
  49. DWORD dwSts = m_hSignalNoReaders.GetLastError();
  50. CalaisWarning(
  51. __SUBROUTINE__,
  52. DBGT("Access Lock Object cannot create the No Readers signal: %1"),
  53. dwSts);
  54. throw dwSts; // Force a shutdown.
  55. }
  56. m_hSignalNoWriters = CreateEvent(NULL, TRUE, TRUE, NULL);
  57. if (!m_hSignalNoWriters.IsValid())
  58. {
  59. DWORD dwSts = m_hSignalNoWriters.GetLastError();
  60. CalaisWarning(
  61. __SUBROUTINE__,
  62. DBGT("Access Lock Object cannot create the No Writers signal: %1"),
  63. dwSts);
  64. throw dwSts; // Force a shutdown.
  65. }
  66. m_dwOwner = 0;
  67. m_dwReadCount = m_dwWriteCount = 0;
  68. m_dwTimeout = dwTimeout;
  69. }
  70. /*++
  71. DESTRUCTOR:
  72. This cleans up after a CAccessLock.
  73. Arguments:
  74. None
  75. Author:
  76. Doug Barlow (dbarlow) 6/2/1998
  77. --*/
  78. #undef __SUBROUTINE__
  79. #define __SUBROUTINE__ DBGT("CAccessLock::~CAccessLock")
  80. CAccessLock::~CAccessLock()
  81. {
  82. if (InitFailed())
  83. return;
  84. {
  85. CLockWrite rwLock(this);
  86. m_csLock.Enter(
  87. __SUBROUTINE__,
  88. DBGT("Closing down the CAccessLock"));
  89. }
  90. #ifdef DBG
  91. {
  92. ASSERT(0 == m_dwReadCount);
  93. for (DWORD ix = m_rgdwReaders.Count(); ix > 0;)
  94. {
  95. ix -= 1;
  96. ASSERT(0 == m_rgdwReaders[ix]);
  97. }
  98. }
  99. #endif
  100. if (m_hSignalNoReaders.IsValid())
  101. m_hSignalNoReaders.Close();
  102. if (m_hSignalNoWriters.IsValid())
  103. m_hSignalNoWriters.Close();
  104. }
  105. /*++
  106. Wait:
  107. Wait for the usage signal to trigger.
  108. Arguments:
  109. hSignal supplies the handle to use for the wait.
  110. Return Value:
  111. None
  112. Throws:
  113. None
  114. Remarks:
  115. This routine blocks until the usage signal fires.
  116. Author:
  117. Doug Barlow (dbarlow) 6/2/1998
  118. --*/
  119. #undef __SUBROUTINE__
  120. #define __SUBROUTINE__ DBGT("CAccessLock::Wait")
  121. void
  122. CAccessLock::Wait(
  123. HANDLE hSignal)
  124. {
  125. WaitForever(
  126. hSignal,
  127. m_dwTimeout,
  128. DBGT("Waiting for Read/Write Lock signal (owner %2): %1"),
  129. m_dwOwner);
  130. }
  131. /*++
  132. Signal:
  133. This routine signals the usage signal that the structure is available.
  134. Arguments:
  135. hSignal supplies the handle to be signaled.
  136. Return Value:
  137. None
  138. Throws:
  139. Errors are thrown as DWORD status codes
  140. Author:
  141. Doug Barlow (dbarlow) 6/2/1998
  142. --*/
  143. #undef __SUBROUTINE__
  144. #define __SUBROUTINE__ DBGT("CAccessLock::Signal")
  145. void
  146. CAccessLock::Signal(
  147. HANDLE hSignal)
  148. {
  149. if (!SetEvent(hSignal))
  150. {
  151. DWORD dwSts = GetLastError();
  152. CalaisWarning(
  153. __SUBROUTINE__,
  154. DBGT("Access Lock Object cannot set its signal: %1"),
  155. dwSts);
  156. throw dwSts;
  157. }
  158. }
  159. /*++
  160. Unsignal:
  161. This method is used to notify other threads that the lock has been taken.
  162. Arguments:
  163. hSignal supplies the handle to be reset.
  164. Return Value:
  165. None
  166. Throws:
  167. Errors are thrown as DWORD status codes.
  168. Remarks:
  169. Author:
  170. Doug Barlow (dbarlow) 6/3/1998
  171. --*/
  172. #undef __SUBROUTINE__
  173. #define __SUBROUTINE__ DBGT("CAccessLock::Unsignal")
  174. void
  175. CAccessLock::Unsignal(
  176. HANDLE hSignal)
  177. {
  178. if (!ResetEvent(hSignal))
  179. {
  180. DWORD dwSts = GetLastError();
  181. CalaisWarning(
  182. __SUBROUTINE__,
  183. DBGT("Access Lock Object cannot reset its signal: %1"),
  184. dwSts);
  185. throw dwSts;
  186. }
  187. }
  188. #ifdef DBG
  189. /*
  190. Trivial Internal consistency check routines.
  191. */
  192. #undef __SUBROUTINE__
  193. #define __SUBROUTINE__ DBGT("CAccessLock::NotReadLocked")
  194. BOOL
  195. CAccessLock::NotReadLocked(
  196. void)
  197. {
  198. LockSection(&m_csLock, DBGT("Verifying Lock State"));
  199. BOOL fReturn = TRUE;
  200. for (DWORD ix = m_rgdwReaders.Count(); ix > 0;)
  201. {
  202. ix -= 1;
  203. if (GetCurrentThreadId() == m_rgdwReaders[ix])
  204. {
  205. fReturn = FALSE;
  206. break;
  207. }
  208. }
  209. return fReturn;
  210. }
  211. #undef __SUBROUTINE__
  212. #define __SUBROUTINE__ DBGT("CAccessLock::IsReadLocked")
  213. BOOL
  214. CAccessLock::IsReadLocked(
  215. void)
  216. {
  217. return !NotReadLocked();
  218. }
  219. #undef __SUBROUTINE__
  220. #define __SUBROUTINE__ DBGT("CAccessLock::NotWriteLocked")
  221. BOOL
  222. CAccessLock::NotWriteLocked(
  223. void)
  224. {
  225. LockSection(&m_csLock, DBGT("Verifying Lock state"));
  226. return (GetCurrentThreadId() != m_dwOwner);
  227. }
  228. #undef __SUBROUTINE__
  229. #define __SUBROUTINE__ DBGT("CAccessLock::IsWriteLocked")
  230. BOOL
  231. CAccessLock::IsWriteLocked(
  232. void)
  233. {
  234. LockSection(&m_csLock, DBGT("Verifying Lock state"));
  235. return (GetCurrentThreadId() == m_dwOwner);
  236. }
  237. #endif
  238. //
  239. //==============================================================================
  240. //
  241. // CLockRead
  242. //
  243. /*++
  244. CONSTRUCTOR:
  245. This is the constructor for a CLockRead object. The existence of this
  246. object forms a sharable read lock on the supplied CAccessLock object.
  247. Arguments:
  248. pLock supplies the CAccessLock object against which a read request is to
  249. be posted.
  250. Return Value:
  251. None
  252. Throws:
  253. None
  254. Remarks:
  255. ?Remarks?
  256. Author:
  257. Doug Barlow (dbarlow) 6/2/1998
  258. --*/
  259. #undef __SUBROUTINE__
  260. #define __SUBROUTINE__ DBGT("CLockRead::CLockRead")
  261. CLockRead::CLockRead(
  262. CAccessLock *pLock)
  263. {
  264. m_pLock = pLock;
  265. //
  266. // Quick check to see if we're already a writer.
  267. //
  268. {
  269. LockSection(&m_pLock->m_csLock, DBGT("Make sure we're not the writer"));
  270. if (m_pLock->m_dwOwner == GetCurrentThreadId())
  271. {
  272. ASSERT(0 < m_pLock->m_dwWriteCount);
  273. m_pLock->m_dwReadCount += 1;
  274. ASSERT(0 < m_pLock->m_dwReadCount);
  275. #ifdef DBG
  276. DWORD dwCurrentThread = GetCurrentThreadId();
  277. for (DWORD ix = 0; 0 != m_pLock->m_rgdwReaders[ix]; ix += 1);
  278. // Empty loop body
  279. m_pLock->m_rgdwReaders.Set(ix, dwCurrentThread);
  280. #endif
  281. m_pLock->UnsignalNoReaders();
  282. return;
  283. }
  284. }
  285. //
  286. // We're not a writer. Acquire the read lock.
  287. //
  288. for (;;)
  289. {
  290. m_pLock->WaitOnWriters();
  291. {
  292. LockSection(&m_pLock->m_csLock, DBGT("Get the read lock"));
  293. if ((0 == m_pLock->m_dwWriteCount)
  294. || (m_pLock->m_dwOwner == GetCurrentThreadId()))
  295. {
  296. m_pLock->m_dwReadCount += 1;
  297. ASSERT(0 < m_pLock->m_dwReadCount);
  298. #ifdef DBG
  299. DWORD dwCurrentThread = GetCurrentThreadId();
  300. for (DWORD ix = 0; 0 != m_pLock->m_rgdwReaders[ix]; ix += 1);
  301. // Empty loop body
  302. m_pLock->m_rgdwReaders.Set(ix, dwCurrentThread);
  303. #endif
  304. m_pLock->UnsignalNoReaders();
  305. break;
  306. }
  307. }
  308. }
  309. }
  310. /*++
  311. DESTRUCTOR:
  312. The CLockRead destructor frees the outstanding read lock on the CAccessLock
  313. object.
  314. Author:
  315. Doug Barlow (dbarlow) 6/2/1998
  316. --*/
  317. #undef __SUBROUTINE__
  318. #define __SUBROUTINE__ DBGT("CLockRead::~CLockRead")
  319. CLockRead::~CLockRead()
  320. {
  321. if (InitFailed())
  322. return;
  323. LockSection(&m_pLock->m_csLock, DBGT("Releasing the read lock"));
  324. ASSERT(0 < m_pLock->m_dwReadCount);
  325. m_pLock->m_dwReadCount -= 1;
  326. #ifdef DBG
  327. DWORD dwCurrentThread = GetCurrentThreadId();
  328. for (DWORD ix = m_pLock->m_rgdwReaders.Count(); ix > 0;)
  329. {
  330. ix -= 1;
  331. if (dwCurrentThread == m_pLock->m_rgdwReaders[ix])
  332. {
  333. m_pLock->m_rgdwReaders.Set(ix, 0);
  334. break;
  335. }
  336. ASSERT(0 < ix);
  337. }
  338. #endif
  339. if (0 == m_pLock->m_dwReadCount)
  340. m_pLock->SignalNoReaders();
  341. }
  342. //
  343. //==============================================================================
  344. //
  345. // CLockWrite
  346. //
  347. /*++
  348. CONSTRUCTOR:
  349. This is the constructor for a CLockWrite object. The existence of this
  350. object forms a unshared write lock on the supplied CAccessLock object.
  351. Arguments:
  352. pLock supplies the CAccessLock object against which a write request is to
  353. be posted.
  354. Return Value:
  355. None
  356. Throws:
  357. None
  358. Remarks:
  359. ?Remarks?
  360. Author:
  361. Doug Barlow (dbarlow) 6/2/1998
  362. --*/
  363. #undef __SUBROUTINE__
  364. #define __SUBROUTINE__ DBGT("CLockWrite::CLockWrite")
  365. CLockWrite::CLockWrite(
  366. CAccessLock *pLock)
  367. {
  368. m_pLock = pLock;
  369. //
  370. // Quick check to see if we're already a writer.
  371. //
  372. {
  373. LockSection(&m_pLock->m_csLock, DBGT("See if we're already a writer"));
  374. if (m_pLock->m_dwOwner == GetCurrentThreadId())
  375. {
  376. ASSERT(0 < m_pLock->m_dwWriteCount);
  377. m_pLock->m_dwWriteCount += 1;
  378. return;
  379. }
  380. }
  381. //
  382. // We're not a writer. Acquire the write lock.
  383. //
  384. for (;;)
  385. {
  386. m_pLock->WaitOnWriters();
  387. {
  388. LockSection(&m_pLock->m_csLock, DBGT("Get the Write lock"));
  389. if (0 == m_pLock->m_dwWriteCount)
  390. {
  391. ASSERT(m_pLock->NotReadLocked());
  392. ASSERT(0 == m_pLock->m_dwOwner);
  393. m_pLock->m_dwWriteCount += 1;
  394. m_pLock->m_dwOwner = GetCurrentThreadId();
  395. m_pLock->UnsignalNoWriters();
  396. break;
  397. }
  398. }
  399. }
  400. for (;;)
  401. {
  402. m_pLock->WaitOnReaders();
  403. {
  404. LockSection(&m_pLock->m_csLock, DBGT("See if we got the read lock"));
  405. if (0 == m_pLock->m_dwReadCount)
  406. break;
  407. #ifdef DBG
  408. else
  409. {
  410. DWORD dwIndex;
  411. for (dwIndex = m_pLock->m_rgdwReaders.Count(); dwIndex > 0;)
  412. {
  413. dwIndex -= 1;
  414. if (0 != m_pLock->m_rgdwReaders[dwIndex])
  415. break;
  416. ASSERT(0 < dwIndex); // No one will ever respond!
  417. }
  418. }
  419. #endif
  420. }
  421. }
  422. }
  423. /*++
  424. DESTRUCTOR:
  425. The CLockWrite destructor frees the outstanding write lock on the
  426. CAccessLock object.
  427. Author:
  428. Doug Barlow (dbarlow) 6/2/1998
  429. --*/
  430. #undef __SUBROUTINE__
  431. #define __SUBROUTINE__ DBGT("CLockWrite::~CLockWrite")
  432. CLockWrite::~CLockWrite()
  433. {
  434. if (InitFailed())
  435. return;
  436. LockSection(&m_pLock->m_csLock, DBGT("Releasing the write lock"));
  437. ASSERT(0 == m_pLock->m_dwReadCount);
  438. ASSERT(0 < m_pLock->m_dwWriteCount);
  439. ASSERT(m_pLock->m_dwOwner == GetCurrentThreadId());
  440. m_pLock->m_dwWriteCount -= 1;
  441. if (0 == m_pLock->m_dwWriteCount)
  442. {
  443. m_pLock->m_dwOwner = 0;
  444. m_pLock->SignalNoWriters();
  445. }
  446. }
  447. //
  448. //==============================================================================
  449. //
  450. // CMutex
  451. //
  452. /*++
  453. CONSTRUCTOR:
  454. The constructor for a CMutex object. A CMutex allows threads to synchronize
  455. on it. It differs from a regular mutex in that it is possible for one
  456. thread to take this mutex away from another thread.
  457. Arguments:
  458. None
  459. Author:
  460. Doug Barlow (dbarlow) 6/2/1998
  461. --*/
  462. #undef __SUBROUTINE__
  463. #define __SUBROUTINE__ DBGT("CMutex::CMutex")
  464. CMutex::CMutex(
  465. void)
  466. : m_csAccessLock(CSID_MUTEX),
  467. m_hAvailableEvent(DBGT("CMutex Availability event"))
  468. {
  469. m_dwOwnerThreadId = 0;
  470. m_dwGrabCount = 0;
  471. m_dwValidityCount = 0;
  472. m_hAvailableEvent = CreateEvent(NULL, FALSE, TRUE, NULL);
  473. if (!m_hAvailableEvent.IsValid())
  474. {
  475. DWORD dwErr = m_hAvailableEvent.GetLastError();
  476. CalaisWarning(
  477. __SUBROUTINE__,
  478. DBGT("Mutex Object cannot create its signal: %1"),
  479. dwErr);
  480. }
  481. }
  482. /*++
  483. DESTRUCTOR:
  484. This cleans up the mutex object.
  485. Author:
  486. Doug Barlow (dbarlow) 6/2/1998
  487. --*/
  488. #undef __SUBROUTINE__
  489. #define __SUBROUTINE__ DBGT("CMutex::~CMutex")
  490. CMutex::~CMutex()
  491. {
  492. if (InitFailed())
  493. return;
  494. Invalidate();
  495. if (m_hAvailableEvent.IsValid())
  496. m_hAvailableEvent.Close();
  497. }
  498. /*++
  499. Grab:
  500. Get a hold of the Mutex, blocking other threads that also need it.
  501. Arguments:
  502. None
  503. Return Value:
  504. none
  505. Throws:
  506. Errors are thrown as DWORD status codes
  507. Author:
  508. Doug Barlow (dbarlow) 6/2/1998
  509. --*/
  510. #undef __SUBROUTINE__
  511. #define __SUBROUTINE__ DBGT("CMutex::Grab")
  512. void
  513. CMutex::Grab(
  514. void)
  515. {
  516. DWORD dwValid;
  517. {
  518. LockSection(&m_csAccessLock, DBGT("See if we have the mutex already"));
  519. if (GetCurrentThreadId() == m_dwOwnerThreadId)
  520. {
  521. ASSERT(0 < m_dwGrabCount);
  522. m_dwGrabCount += 1;
  523. return;
  524. }
  525. dwValid = m_dwValidityCount;
  526. }
  527. WaitForever(
  528. m_hAvailableEvent,
  529. REASONABLE_TIME,
  530. DBGT("Waiting to grab CMutex (owner %2): %1"),
  531. m_dwOwnerThreadId);
  532. LockSection(&m_csAccessLock, DBGT("Grab the Mutex"));
  533. if (dwValid == m_dwValidityCount)
  534. {
  535. ASSERT(0 == m_dwGrabCount);
  536. ASSERT(0 == m_dwOwnerThreadId);
  537. m_dwOwnerThreadId = GetCurrentThreadId();
  538. m_dwGrabCount = 1;
  539. }
  540. else
  541. {
  542. if (!SetEvent(m_hAvailableEvent))
  543. {
  544. DWORD dwErr = GetLastError();
  545. CalaisWarning(
  546. __SUBROUTINE__,
  547. DBGT("Mutex Object cannot set its signal: %1"),
  548. dwErr);
  549. throw dwErr;
  550. }
  551. CalaisWarning(
  552. __SUBROUTINE__,
  553. DBGT("Attempt to grab reader a failed -- grab invalidated"));
  554. throw (DWORD)SCARD_E_READER_UNAVAILABLE; // ?SCARD_E_SYSTEM_CANCELLED?
  555. }
  556. }
  557. /*++
  558. Share:
  559. This method is called when the owning thread no longer requires the mutex.
  560. Arguments:
  561. None
  562. Return Value:
  563. None
  564. Throws:
  565. Errors are thrown as DWORD status codes.
  566. Author:
  567. Doug Barlow (dbarlow) 6/2/1998
  568. --*/
  569. #undef __SUBROUTINE__
  570. #define __SUBROUTINE__ DBGT("CMutex::Share")
  571. BOOL
  572. CMutex::Share(
  573. void)
  574. {
  575. BOOL fRtn = FALSE;
  576. LockSection(&m_csAccessLock, DBGT("Release the mutex"));
  577. if (m_dwOwnerThreadId == GetCurrentThreadId())
  578. {
  579. ASSERT(0 < m_dwGrabCount);
  580. m_dwGrabCount -= 1;
  581. if (0 == m_dwGrabCount)
  582. {
  583. m_dwOwnerThreadId = 0;
  584. if (!SetEvent(m_hAvailableEvent))
  585. {
  586. DWORD dwErr = GetLastError();
  587. CalaisWarning(
  588. __SUBROUTINE__,
  589. DBGT("Mutex Object cannot set its signal: %1"),
  590. dwErr);
  591. }
  592. }
  593. fRtn = TRUE;
  594. }
  595. return fRtn;
  596. }
  597. /*++
  598. Invalidate:
  599. This method causes any owning thread to lose the mutex, making it available
  600. for others.
  601. Arguments:
  602. None
  603. Return Value:
  604. None
  605. Throws:
  606. Errors are thrown as DWORD status codes.
  607. Remarks:
  608. This routine waits until it can access the originally supplied HANDLE before
  609. stealing the mutex. That way, the owning thread can make critical areas
  610. where the mutex is guaranteed to not be taken away.
  611. Author:
  612. Doug Barlow (dbarlow) 6/2/1998
  613. --*/
  614. #undef __SUBROUTINE__
  615. #define __SUBROUTINE__ DBGT("CMutex::Invalidate")
  616. void
  617. CMutex::Invalidate(
  618. void)
  619. {
  620. LockSection(&m_csAccessLock, DBGT("Invalidate any outstanding grabs"));
  621. m_dwValidityCount += 1;
  622. m_dwOwnerThreadId = 0;
  623. m_dwGrabCount = 0;
  624. if (!SetEvent(m_hAvailableEvent))
  625. {
  626. CalaisWarning(
  627. __SUBROUTINE__,
  628. DBGT("Mutex Object cannot set its signal: %1"),
  629. GetLastError());
  630. }
  631. }
  632. /*++
  633. Take:
  634. This method causes any owning thread to lose the mutex, reassigning the
  635. mutex to the current calling thread.
  636. Arguments:
  637. None
  638. Return Value:
  639. None
  640. Throws:
  641. Errors are thrown as DWORD status codes.
  642. Remarks:
  643. This routine waits until it can access the originally supplied HANDLE before
  644. stealing the mutex. That way, the owning thread can make critical areas
  645. where the mutex is guaranteed to not be taken away.
  646. Author:
  647. Doug Barlow (dbarlow) 6/2/1998
  648. --*/
  649. #undef __SUBROUTINE__
  650. #define __SUBROUTINE__ DBGT("CMutex::Take")
  651. void
  652. CMutex::Take(
  653. void)
  654. {
  655. LockSection(&m_csAccessLock, DBGT("Take the mutex"));
  656. if (!ResetEvent(m_hAvailableEvent))
  657. {
  658. DWORD dwErr = GetLastError();
  659. CalaisWarning(
  660. __SUBROUTINE__,
  661. DBGT("Mutex Object cannot reset its signal: %1"),
  662. dwErr);
  663. }
  664. m_dwValidityCount += 1;
  665. m_dwOwnerThreadId = GetCurrentThreadId();
  666. m_dwGrabCount = 1;
  667. }
  668. /*++
  669. Simple state checking services
  670. --*/
  671. #undef __SUBROUTINE__
  672. #define __SUBROUTINE__ DBGT("CMutex::IsGrabbed")
  673. BOOL
  674. CMutex::IsGrabbed(
  675. void)
  676. {
  677. LockSection(&m_csAccessLock, DBGT("Is the mutex owned?"));
  678. return (m_dwOwnerThreadId != 0);
  679. }
  680. #undef __SUBROUTINE__
  681. #define __SUBROUTINE__ DBGT("CMutex::IsGrabbedBy")
  682. BOOL
  683. CMutex::IsGrabbedBy(
  684. DWORD dwThreadId)
  685. {
  686. LockSection(&m_csAccessLock, DBGT("Check mutex ownership"));
  687. return (m_dwOwnerThreadId == dwThreadId);
  688. }
  689. #undef __SUBROUTINE__
  690. #define __SUBROUTINE__ DBGT("CMutex::IsGrabbedByMe")
  691. BOOL
  692. CMutex::IsGrabbedByMe(
  693. void)
  694. {
  695. return IsGrabbedBy(GetCurrentThreadId());
  696. }
  697. //
  698. //==============================================================================
  699. //
  700. // CMultiEvent
  701. //
  702. /*++
  703. CONSTRUCTOR:
  704. This is the constructor for a CMultiEvent object. A MultiEvent object is
  705. used for events that need a single event, but which listeners may not be
  706. quick to watch for. It has an array of events, and sets them round robin,
  707. so that a waiter politely waits for their particular event.
  708. Arguments:
  709. None
  710. Author:
  711. Doug Barlow (dbarlow) 6/2/1998
  712. --*/
  713. #undef __SUBROUTINE__
  714. #define __SUBROUTINE__ DBGT("CMultiEvent::CMultiEvent")
  715. CMultiEvent::CMultiEvent(
  716. void)
  717. : m_csLock(CSID_MULTIEVENT)
  718. {
  719. for (DWORD ix = 0; ix < sizeof(m_rghEvents) / sizeof(HANDLE); ix += 1)
  720. m_rghEvents[ix] = NULL;
  721. for (ix = 0; ix < sizeof(m_rghEvents) / sizeof(HANDLE); ix += 1)
  722. {
  723. m_rghEvents[ix] = CreateEvent(NULL, TRUE, FALSE, NULL);
  724. if (NULL == m_rghEvents[ix])
  725. throw GetLastError();
  726. }
  727. m_dwEventIndex = 0;
  728. }
  729. /*++
  730. DESTRUCTOR:
  731. This method cleans up after a CMultiEvent object is no longer needed.
  732. Author:
  733. Doug Barlow (dbarlow) 6/2/1998
  734. --*/
  735. #undef __SUBROUTINE__
  736. #define __SUBROUTINE__ DBGT("CMultiEvent::~CMultiEvent")
  737. CMultiEvent::~CMultiEvent()
  738. {
  739. for (DWORD ix = 0; ix < sizeof(m_rghEvents) / sizeof(HANDLE); ix += 1)
  740. {
  741. if (NULL != m_rghEvents[ix])
  742. {
  743. if (!CloseHandle(m_rghEvents[ix]))
  744. CalaisWarning(
  745. __SUBROUTINE__,
  746. DBGT("Failed to close MultiEvent handle: %1"),
  747. GetLastError());
  748. }
  749. }
  750. }
  751. /*++
  752. WaitHandle:
  753. This method returns the handle of the current event, suitable for waiting
  754. on.
  755. Arguments:
  756. None
  757. Return Value:
  758. The value of the handle which can be waited on.
  759. Throws:
  760. None
  761. Remarks:
  762. ?Remarks?
  763. Author:
  764. Doug Barlow (dbarlow) 6/2/1998
  765. --*/
  766. #undef __SUBROUTINE__
  767. #define __SUBROUTINE__ DBGT("CMultiEvent::WaitHandle")
  768. HANDLE
  769. CMultiEvent::WaitHandle(
  770. void)
  771. {
  772. LockSection(&m_csLock, DBGT("Obtaining the current wait handle"));
  773. return m_rghEvents[m_dwEventIndex];
  774. }
  775. /*++
  776. Signal:
  777. This method signals the current handle, and moves onto the next handle in
  778. the array. This way it can leave the current handle set for a significant
  779. time period, but still provide new waiters with reason to block.
  780. Arguments:
  781. None
  782. Return Value:
  783. None
  784. Author:
  785. Doug Barlow (dbarlow) 6/2/1998
  786. --*/
  787. #undef __SUBROUTINE__
  788. #define __SUBROUTINE__ DBGT("CMultiEvent::Signal")
  789. void
  790. CMultiEvent::Signal(
  791. void)
  792. {
  793. LockSection(&m_csLock, DBGT("Signal the current event"));
  794. if (!SetEvent(m_rghEvents[m_dwEventIndex]))
  795. throw GetLastError();
  796. m_dwEventIndex += 1;
  797. m_dwEventIndex %= sizeof(m_rghEvents) / sizeof(HANDLE);
  798. if (!ResetEvent(m_rghEvents[m_dwEventIndex]))
  799. throw GetLastError();
  800. }
  801. /*++
  802. WaitForAnObject:
  803. This routine performs object waiting services. It really doesn't have
  804. anything to do with locking except that there are so many error conditions
  805. to check for that it's more convenient to have it off in its own routine.
  806. Arguments:
  807. hWaitOn supplies the handle to wait on.
  808. dwTimeout supplies the wait timeout value.
  809. Return Value:
  810. The error code, if any
  811. Throws:
  812. None
  813. Author:
  814. Doug Barlow (dbarlow) 6/19/1997
  815. --*/
  816. #undef __SUBROUTINE__
  817. #define __SUBROUTINE__ DBGT("WaitForAnObject")
  818. DWORD
  819. WaitForAnObject(
  820. HANDLE hWaitOn,
  821. DWORD dwTimeout)
  822. {
  823. DWORD dwReturn = SCARD_S_SUCCESS;
  824. DWORD dwSts;
  825. ASSERT(INVALID_HANDLE_VALUE != hWaitOn);
  826. ASSERT(NULL != hWaitOn);
  827. dwSts = WaitForSingleObject(hWaitOn, dwTimeout);
  828. switch (dwSts)
  829. {
  830. case WAIT_FAILED:
  831. dwSts = GetLastError();
  832. CalaisWarning(
  833. __SUBROUTINE__,
  834. DBGT("Wait for object failed: %1"),
  835. dwSts);
  836. dwReturn = dwSts;
  837. break;
  838. case WAIT_TIMEOUT:
  839. CalaisWarning(
  840. __SUBROUTINE__,
  841. DBGT("Wait for object timed out"));
  842. dwReturn = SCARD_F_WAITED_TOO_LONG;
  843. break;
  844. case WAIT_ABANDONED:
  845. CalaisWarning(
  846. __SUBROUTINE__,
  847. DBGT("Wait for object received wait abandoned"));
  848. // That's OK, we still got it.
  849. break;
  850. case WAIT_OBJECT_0:
  851. break;
  852. default:
  853. CalaisWarning(
  854. __SUBROUTINE__,
  855. DBGT("Wait for object got invalid response"));
  856. dwReturn = SCARD_F_INTERNAL_ERROR;
  857. }
  858. return dwReturn;
  859. }
  860. /*++
  861. WaitForObjects:
  862. This routine is a utility to allow waiting for multiple objects. It returns
  863. the index of the object that completed.
  864. Arguments:
  865. dwTimeout supplies the timeout value, in milliseconds, or INFINITE.
  866. hObject and following supply the list of objects to wait for. This list
  867. must be NULL terminated.
  868. Return Value:
  869. The number of the object completed. 1 implies the first one, 2 implies the
  870. second one, etc.
  871. Throws:
  872. Errors are thrown as DWORD status codes.
  873. Author:
  874. Doug Barlow (dbarlow) 6/17/1998
  875. --*/
  876. #undef __SUBROUTINE__
  877. #define __SUBROUTINE__ DBGT("WaitForAnyObject")
  878. DWORD
  879. WaitForAnyObject(
  880. DWORD dwTimeout,
  881. ...)
  882. {
  883. va_list ap;
  884. HANDLE h, rgh[4];
  885. DWORD dwIndex = 0, dwWait, dwErr;
  886. va_start(ap, dwTimeout);
  887. for (h = va_arg(ap, HANDLE); NULL != h; h = va_arg(ap, HANDLE))
  888. {
  889. ASSERT(dwIndex < sizeof(rgh) / sizeof(HANDLE));
  890. ASSERT(INVALID_HANDLE_VALUE != h);
  891. if (INVALID_HANDLE_VALUE != h)
  892. rgh[dwIndex++] = h;
  893. }
  894. va_end(ap);
  895. ASSERT(0 < dwIndex);
  896. if (0 < dwIndex)
  897. dwWait = WaitForMultipleObjects(dwIndex, rgh, FALSE, dwTimeout);
  898. else
  899. {
  900. dwWait = WAIT_FAILED;
  901. SetLastError(ERROR_INVALID_EVENT_COUNT);
  902. // That's a good symbolic name, but a lousy user message.
  903. }
  904. switch (dwWait)
  905. {
  906. case WAIT_FAILED:
  907. dwErr = GetLastError();
  908. CalaisWarning(
  909. __SUBROUTINE__,
  910. DBGT("WaitForObjects failed its wait: %1"),
  911. dwErr);
  912. throw dwErr;
  913. break;
  914. case WAIT_TIMEOUT:
  915. CalaisWarning(
  916. __SUBROUTINE__,
  917. DBGT("WaitForObjects timed out on its wait"));
  918. throw (DWORD)ERROR_TIMEOUT;
  919. break;
  920. default:
  921. C_ASSERT(WAIT_OBJECT_0 == 0);
  922. ASSERT(WAIT_OBJECT_0 < WAIT_ABANDONED_0);
  923. if ((dwWait >= WAIT_ABANDONED_0)
  924. && (dwWait < (WAIT_ABANDONED_0 + WAIT_ABANDONED_0 - WAIT_OBJECT_0)))
  925. {
  926. CalaisWarning(
  927. __SUBROUTINE__,
  928. DBGT("WaitForObjects received a Wait Abandoned warning"));
  929. dwIndex = dwWait - WAIT_ABANDONED_0 + 1;
  930. }
  931. else if (dwWait < WAIT_ABANDONED_0)
  932. {
  933. dwIndex = dwWait - WAIT_OBJECT_0 + 1;
  934. }
  935. else
  936. {
  937. CalaisWarning(
  938. __SUBROUTINE__,
  939. DBGT("WaitForObjects received unknown error code: %1"),
  940. dwWait);
  941. throw dwWait;
  942. }
  943. }
  944. return dwIndex;
  945. }
  946. #ifdef DBG
  947. //
  948. // Critical Section Support.
  949. //
  950. // The following Classes aid in debugging Critical Section Conflicts.
  951. //
  952. static const TCHAR l_szUnowned[] = TEXT("<Unowned>");
  953. static const LPCTSTR l_rgszLockList[]
  954. = { DBGT("Service Status Critical Section"), // CSID_SERVICE_STATUS
  955. DBGT("Lock for Calais control commands."), // CSID_CONTROL_LOCK
  956. DBGT("Lock for server thread enumeration."), // CSID_SERVER_THREADS
  957. DBGT("MultiEvent Critical Access Section"), // CSID_MULTIEVENT
  958. DBGT("Mutex critical access section"), // CSID_MUTEX
  959. DBGT("Access Lock control"), // CSID_ACCESSCONTROL
  960. DBGT("Lock for tracing output."), // CSID_TRACEOUTPUT
  961. NULL };
  962. //
  963. //==============================================================================
  964. //
  965. // CCriticalSectionObject
  966. //
  967. /*++
  968. CONSTRUCTOR:
  969. This method builds the critical section object and coordinates its tracking.
  970. Arguments:
  971. szDescription supplies a description of what this critical section object
  972. is used for. This aids identification.
  973. Return Value:
  974. None
  975. Throws:
  976. None
  977. Remarks:
  978. ?Remarks?
  979. Author:
  980. Doug Barlow (dbarlow) 3/19/1999
  981. --*/
  982. #undef __SUBROUTINE__
  983. #define __SUBROUTINE__ DBGT("CCriticalSectionObject::CCriticalSectionObject")
  984. CCriticalSectionObject::CCriticalSectionObject(
  985. DWORD dwCsid)
  986. {
  987. m_fInitFailed = TRUE;
  988. try {
  989. // Preallocate the event used by the EnterCriticalSection
  990. // function to prevent an exception from being thrown in
  991. // CCriticalSectionObject::Enter
  992. if (! InitializeCriticalSectionAndSpinCount(
  993. &m_csLock, 0x80000000))
  994. return;
  995. }
  996. catch (HRESULT hr) {
  997. return;
  998. }
  999. m_dwCsid = dwCsid;
  1000. m_bfOwner.Set((LPCBYTE)l_szUnowned, sizeof(l_szUnowned));
  1001. m_bfComment.Set((LPCBYTE)DBGT(""), sizeof(TCHAR));
  1002. m_dwOwnerThread = 0;
  1003. m_dwRecursion = 0;
  1004. m_fInitFailed = FALSE;
  1005. }
  1006. /*++
  1007. DESTRUCTOR:
  1008. This method cleans up the critical section object.
  1009. Arguments:
  1010. None
  1011. Return Value:
  1012. None
  1013. Throws:
  1014. None
  1015. Remarks:
  1016. ?Remarks?
  1017. Author:
  1018. Doug Barlow (dbarlow) 3/19/1999
  1019. --*/
  1020. #undef __SUBROUTINE__
  1021. #define __SUBROUTINE__ DBGT("CCriticalSectionObject::~CCriticalSectionObject")
  1022. CCriticalSectionObject::~CCriticalSectionObject()
  1023. {
  1024. if (m_fInitFailed)
  1025. return;
  1026. if (0 == m_dwOwnerThread)
  1027. {
  1028. ASSERT(0 == m_dwRecursion);
  1029. }
  1030. else
  1031. {
  1032. ASSERT(IsOwnedByMe());
  1033. ASSERT(1 == m_dwRecursion);
  1034. LeaveCriticalSection(&m_csLock);
  1035. }
  1036. DeleteCriticalSection(&m_csLock);
  1037. }
  1038. /*++
  1039. Enter:
  1040. This method enters a critical section, and tracks the owner.
  1041. Arguments:
  1042. szOwner supplies the name of the calling subroutine.
  1043. szComment supplies an additional comment to help distinguish between
  1044. multiple calls within a subroutine.
  1045. Return Value:
  1046. None
  1047. Throws:
  1048. None
  1049. Remarks:
  1050. ?Remarks?
  1051. Author:
  1052. Doug Barlow (dbarlow) 3/19/1999
  1053. --*/
  1054. #undef __SUBROUTINE__
  1055. #define __SUBROUTINE__ DBGT("CCriticalSectionObject::Enter")
  1056. void
  1057. CCriticalSectionObject::Enter(
  1058. LPCTSTR szOwner,
  1059. LPCTSTR szComment)
  1060. {
  1061. if (m_fInitFailed)
  1062. throw (DWORD)SCARD_E_NO_MEMORY;
  1063. EnterCriticalSection(&m_csLock);
  1064. if (0 == m_dwRecursion)
  1065. {
  1066. ASSERT(0 == m_dwOwnerThread);
  1067. m_dwOwnerThread = GetCurrentThreadId();
  1068. m_bfOwner.Set(
  1069. (LPCBYTE)szOwner,
  1070. (lstrlen(szOwner) + 1) * sizeof(TCHAR));
  1071. m_bfComment.Set(
  1072. (LPCBYTE)szComment,
  1073. (lstrlen(szComment) + 1) * sizeof(TCHAR));
  1074. }
  1075. else
  1076. {
  1077. ASSERT(GetCurrentThreadId() == m_dwOwnerThread);
  1078. CalaisDebug((
  1079. DBGT("Critical Section '%s' already owned by %s (%s)\nCalled from %s (%s)\n"),
  1080. Description(),
  1081. Owner(),
  1082. Comment(),
  1083. szOwner,
  1084. szComment));
  1085. }
  1086. m_dwRecursion += 1;
  1087. ASSERT(0 < m_dwRecursion);
  1088. }
  1089. /*++
  1090. Leave:
  1091. This method exits a critical section.
  1092. Arguments:
  1093. None
  1094. Return Value:
  1095. None
  1096. Throws:
  1097. None
  1098. Remarks:
  1099. ?Remarks?
  1100. Author:
  1101. Doug Barlow (dbarlow) 3/19/1999
  1102. --*/
  1103. #undef __SUBROUTINE__
  1104. #define __SUBROUTINE__ DBGT("CCriticalSectionObject::Leave")
  1105. void
  1106. CCriticalSectionObject::Leave(
  1107. void)
  1108. {
  1109. ASSERT(0 < m_dwRecursion);
  1110. m_dwRecursion -= 1;
  1111. if (0 == m_dwRecursion)
  1112. {
  1113. m_bfOwner.Set((LPCBYTE)l_szUnowned, sizeof(l_szUnowned));
  1114. m_bfComment.Set((LPCBYTE)DBGT(""), sizeof(TCHAR));
  1115. m_dwOwnerThread = 0;
  1116. }
  1117. LeaveCriticalSection(&m_csLock);
  1118. }
  1119. /*++
  1120. Description:
  1121. Translate the Critical Section Id number to a descriptive string.
  1122. Arguments:
  1123. None
  1124. Return Value:
  1125. The descriptive string corresponding to this critical section type.
  1126. Throws:
  1127. None
  1128. Remarks:
  1129. ?Remarks?
  1130. Author:
  1131. Doug Barlow (dbarlow) 3/22/1999
  1132. --*/
  1133. #undef __SUBROUTINE__
  1134. #define __SUBROUTINE__ DBGT("CCriticalSectionObject::Description")
  1135. LPCTSTR
  1136. CCriticalSectionObject::Description(
  1137. void)
  1138. const
  1139. {
  1140. return l_rgszLockList[m_dwCsid];
  1141. }
  1142. #endif