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.

628 lines
18 KiB

  1. //-----------------------------------------------------------------------------
  2. //
  3. //
  4. // File: rwinst.cpp
  5. //
  6. // Description: Implementation of CShareLockInst library functions
  7. //
  8. // Author: Mike Swafford (MikeSwa)
  9. //
  10. // History:
  11. // 5/24/99 - MikeSwa Created
  12. // 8/6/99 - MikeSwa created phatq version
  13. //
  14. // Copyright (C) 1999 Microsoft Corporation
  15. //
  16. //-----------------------------------------------------------------------------
  17. #include <windows.h>
  18. #include <rwinst.h>
  19. #include <stdlib.h>
  20. #include <dbgtrace.h>
  21. //Static initialization
  22. LIST_ENTRY CShareLockInst::s_liLocks;
  23. volatile DWORD CShareLockInst::s_dwLock = 0;
  24. DWORD CShareLockInst::s_cLockSpins = 0;
  25. DWORD CShareLockInst::s_dwSignature = SHARE_LOCK_INST_SIG_FREE;
  26. //---[ CThreadIdBlock::cIncThreadCount ]---------------------------------------
  27. //
  28. //
  29. // Description:
  30. // Increments the thread count for a given thread ID
  31. // Parameters:
  32. // dwThreadId Thread to increment the thread count for
  33. // Returns:
  34. // New count value
  35. // History:
  36. // 8/9/99 - MikeSwa Created
  37. //
  38. //-----------------------------------------------------------------------------
  39. DWORD CThreadIdBlock::cIncThreadCount(DWORD dwThreadId)
  40. {
  41. _ASSERT(THREAD_ID_BLOCK_UNUSED != dwThreadId);
  42. CThreadIdBlock *ptblkCurrent = this;
  43. CThreadIdBlock *ptblkOld = NULL;
  44. CThreadIdBlock *ptblkNew = NULL;
  45. while (ptblkCurrent)
  46. {
  47. _ASSERT(THREAD_ID_BLOCK_SIG == ptblkCurrent->m_dwSignature);
  48. if (dwThreadId == ptblkCurrent->m_dwThreadId)
  49. return InterlockedIncrement((PLONG) &(ptblkCurrent->m_cThreadRecursionCount));
  50. ptblkOld = ptblkCurrent;
  51. ptblkCurrent = ptblkCurrent->m_ptblkNext;
  52. }
  53. _ASSERT(ptblkOld); //we should hit loop at least once
  54. //See if the current block has a thread ID associated with it
  55. if (THREAD_ID_BLOCK_UNUSED == ptblkOld->m_dwThreadId)
  56. {
  57. //This is actually the head block... use it to avoid an extra alloc
  58. if (THREAD_ID_BLOCK_UNUSED == InterlockedCompareExchange(
  59. (PLONG) &ptblkOld->m_dwThreadId,
  60. dwThreadId, THREAD_ID_BLOCK_UNUSED))
  61. {
  62. _ASSERT(dwThreadId == ptblkOld->m_dwThreadId);
  63. //Now this thread block is the current one
  64. return InterlockedIncrement((PLONG) &ptblkOld->m_cThreadRecursionCount);
  65. }
  66. }
  67. //We did not find it... we must create a new CThreadIdBlock
  68. ptblkNew = new CThreadIdBlock();
  69. //if we fail to alloc 32 bytes... I should see if we have spun out of
  70. //control
  71. _ASSERT(ptblkNew);
  72. if (!ptblkNew)
  73. return 1; //Fake success for our callers
  74. ptblkNew->m_dwThreadId = dwThreadId;
  75. ptblkNew->m_cThreadRecursionCount = 1;
  76. ptblkCurrent = (CThreadIdBlock *) InterlockedCompareExchangePointer(
  77. (PVOID *) &ptblkOld->m_ptblkNext,
  78. (PVOID) ptblkNew,
  79. NULL);
  80. //If it is non-NULL, then our insert failed
  81. if (ptblkCurrent)
  82. {
  83. _ASSERT(ptblkCurrent != ptblkNew);
  84. //Whoops... another thread has added a block... time to try again
  85. //This time, start search from the block the just appeared
  86. delete ptblkNew;
  87. return ptblkCurrent->cIncThreadCount(dwThreadId);
  88. }
  89. //We inserted the block... inital count was 1
  90. return 1;
  91. }
  92. //---[ CThreadIdBlock::cDecThreadCount ]---------------------------------------
  93. //
  94. //
  95. // Description:
  96. // Decrements the thread count for a given thread ID
  97. // Parameters:
  98. // dwThreadId
  99. // Returns:
  100. // The resulting count
  101. // History:
  102. // 8/9/99 - MikeSwa Created
  103. //
  104. //-----------------------------------------------------------------------------
  105. DWORD CThreadIdBlock::cDecThreadCount(DWORD dwThreadId)
  106. {
  107. _ASSERT(THREAD_ID_BLOCK_UNUSED != dwThreadId);
  108. CThreadIdBlock *ptblkCurrent = this;
  109. while (ptblkCurrent)
  110. {
  111. _ASSERT(THREAD_ID_BLOCK_SIG == ptblkCurrent->m_dwSignature);
  112. if (dwThreadId == ptblkCurrent->m_dwThreadId)
  113. return InterlockedDecrement((PLONG) &(ptblkCurrent->m_cThreadRecursionCount));
  114. ptblkCurrent = ptblkCurrent->m_ptblkNext;
  115. }
  116. //We didn't find it... we would have asserted on insertion
  117. //Don't assert twice
  118. //$$TODO - Add global counts of these failures
  119. return 0;
  120. }
  121. //---[ CThreadIdBlock::cMatchesId ]--------------------------------------------
  122. //
  123. //
  124. // Description:
  125. // Checks if this thread block (or one in this thread blocks chain)
  126. // matches the given thread id. Returns the count for this thread
  127. // Parameters:
  128. // dwThreadId - Thread Id to search for
  129. // Returns:
  130. // Thread count if the thread ID is found
  131. // 0 if not found (or count is 0)
  132. // History:
  133. // 8/9/99 - MikeSwa Created
  134. //
  135. //-----------------------------------------------------------------------------
  136. DWORD CThreadIdBlock::cMatchesId(DWORD dwThreadId)
  137. {
  138. CThreadIdBlock *ptblk = this;
  139. while (ptblk)
  140. {
  141. _ASSERT(THREAD_ID_BLOCK_SIG == ptblk->m_dwSignature);
  142. if (ptblk->m_dwThreadId == dwThreadId)
  143. return ptblk->m_cThreadRecursionCount;
  144. ptblk = ptblk->m_ptblkNext;
  145. }
  146. return 0;
  147. }
  148. //---[ CShareLockInst::AcquireStaticSpinLock ]---------------------------------
  149. //
  150. //
  151. // Description:
  152. // Acquires static spin lock... from aqueue\cat\ldapstor
  153. // Parameters:
  154. // -
  155. // Returns:
  156. // -
  157. // History:
  158. // 5/21/99 - MikeSwa Adapted from JStamerJ's code
  159. //
  160. //-----------------------------------------------------------------------------
  161. void CShareLockInst::AcquireStaticSpinLock()
  162. {
  163. do {
  164. //
  165. // Spin while the lock is unavailable
  166. //
  167. while (s_dwLock > 0)
  168. {
  169. Sleep(0);
  170. InterlockedIncrement((PLONG) &s_cLockSpins);
  171. }
  172. //
  173. // Lock just became available, try to grab it
  174. //
  175. } while ( InterlockedIncrement((PLONG) &s_dwLock) != 1 );
  176. //We have the lock... make sure that s_liLocks has been initialized
  177. if (s_dwSignature != SHARE_LOCK_INST_SIG)
  178. {
  179. InitializeListHead(&s_liLocks);
  180. s_dwSignature = SHARE_LOCK_INST_SIG;
  181. }
  182. }
  183. //---[ CShareLockInst::ReleaseStaticSpinLock ]---------------------------------
  184. //
  185. //
  186. // Description:
  187. // Releases previously acquired spinlock
  188. // Parameters:
  189. // -
  190. // Returns:
  191. // -
  192. // History:
  193. // 5/21/99 - MikeSwa Adapted from JStamerJ's code
  194. //
  195. //-----------------------------------------------------------------------------
  196. void CShareLockInst::ReleaseStaticSpinLock()
  197. {
  198. _ASSERT(SHARE_LOCK_INST_SIG == s_dwSignature); //static init was done
  199. _ASSERT(s_dwLock > 0);
  200. InterlockedExchange((PLONG) &s_dwLock, 0 );
  201. }
  202. //---[ CShareLockInst::CShareLockInst ]----------------------------------------
  203. //
  204. //
  205. // Description:
  206. // Constructor for CShareLockInst
  207. // Parameters:
  208. // szDescription Constant string passed in to describe lock
  209. // dwFlags Flags describing what to track
  210. // cMaxTrackedSharedThreadIDs Maximum # of threads to track
  211. // Returns:
  212. // -
  213. // History:
  214. // 5/21/99 - MikeSwa Created
  215. //
  216. //-----------------------------------------------------------------------------
  217. CShareLockInst::CShareLockInst(LPCSTR szDescription,
  218. DWORD dwFlags, DWORD cMaxTrackedSharedThreadIDs)
  219. {
  220. DWORD cbArray = sizeof(DWORD) * cMaxTrackedSharedThreadIDs;
  221. m_dwSignature = SHARE_LOCK_INST_SIG;
  222. m_dwFlags = dwFlags;
  223. m_liLocks.Flink = NULL;
  224. m_liLocks.Blink = NULL;
  225. m_cShareAttempts = 0;
  226. m_cShareAttemptsBlocked = 0;
  227. m_cExclusiveAttempts = 0;
  228. m_cExclusiveAttemptsBlocked = 0;
  229. m_szDescription = szDescription;
  230. m_rgtblkSharedThreadIDs = NULL;
  231. m_dwExclusiveThread = NULL;
  232. m_cCurrentSharedThreads = 0;
  233. m_cMaxConcurrentSharedThreads = 0;
  234. m_cMaxTrackedSharedThreadIDs = cMaxTrackedSharedThreadIDs;
  235. if (SHARE_LOCK_INST_TRACK_NOTHING & m_dwFlags)
  236. m_dwFlags = 0;
  237. //Allocate memory to store thread IDs
  238. if (fTrackSharedThreads())
  239. {
  240. _ASSERT(cbArray);
  241. m_rgtblkSharedThreadIDs = new CThreadIdBlock[m_cMaxTrackedSharedThreadIDs];
  242. if (!m_rgtblkSharedThreadIDs)
  243. m_cMaxTrackedSharedThreadIDs = 0;
  244. }
  245. //Insert in list if we are tracking
  246. if (fTrackInGlobalList())
  247. {
  248. AcquireStaticSpinLock();
  249. InsertHeadList(&s_liLocks, &m_liLocks);
  250. ReleaseStaticSpinLock();
  251. }
  252. };
  253. //---[ CShareLockinst::~CShareLockinst ]---------------------------------------
  254. //
  255. //
  256. // Description:
  257. // CShareLockInst desctructor. Will remove this lock from the
  258. // Parameters:
  259. // -
  260. // Returns:
  261. // -
  262. // History:
  263. // 5/21/99 - MikeSwa Created
  264. //
  265. //-----------------------------------------------------------------------------
  266. CShareLockInst::~CShareLockInst()
  267. {
  268. m_dwSignature = SHARE_LOCK_INST_SIG_FREE;
  269. if (m_rgtblkSharedThreadIDs)
  270. {
  271. delete [] m_rgtblkSharedThreadIDs;
  272. m_rgtblkSharedThreadIDs = NULL;
  273. }
  274. if (fTrackInGlobalList())
  275. {
  276. AcquireStaticSpinLock();
  277. RemoveEntryList(&m_liLocks);
  278. ReleaseStaticSpinLock();
  279. }
  280. };
  281. //---[ CShareLockInst::LogAcquireShareLock ]-----------------------------------
  282. //
  283. //
  284. // Description:
  285. // Does all the work of logging the appropriate information when a thread
  286. // acquires the lock shared.
  287. // - Updates max concurrent shared threads
  288. // - Updates current shared threads
  289. // - Updates lists of shared thread IDs
  290. // - Asserts when shared deadlocks are detected
  291. // Parameters:
  292. // BOOL fTry - TRUE if this is for a try enter (deadlock cannot happen)
  293. // Returns:
  294. // -
  295. // History:
  296. // 5/21/99 - MikeSwa Created
  297. //
  298. //-----------------------------------------------------------------------------
  299. void CShareLockInst::LogAcquireShareLock(BOOL fTry)
  300. {
  301. if (fTrackSharedThreads())
  302. {
  303. DWORD cCurrentSharedThreads = 0;
  304. DWORD cMaxConcurrentSharedThreads = 0;
  305. DWORD dwThreadID = GetCurrentThreadId();
  306. DWORD dwThreadCount = 0;
  307. DWORD dwThreadHash = 0;
  308. _ASSERT(dwThreadID); //Our algorithm requires this to be non-zero
  309. cCurrentSharedThreads = InterlockedIncrement((PLONG) &m_cCurrentSharedThreads);
  310. //Update max concurrent threads if we have set a new record
  311. cMaxConcurrentSharedThreads = m_cMaxConcurrentSharedThreads;
  312. while (cCurrentSharedThreads > cMaxConcurrentSharedThreads)
  313. {
  314. InterlockedCompareExchange((PLONG) &m_cMaxConcurrentSharedThreads,
  315. (LONG) cCurrentSharedThreads,
  316. (LONG) cMaxConcurrentSharedThreads);
  317. cMaxConcurrentSharedThreads = m_cMaxConcurrentSharedThreads;
  318. }
  319. //if we have a place to store our thread ID...save it
  320. if (m_rgtblkSharedThreadIDs)
  321. {
  322. dwThreadHash = dwHashThreadId(dwThreadID,
  323. m_cMaxTrackedSharedThreadIDs);
  324. _ASSERT(dwThreadHash < m_cMaxTrackedSharedThreadIDs);
  325. dwThreadCount = m_rgtblkSharedThreadIDs[dwThreadHash].cIncThreadCount(dwThreadID);
  326. if (!fTry && (dwThreadCount > 1))
  327. {
  328. //This thread already holds this lock... this is a
  329. //potential deadlock situation
  330. if (fAssertSharedDeadlocks())
  331. {
  332. _ASSERT(0 && "Found potential share deadlock");
  333. }
  334. }
  335. }
  336. }
  337. }
  338. //---[ CShareLockInst::LogReleaseShareLock ]-----------------------------------
  339. //
  340. //
  341. // Description:
  342. // Called when a sharelock is released to cleanup the information stored
  343. // in LogAcquireShareLock.
  344. // Parameters:
  345. // -
  346. // Returns:
  347. // -
  348. // History:
  349. // 5/21/99 - MikeSwa Created
  350. //
  351. //-----------------------------------------------------------------------------
  352. void CShareLockInst::LogReleaseShareLock()
  353. {
  354. if (fTrackSharedThreads())
  355. {
  356. DWORD dwThreadID = GetCurrentThreadId();
  357. DWORD dwThreadHash = 0;
  358. _ASSERT(dwThreadID); //Our algorithm requires this to be non-zero
  359. //Search through list of thread IDs for
  360. if (m_rgtblkSharedThreadIDs)
  361. {
  362. dwThreadHash = dwHashThreadId(dwThreadID,
  363. m_cMaxTrackedSharedThreadIDs);
  364. _ASSERT(dwThreadHash < m_cMaxTrackedSharedThreadIDs);
  365. m_rgtblkSharedThreadIDs[dwThreadHash].cDecThreadCount(dwThreadID);
  366. }
  367. }
  368. }
  369. //---[ CShareLockInst::ShareLock ]---------------------------------------------
  370. //
  371. //
  372. // Description:
  373. // Implements sharelock wrapper
  374. // Parameters:
  375. //
  376. // Returns:
  377. //
  378. // History:
  379. // 5/21/99 - MikeSwa Created
  380. //
  381. //-----------------------------------------------------------------------------
  382. void CShareLockInst::PrvShareLock()
  383. {
  384. LogAcquireShareLock(FALSE);
  385. //If we are tracking contention, then we will try to enter the sharelock
  386. //and increment the contention count if that fails.
  387. if (fTrackContention())
  388. {
  389. InterlockedIncrement((PLONG) &m_cShareAttempts);
  390. if (!CShareLockInstBase::TryShareLock())
  391. {
  392. InterlockedIncrement((PLONG) &m_cShareAttemptsBlocked);
  393. CShareLockInstBase::ShareLock();
  394. }
  395. }
  396. else
  397. {
  398. CShareLockInstBase::ShareLock();
  399. }
  400. };
  401. //---[ CShareLockInst::ShareUnlock ]-------------------------------------------
  402. //
  403. //
  404. // Description:
  405. // Wrapper for ShareUnlock
  406. // Parameters:
  407. //
  408. // Returns:
  409. //
  410. // History:
  411. // 5/21/99 - MikeSwa Created
  412. //
  413. //-----------------------------------------------------------------------------
  414. void CShareLockInst::PrvShareUnlock()
  415. {
  416. LogReleaseShareLock();
  417. CShareLockInstBase::ShareUnlock();
  418. };
  419. //---[ CShareLockInst::TryShareLock ]------------------------------------------
  420. //
  421. //
  422. // Description:
  423. // Implements TryShareLock wrapper.
  424. // Parameters:
  425. //
  426. // Returns:
  427. // TRUE if the lock was acquired.
  428. // History:
  429. // 5/21/99 - MikeSwa Created
  430. //
  431. //-----------------------------------------------------------------------------
  432. BOOL CShareLockInst::PrvTryShareLock()
  433. {
  434. BOOL fLocked = FALSE;
  435. fLocked = CShareLockInstBase::TryShareLock();
  436. if (fLocked)
  437. LogAcquireShareLock(TRUE);
  438. return fLocked;
  439. };
  440. //---[ CShareLockInst::ExclusiveLock ]-----------------------------------------
  441. //
  442. //
  443. // Description:
  444. // Implements ExclusiveLock wrapper
  445. // Parameters:
  446. //
  447. // Returns:
  448. //
  449. // History:
  450. // 5/21/99 - MikeSwa Created
  451. //
  452. //-----------------------------------------------------------------------------
  453. void CShareLockInst::PrvExclusiveLock()
  454. {
  455. //If we are tracking contention, then we will try to enter the lock
  456. //and increment the contention count if that fails.
  457. if (fTrackContention())
  458. {
  459. InterlockedIncrement((PLONG) &m_cExclusiveAttempts);
  460. if (!CShareLockInstBase::TryExclusiveLock())
  461. {
  462. InterlockedIncrement((PLONG) &m_cExclusiveAttemptsBlocked);
  463. CShareLockInstBase::ExclusiveLock();
  464. }
  465. }
  466. else
  467. {
  468. CShareLockInstBase::ExclusiveLock();
  469. }
  470. if (fTrackExclusiveThreads())
  471. {
  472. //This should be the only thread accessing this now
  473. _ASSERT(!m_dwExclusiveThread);
  474. m_dwExclusiveThread = GetCurrentThreadId();
  475. }
  476. };
  477. //---[ CShareLockInst::ExclusiveUnlock ]---------------------------------------
  478. //
  479. //
  480. // Description:
  481. // Wrapper for ExclusiveUnlock
  482. // Parameters:
  483. // -
  484. // Returns:
  485. // -
  486. // History:
  487. // 5/21/99 - MikeSwa Created
  488. //
  489. //-----------------------------------------------------------------------------
  490. void CShareLockInst::PrvExclusiveUnlock()
  491. {
  492. if (fTrackExclusiveThreads())
  493. {
  494. _ASSERT(GetCurrentThreadId() == m_dwExclusiveThread);
  495. m_dwExclusiveThread = 0;
  496. }
  497. CShareLockInstBase::ExclusiveUnlock();
  498. };
  499. //---[ CShareLockInst::TryExclusiveLock ]--------------------------------------
  500. //
  501. //
  502. // Description:
  503. // Implements TryExclusiveLock wrapper.
  504. // Parameters:
  505. //
  506. // Returns:
  507. // TRUE if the lock was acquired.
  508. // History:
  509. // 5/21/99 - MikeSwa Created
  510. //
  511. //-----------------------------------------------------------------------------
  512. BOOL CShareLockInst::PrvTryExclusiveLock()
  513. {
  514. BOOL fLocked = FALSE;
  515. fLocked = CShareLockInstBase::TryExclusiveLock();
  516. if (fLocked && fTrackExclusiveThreads())
  517. {
  518. //This should be the only thread accessing this now
  519. _ASSERT(!m_dwExclusiveThread);
  520. m_dwExclusiveThread = GetCurrentThreadId();
  521. }
  522. return fLocked;
  523. };
  524. //---[ CShareLockInst::PrvAssertIsLocked ]-------------------------------------
  525. //
  526. //
  527. // Description:
  528. // Asserts if this threads ID is not recorded as one that acquired this
  529. // lock.
  530. // Parameters:
  531. // -
  532. // Returns:
  533. // -
  534. // History:
  535. // 5/24/99 - MikeSwa Created
  536. //
  537. //-----------------------------------------------------------------------------
  538. void CShareLockInst::PrvAssertIsLocked()
  539. {
  540. DWORD dwThreadID = GetCurrentThreadId();
  541. DWORD dwThreadHash = 0;
  542. BOOL fFoundThreadID = FALSE;
  543. _ASSERT(dwThreadID); //Our algorithm requires this to be non-zero
  544. //Bail out if we are not configured to track this things.
  545. if (!fTrackSharedThreads() || !fTrackExclusiveThreads() || !m_rgtblkSharedThreadIDs)
  546. return;
  547. if (dwThreadID == m_dwExclusiveThread)
  548. {
  549. fFoundThreadID = TRUE;
  550. }
  551. else
  552. {
  553. dwThreadHash = dwHashThreadId(dwThreadID,
  554. m_cMaxTrackedSharedThreadIDs);
  555. _ASSERT(dwThreadHash < m_cMaxTrackedSharedThreadIDs);
  556. fFoundThreadID = (0 < m_rgtblkSharedThreadIDs[dwThreadHash].cMatchesId(dwThreadID));
  557. }
  558. if (!fFoundThreadID)
  559. _ASSERT(0 && "Lock is not held by this thread!!!");
  560. }