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.

1096 lines
23 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1998 - 1999
  3. Module Name:
  4. locks
  5. Abstract:
  6. This module provides the implementations of common lock objects.
  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 "cspUtils.h"
  19. //
  20. //==============================================================================
  21. //
  22. // CAccessLock
  23. //
  24. /*++
  25. CONSTRUCTOR:
  26. A CAccessLock provides a multiple-reader, single writer lock on a structure.
  27. Arguments:
  28. dwTimeout supplies a reasonable timeout value for any lock.
  29. Remarks:
  30. Author:
  31. Doug Barlow (dbarlow) 6/2/1998
  32. --*/
  33. #undef __SUBROUTINE__
  34. #define __SUBROUTINE__ TEXT("CAccessLock::CAccessLock")
  35. CAccessLock::CAccessLock(
  36. DWORD dwTimeout)
  37. : m_csLock(CSID_ACCESSCONTROL),
  38. m_hSignalNoReaders(DBGT("CAccessLock No Readers Event")),
  39. m_hSignalNoWriters(DBGT("CAccessLock No Writers Event"))
  40. #ifdef DBG
  41. , m_rgdwReaders()
  42. #endif
  43. {
  44. m_hSignalNoReaders = CreateEvent(NULL, TRUE, TRUE, NULL);
  45. if (!m_hSignalNoReaders.IsValid())
  46. {
  47. DWORD dwSts = m_hSignalNoReaders.GetLastError();
  48. CalaisWarning(
  49. __SUBROUTINE__,
  50. DBGT("Access Lock Object cannot create the No Readers signal: %1"),
  51. dwSts);
  52. throw dwSts; // Force a shutdown.
  53. }
  54. m_hSignalNoWriters = CreateEvent(NULL, TRUE, TRUE, NULL);
  55. if (!m_hSignalNoWriters.IsValid())
  56. {
  57. DWORD dwSts = m_hSignalNoWriters.GetLastError();
  58. CalaisWarning(
  59. __SUBROUTINE__,
  60. DBGT("Access Lock Object cannot create the No Writers signal: %1"),
  61. dwSts);
  62. throw dwSts; // Force a shutdown.
  63. }
  64. m_dwOwner = 0;
  65. m_dwReadCount = m_dwWriteCount = 0;
  66. m_dwTimeout = dwTimeout;
  67. }
  68. /*++
  69. DESTRUCTOR:
  70. This cleans up after a CAccessLock.
  71. Arguments:
  72. None
  73. Author:
  74. Doug Barlow (dbarlow) 6/2/1998
  75. --*/
  76. #undef __SUBROUTINE__
  77. #define __SUBROUTINE__ TEXT("CAccessLock::~CAccessLock")
  78. CAccessLock::~CAccessLock()
  79. {
  80. {
  81. CLockWrite rwLock(this);
  82. m_csLock.Enter(
  83. __SUBROUTINE__,
  84. DBGT("Closing down the CAccessLock"));
  85. }
  86. #ifdef DBG
  87. {
  88. ASSERT(0 == m_dwReadCount);
  89. for (DWORD ix = m_rgdwReaders.Count(); ix > 0;)
  90. {
  91. ix -= 1;
  92. ASSERT(0 == m_rgdwReaders[ix]);
  93. }
  94. }
  95. #endif
  96. if (m_hSignalNoReaders.IsValid())
  97. m_hSignalNoReaders.Close();
  98. if (m_hSignalNoWriters.IsValid())
  99. m_hSignalNoWriters.Close();
  100. }
  101. /*++
  102. Wait:
  103. Wait for the usage signal to trigger.
  104. Arguments:
  105. hSignal supplies the handle to use for the wait.
  106. Return Value:
  107. None
  108. Throws:
  109. None
  110. Remarks:
  111. This routine blocks until the usage signal fires.
  112. Author:
  113. Doug Barlow (dbarlow) 6/2/1998
  114. --*/
  115. #undef __SUBROUTINE__
  116. #define __SUBROUTINE__ TEXT("CAccessLock::Wait")
  117. void
  118. CAccessLock::Wait(
  119. HANDLE hSignal)
  120. {
  121. WaitForever(
  122. hSignal,
  123. m_dwTimeout,
  124. DBGT("Waiting for Read/Write Lock signal (owner %2): %1"),
  125. m_dwOwner);
  126. }
  127. /*++
  128. Signal:
  129. This routine signals the usage signal that the structure is available.
  130. Arguments:
  131. hSignal supplies the handle to be signaled.
  132. Return Value:
  133. None
  134. Throws:
  135. Errors are thrown as DWORD status codes
  136. Author:
  137. Doug Barlow (dbarlow) 6/2/1998
  138. --*/
  139. #undef __SUBROUTINE__
  140. #define __SUBROUTINE__ TEXT("CAccessLock::Signal")
  141. void
  142. CAccessLock::Signal(
  143. HANDLE hSignal)
  144. {
  145. if (!SetEvent(hSignal))
  146. {
  147. DWORD dwSts = GetLastError();
  148. CalaisWarning(
  149. __SUBROUTINE__,
  150. DBGT("Access Lock Object cannot set its signal: %1"),
  151. dwSts);
  152. throw dwSts;
  153. }
  154. }
  155. /*++
  156. Unsignal:
  157. This method is used to notify other threads that the lock has been taken.
  158. Arguments:
  159. hSignal supplies the handle to be reset.
  160. Return Value:
  161. None
  162. Throws:
  163. Errors are thrown as DWORD status codes.
  164. Remarks:
  165. Author:
  166. Doug Barlow (dbarlow) 6/3/1998
  167. --*/
  168. #undef __SUBROUTINE__
  169. #define __SUBROUTINE__ TEXT("CAccessLock::Unsignal")
  170. void
  171. CAccessLock::Unsignal(
  172. HANDLE hSignal)
  173. {
  174. if (!ResetEvent(hSignal))
  175. {
  176. DWORD dwSts = GetLastError();
  177. CalaisWarning(
  178. __SUBROUTINE__,
  179. DBGT("Access Lock Object cannot reset its signal: %1"),
  180. dwSts);
  181. throw dwSts;
  182. }
  183. }
  184. #ifdef DBG
  185. /*
  186. Trivial Internal consistency check routines.
  187. */
  188. #undef __SUBROUTINE__
  189. #define __SUBROUTINE__ TEXT("CAccessLock::NotReadLocked")
  190. BOOL
  191. CAccessLock::NotReadLocked(
  192. void)
  193. {
  194. LockSection(&m_csLock, DBGT("Verifying Lock State"));
  195. BOOL fReturn = TRUE;
  196. for (DWORD ix = m_rgdwReaders.Count(); ix > 0;)
  197. {
  198. ix -= 1;
  199. if ((LPVOID)GetCurrentThreadId() == m_rgdwReaders[ix])
  200. {
  201. fReturn = FALSE;
  202. break;
  203. }
  204. }
  205. return fReturn;
  206. }
  207. #undef __SUBROUTINE__
  208. #define __SUBROUTINE__ TEXT("CAccessLock::IsReadLocked")
  209. BOOL
  210. CAccessLock::IsReadLocked(
  211. void)
  212. {
  213. return !NotReadLocked();
  214. }
  215. #undef __SUBROUTINE__
  216. #define __SUBROUTINE__ TEXT("CAccessLock::NotWriteLocked")
  217. BOOL
  218. CAccessLock::NotWriteLocked(
  219. void)
  220. {
  221. LockSection(&m_csLock, DBGT("Verifying Lock state"));
  222. return (GetCurrentThreadId() != m_dwOwner);
  223. }
  224. #undef __SUBROUTINE__
  225. #define __SUBROUTINE__ TEXT("CAccessLock::IsWriteLocked")
  226. BOOL
  227. CAccessLock::IsWriteLocked(
  228. void)
  229. {
  230. LockSection(&m_csLock, DBGT("Verifying Lock state"));
  231. return (GetCurrentThreadId() == m_dwOwner);
  232. }
  233. #endif
  234. //
  235. //==============================================================================
  236. //
  237. // CLockRead
  238. //
  239. /*++
  240. CONSTRUCTOR:
  241. This is the constructor for a CLockRead object. The existence of this
  242. object forms a sharable read lock on the supplied CAccessLock object.
  243. Arguments:
  244. pLock supplies the CAccessLock object against which a read request is to
  245. be posted.
  246. Return Value:
  247. None
  248. Throws:
  249. None
  250. Remarks:
  251. ?Remarks?
  252. Author:
  253. Doug Barlow (dbarlow) 6/2/1998
  254. --*/
  255. #undef __SUBROUTINE__
  256. #define __SUBROUTINE__ TEXT("CLockRead::CLockRead")
  257. CLockRead::CLockRead(
  258. CAccessLock *pLock)
  259. {
  260. m_pLock = pLock;
  261. //
  262. // Quick check to see if we're already a writer.
  263. //
  264. {
  265. LockSection(&m_pLock->m_csLock, DBGT("Make sure we're not the writer"));
  266. if (m_pLock->m_dwOwner == GetCurrentThreadId())
  267. {
  268. ASSERT(0 < m_pLock->m_dwWriteCount);
  269. m_pLock->m_dwReadCount += 1;
  270. ASSERT(0 < m_pLock->m_dwReadCount);
  271. #ifdef DBG
  272. DWORD dwCurrentThread = GetCurrentThreadId();
  273. for (DWORD ix = 0; NULL != m_pLock->m_rgdwReaders[ix]; ix += 1);
  274. // Empty loop body
  275. m_pLock->m_rgdwReaders.Set(ix, (LPVOID)dwCurrentThread);
  276. #endif
  277. m_pLock->UnsignalNoReaders();
  278. return;
  279. }
  280. }
  281. //
  282. // We're not a writer. Acquire the read lock.
  283. //
  284. for (;;)
  285. {
  286. m_pLock->WaitOnWriters();
  287. {
  288. LockSection(&m_pLock->m_csLock, DBGT("Get the read lock"));
  289. if ((0 == m_pLock->m_dwWriteCount)
  290. || (m_pLock->m_dwOwner == GetCurrentThreadId()))
  291. {
  292. m_pLock->m_dwReadCount += 1;
  293. ASSERT(0 < m_pLock->m_dwReadCount);
  294. #ifdef DBG
  295. DWORD dwCurrentThread = GetCurrentThreadId();
  296. for (DWORD ix = 0; NULL != m_pLock->m_rgdwReaders[ix]; ix += 1);
  297. // Empty loop body
  298. m_pLock->m_rgdwReaders.Set(ix, (LPVOID)dwCurrentThread);
  299. #endif
  300. m_pLock->UnsignalNoReaders();
  301. break;
  302. }
  303. }
  304. }
  305. }
  306. /*++
  307. DESTRUCTOR:
  308. The CLockRead destructor frees the outstanding read lock on the CAccessLock
  309. object.
  310. Author:
  311. Doug Barlow (dbarlow) 6/2/1998
  312. --*/
  313. #undef __SUBROUTINE__
  314. #define __SUBROUTINE__ TEXT("CLockRead::~CLockRead")
  315. CLockRead::~CLockRead()
  316. {
  317. LockSection(&m_pLock->m_csLock, DBGT("Releasing the read lock"));
  318. ASSERT(0 < m_pLock->m_dwReadCount);
  319. m_pLock->m_dwReadCount -= 1;
  320. #ifdef DBG
  321. DWORD dwCurrentThread = GetCurrentThreadId();
  322. for (DWORD ix = m_pLock->m_rgdwReaders.Count(); ix > 0;)
  323. {
  324. ix -= 1;
  325. if ((LPVOID)dwCurrentThread == m_pLock->m_rgdwReaders[ix])
  326. {
  327. m_pLock->m_rgdwReaders.Set(ix, NULL);
  328. break;
  329. }
  330. ASSERT(0 < ix);
  331. }
  332. #endif
  333. if (0 == m_pLock->m_dwReadCount)
  334. m_pLock->SignalNoReaders();
  335. }
  336. //
  337. //==============================================================================
  338. //
  339. // CLockWrite
  340. //
  341. /*++
  342. CONSTRUCTOR:
  343. This is the constructor for a CLockWrite object. The existence of this
  344. object forms a unshared write lock on the supplied CAccessLock object.
  345. Arguments:
  346. pLock supplies the CAccessLock object against which a write request is to
  347. be posted.
  348. Return Value:
  349. None
  350. Throws:
  351. None
  352. Remarks:
  353. ?Remarks?
  354. Author:
  355. Doug Barlow (dbarlow) 6/2/1998
  356. --*/
  357. #undef __SUBROUTINE__
  358. #define __SUBROUTINE__ TEXT("CLockWrite::CLockWrite")
  359. CLockWrite::CLockWrite(
  360. CAccessLock *pLock)
  361. {
  362. m_pLock = pLock;
  363. //
  364. // Quick check to see if we're already a writer.
  365. //
  366. {
  367. LockSection(&m_pLock->m_csLock, DBGT("See if we're already a writer"));
  368. if (m_pLock->m_dwOwner == GetCurrentThreadId())
  369. {
  370. ASSERT(0 < m_pLock->m_dwWriteCount);
  371. m_pLock->m_dwWriteCount += 1;
  372. return;
  373. }
  374. }
  375. //
  376. // We're not a writer. Acquire the write lock.
  377. //
  378. for (;;)
  379. {
  380. m_pLock->WaitOnWriters();
  381. {
  382. LockSection(&m_pLock->m_csLock, DBGT("Get the Write lock"));
  383. if (0 == m_pLock->m_dwWriteCount)
  384. {
  385. ASSERT(m_pLock->NotReadLocked());
  386. ASSERT(0 == m_pLock->m_dwOwner);
  387. m_pLock->m_dwWriteCount += 1;
  388. m_pLock->m_dwOwner = GetCurrentThreadId();
  389. m_pLock->UnsignalNoWriters();
  390. break;
  391. }
  392. }
  393. }
  394. for (;;)
  395. {
  396. m_pLock->WaitOnReaders();
  397. {
  398. LockSection(&m_pLock->m_csLock, DBGT("See if we got the read lock"));
  399. if (0 == m_pLock->m_dwReadCount)
  400. break;
  401. #ifdef DBG
  402. else
  403. {
  404. DWORD dwIndex;
  405. for (dwIndex = m_pLock->m_rgdwReaders.Count(); dwIndex > 0;)
  406. {
  407. dwIndex -= 1;
  408. if (NULL != m_pLock->m_rgdwReaders[dwIndex])
  409. break;
  410. ASSERT(0 < dwIndex); // No one will ever respond!
  411. }
  412. }
  413. #endif
  414. }
  415. }
  416. }
  417. /*++
  418. DESTRUCTOR:
  419. The CLockWrite destructor frees the outstanding write lock on the
  420. CAccessLock object.
  421. Author:
  422. Doug Barlow (dbarlow) 6/2/1998
  423. --*/
  424. #undef __SUBROUTINE__
  425. #define __SUBROUTINE__ TEXT("CLockWrite::~CLockWrite")
  426. CLockWrite::~CLockWrite()
  427. {
  428. LockSection(&m_pLock->m_csLock, DBGT("Releasing the write lock"));
  429. ASSERT(0 == m_pLock->m_dwReadCount);
  430. ASSERT(0 < m_pLock->m_dwWriteCount);
  431. ASSERT(m_pLock->m_dwOwner == GetCurrentThreadId());
  432. m_pLock->m_dwWriteCount -= 1;
  433. if (0 == m_pLock->m_dwWriteCount)
  434. {
  435. m_pLock->m_dwOwner = 0;
  436. m_pLock->SignalNoWriters();
  437. }
  438. }
  439. //
  440. //==============================================================================
  441. //
  442. // Support Routines
  443. //
  444. /*++
  445. WaitForAnObject:
  446. This routine performs object waiting services. It really doesn't have
  447. anything to do with locking except that there are so many error conditions
  448. to check for that it's more convenient to have it off in its own routine.
  449. Arguments:
  450. hWaitOn supplies the handle to wait on.
  451. dwTimeout supplies the wait timeout value.
  452. Return Value:
  453. The error code, if any
  454. Throws:
  455. None
  456. Author:
  457. Doug Barlow (dbarlow) 6/19/1997
  458. --*/
  459. #undef __SUBROUTINE__
  460. #define __SUBROUTINE__ TEXT("WaitForAnObject")
  461. DWORD
  462. WaitForAnObject(
  463. HANDLE hWaitOn,
  464. DWORD dwTimeout)
  465. {
  466. DWORD dwReturn = SCARD_S_SUCCESS;
  467. DWORD dwSts;
  468. ASSERT(INVALID_HANDLE_VALUE != hWaitOn);
  469. ASSERT(NULL != hWaitOn);
  470. dwSts = WaitForSingleObject(hWaitOn, dwTimeout);
  471. switch (dwSts)
  472. {
  473. case WAIT_FAILED:
  474. dwSts = GetLastError();
  475. CalaisWarning(
  476. __SUBROUTINE__,
  477. DBGT("Wait for object failed: %1"),
  478. dwSts);
  479. dwReturn = dwSts;
  480. break;
  481. case WAIT_TIMEOUT:
  482. CalaisWarning(
  483. __SUBROUTINE__,
  484. DBGT("Wait for object timed out"));
  485. dwReturn = SCARD_F_WAITED_TOO_LONG;
  486. break;
  487. case WAIT_ABANDONED:
  488. CalaisWarning(
  489. __SUBROUTINE__,
  490. DBGT("Wait for object received wait abandoned"));
  491. // That's OK, we still got it.
  492. break;
  493. case WAIT_OBJECT_0:
  494. break;
  495. default:
  496. CalaisWarning(
  497. __SUBROUTINE__,
  498. DBGT("Wait for object got invalid response"));
  499. dwReturn = SCARD_F_INTERNAL_ERROR;
  500. }
  501. return dwReturn;
  502. }
  503. /*++
  504. WaitForObjects:
  505. This routine is a utility to allow waiting for multiple objects. It returns
  506. the index of the object that completed.
  507. Arguments:
  508. dwTimeout supplies the timeout value, in milliseconds, or INFINITE.
  509. hObject and following supply the list of objects to wait for. This list
  510. must be NULL terminated.
  511. Return Value:
  512. The number of the object completed. 1 implies the first one, 2 implies the
  513. second one, etc.
  514. Throws:
  515. Errors are thrown as DWORD status codes.
  516. Author:
  517. Doug Barlow (dbarlow) 6/17/1998
  518. --*/
  519. #undef __SUBROUTINE__
  520. #define __SUBROUTINE__ TEXT("WaitForAnyObject")
  521. DWORD
  522. WaitForAnyObject(
  523. DWORD dwTimeout,
  524. ...)
  525. {
  526. va_list ap;
  527. HANDLE h, rgh[4];
  528. DWORD dwIndex = 0, dwWait, dwErr;
  529. va_start(ap, dwTimeout);
  530. for (h = va_arg(ap, HANDLE); NULL != h; h = va_arg(ap, HANDLE))
  531. {
  532. ASSERT(dwIndex < sizeof(rgh) / sizeof(HANDLE));
  533. ASSERT(INVALID_HANDLE_VALUE != h);
  534. if (INVALID_HANDLE_VALUE != h)
  535. rgh[dwIndex++] = h;
  536. }
  537. va_end(ap);
  538. ASSERT(0 < dwIndex);
  539. if (0 < dwIndex)
  540. dwWait = WaitForMultipleObjects(dwIndex, rgh, FALSE, dwTimeout);
  541. else
  542. {
  543. dwWait = WAIT_FAILED;
  544. SetLastError(ERROR_INVALID_EVENT_COUNT);
  545. // That's a good symbolic name, but a lousy user message.
  546. }
  547. switch (dwWait)
  548. {
  549. case WAIT_FAILED:
  550. dwErr = GetLastError();
  551. CalaisWarning(
  552. __SUBROUTINE__,
  553. DBGT("WaitForObjects failed its wait: %1"),
  554. dwErr);
  555. throw dwErr;
  556. break;
  557. case WAIT_TIMEOUT:
  558. CalaisWarning(
  559. __SUBROUTINE__,
  560. DBGT("WaitForObjects timed out on its wait"));
  561. throw (DWORD)ERROR_TIMEOUT;
  562. break;
  563. default:
  564. ASSERT(WAIT_OBJECT_0 < WAIT_ABANDONED_0);
  565. if ((dwWait >= WAIT_ABANDONED_0)
  566. && (dwWait < (WAIT_ABANDONED_0 + WAIT_ABANDONED_0 - WAIT_OBJECT_0)))
  567. {
  568. CalaisWarning(
  569. __SUBROUTINE__,
  570. DBGT("WaitForObjects received a Wait Abandoned warning"));
  571. dwIndex = dwWait - WAIT_ABANDONED_0 + 1;
  572. }
  573. else if ((dwWait >= WAIT_OBJECT_0) && (dwWait < WAIT_ABANDONED_0))
  574. {
  575. dwIndex = dwWait - WAIT_OBJECT_0 + 1;
  576. }
  577. else
  578. {
  579. CalaisWarning(
  580. __SUBROUTINE__,
  581. DBGT("WaitForObjects received unknown error code: %1"),
  582. dwWait);
  583. throw dwWait;
  584. }
  585. }
  586. return dwIndex;
  587. }
  588. #ifdef DBG
  589. //
  590. // Critical Section Support.
  591. //
  592. // The following Classes aid in debugging Critical Section Conflicts.
  593. //
  594. static const TCHAR l_szUnowned[] = TEXT("<Unowned>");
  595. CDynamicArray<CCriticalSectionObject> *CCriticalSectionObject::mg_prgCSObjects = NULL;
  596. CRITICAL_SECTION CCriticalSectionObject::mg_csArrayLock;
  597. static const LPCTSTR l_rgszLockList[]
  598. = { DBGT("Service Status Critical Section"), // CSID_SERVICE_STATUS
  599. DBGT("Lock for Calais control commands."), // CSID_CONTROL_LOCK
  600. DBGT("Lock for server thread enumeration."), // CSID_SERVER_THREADS
  601. DBGT("MultiEvent Critical Access Section"), // CSID_MULTIEVENT
  602. DBGT("Mutex critical access section"), // CSID_MUTEX
  603. DBGT("Access Lock control"), // CSID_ACCESSCONTROL
  604. DBGT("Lock for tracing output."), // CSID_TRACEOUTPUT
  605. NULL };
  606. //
  607. //==============================================================================
  608. //
  609. // CCriticalSectionObject
  610. //
  611. /*++
  612. CONSTRUCTOR:
  613. This method builds the critical section object and coordinates its tracking.
  614. Arguments:
  615. szDescription supplies a description of what this critical section object
  616. is used for. This aids identification.
  617. Return Value:
  618. None
  619. Throws:
  620. None
  621. Remarks:
  622. ?Remarks?
  623. Author:
  624. Doug Barlow (dbarlow) 3/19/1999
  625. --*/
  626. #undef __SUBROUTINE__
  627. #define __SUBROUTINE__ TEXT("CCriticalSectionObject::CCriticalSectionObject")
  628. CCriticalSectionObject::CCriticalSectionObject(
  629. DWORD dwCsid)
  630. {
  631. InitializeCriticalSection(&m_csLock);
  632. m_dwCsid = dwCsid;
  633. m_bfOwner.Set((LPCBYTE)l_szUnowned, sizeof(l_szUnowned));
  634. m_bfComment.Set((LPCBYTE)DBGT(""), sizeof(TCHAR));
  635. m_dwOwnerThread = 0;
  636. m_dwRecursion = 0;
  637. if (NULL == mg_prgCSObjects)
  638. {
  639. InitializeCriticalSection(&mg_csArrayLock);
  640. CCritSect csLock(&mg_csArrayLock);
  641. mg_prgCSObjects = new CDynamicArray<CCriticalSectionObject>;
  642. ASSERT(NULL != mg_prgCSObjects);
  643. m_dwArrayEntry = 0;
  644. mg_prgCSObjects->Set(m_dwArrayEntry, this);
  645. }
  646. else
  647. {
  648. CCritSect csLock(&mg_csArrayLock);
  649. for (m_dwArrayEntry = 0;
  650. NULL != (*mg_prgCSObjects)[m_dwArrayEntry];
  651. m_dwArrayEntry += 1)
  652. ; // Empty loop body
  653. mg_prgCSObjects->Set(m_dwArrayEntry, this);
  654. }
  655. }
  656. /*++
  657. DESTRUCTOR:
  658. This method cleans up the critical section object.
  659. Arguments:
  660. None
  661. Return Value:
  662. None
  663. Throws:
  664. None
  665. Remarks:
  666. ?Remarks?
  667. Author:
  668. Doug Barlow (dbarlow) 3/19/1999
  669. --*/
  670. #undef __SUBROUTINE__
  671. #define __SUBROUTINE__ TEXT("CCriticalSectionObject::~CCriticalSectionObject")
  672. CCriticalSectionObject::~CCriticalSectionObject()
  673. {
  674. if (0 == m_dwOwnerThread)
  675. {
  676. ASSERT(0 == m_dwRecursion);
  677. }
  678. else
  679. {
  680. ASSERT(IsOwnedByMe());
  681. ASSERT(1 == m_dwRecursion);
  682. LeaveCriticalSection(&m_csLock);
  683. }
  684. {
  685. CCritSect csLock(&mg_csArrayLock);
  686. ASSERT(this == (*mg_prgCSObjects)[m_dwArrayEntry]);
  687. mg_prgCSObjects->Set(m_dwArrayEntry, NULL);
  688. }
  689. DeleteCriticalSection(&m_csLock);
  690. }
  691. /*++
  692. Enter:
  693. This method enters a critical section, and tracks the owner.
  694. Arguments:
  695. szOwner supplies the name of the calling subroutine.
  696. szComment supplies an additional comment to help distinguish between
  697. multiple calls within a subroutine.
  698. Return Value:
  699. None
  700. Throws:
  701. None
  702. Remarks:
  703. ?Remarks?
  704. Author:
  705. Doug Barlow (dbarlow) 3/19/1999
  706. --*/
  707. #undef __SUBROUTINE__
  708. #define __SUBROUTINE__ TEXT("CCriticalSectionObject::Enter")
  709. void
  710. CCriticalSectionObject::Enter(
  711. LPCTSTR szOwner,
  712. LPCTSTR szComment)
  713. {
  714. {
  715. CCritSect csLock(&mg_csArrayLock);
  716. CCriticalSectionObject *pCs;
  717. for (DWORD dwI = mg_prgCSObjects->Count(); 0 < dwI;)
  718. {
  719. pCs = (*mg_prgCSObjects)[--dwI];
  720. if (m_dwArrayEntry == dwI)
  721. {
  722. ASSERT(this == pCs);
  723. continue;
  724. }
  725. if (NULL != pCs)
  726. {
  727. if (pCs->IsOwnedByMe()
  728. && (m_dwCsid <= pCs->m_dwCsid))
  729. {
  730. CalaisError(
  731. __SUBROUTINE__,
  732. DBGT("Potential Critical Section deadlock: Owner of %1 attempting to access %2"),
  733. pCs->Description(),
  734. Description());
  735. }
  736. }
  737. }
  738. }
  739. EnterCriticalSection(&m_csLock);
  740. if (0 == m_dwRecursion)
  741. {
  742. ASSERT(0 == m_dwOwnerThread);
  743. m_dwOwnerThread = GetCurrentThreadId();
  744. m_bfOwner.Set(
  745. (LPCBYTE)szOwner,
  746. (lstrlen(szOwner) + 1) * sizeof(TCHAR));
  747. m_bfComment.Set(
  748. (LPCBYTE)szComment,
  749. (lstrlen(szComment) + 1) * sizeof(TCHAR));
  750. }
  751. else
  752. {
  753. ASSERT(GetCurrentThreadId() == m_dwOwnerThread);
  754. CalaisDebug((
  755. DBGT("Critical Section '%s' already owned by %s (%s)\nCalled from %s (%s)\n"),
  756. Description(),
  757. Owner(),
  758. Comment(),
  759. szOwner,
  760. szComment));
  761. }
  762. m_dwRecursion += 1;
  763. ASSERT(0 < m_dwRecursion);
  764. }
  765. /*++
  766. Leave:
  767. This method exits a critical section.
  768. Arguments:
  769. None
  770. Return Value:
  771. None
  772. Throws:
  773. None
  774. Remarks:
  775. ?Remarks?
  776. Author:
  777. Doug Barlow (dbarlow) 3/19/1999
  778. --*/
  779. #undef __SUBROUTINE__
  780. #define __SUBROUTINE__ TEXT("CCriticalSectionObject::Leave")
  781. void
  782. CCriticalSectionObject::Leave(
  783. void)
  784. {
  785. ASSERT(0 < m_dwRecursion);
  786. m_dwRecursion -= 1;
  787. if (0 == m_dwRecursion)
  788. {
  789. m_bfOwner.Set((LPCBYTE)l_szUnowned, sizeof(l_szUnowned));
  790. m_bfComment.Set((LPCBYTE)DBGT(""), sizeof(TCHAR));
  791. m_dwOwnerThread = 0;
  792. }
  793. LeaveCriticalSection(&m_csLock);
  794. }
  795. /*++
  796. Description:
  797. Translate the Critical Section Id number to a descriptive string.
  798. Arguments:
  799. None
  800. Return Value:
  801. The descriptive string corresponding to this critical section type.
  802. Throws:
  803. None
  804. Remarks:
  805. ?Remarks?
  806. Author:
  807. Doug Barlow (dbarlow) 3/22/1999
  808. --*/
  809. #undef __SUBROUTINE__
  810. #define __SUBROUTINE__ TEXT("CCriticalSectionObject::Description")
  811. LPCTSTR
  812. CCriticalSectionObject::Description(
  813. void)
  814. const
  815. {
  816. return l_rgszLockList[m_dwCsid];
  817. }
  818. #endif