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.

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