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.

362 lines
11 KiB

  1. //-----------------------------------------------------------------------------
  2. //
  3. //
  4. // File: rwinst.h
  5. //
  6. // Description: Instramented share lock implementations. Our current
  7. // sharelock implementation is non-reentrant. This wrapper can also
  8. // be used to check for possible deadlocks.
  9. //
  10. // Author: Mike Swafford (MikeSwa)
  11. //
  12. // History:
  13. // 5/10/99 - MikeSwa Created
  14. // 8/6/99 - MikeSwa created phatq version
  15. // 11/6/99 - MikeSwa updated to use CShareLockNH
  16. //
  17. // Copyright (C) 1999 Microsoft Corporation
  18. //
  19. //-----------------------------------------------------------------------------
  20. #ifndef __PTRWINST_H__
  21. #define __PTRWINST_H__
  22. #include "rwnew.h"
  23. #include "listmacr.h"
  24. #define SHARE_LOCK_INST_SIG 'kcoL'
  25. #define SHARE_LOCK_INST_SIG_FREE '!koL'
  26. #define THREAD_ID_BLOCK_SIG 'klBT'
  27. #define THREAD_ID_BLOCK_SIG_FREE '!lBT'
  28. #define THREAD_ID_BLOCK_UNUSED 0xFFFFFFFF
  29. //Flag values that describe the type of tracking to do
  30. //These can be passed to the constructor to allow different levels of
  31. //tracking for different instances.
  32. enum
  33. {
  34. SHARE_LOCK_INST_TRACK_CONTENTION = 0x00000001,
  35. SHARE_LOCK_INST_TRACK_SHARED_THREADS = 0x00000002,
  36. SHARE_LOCK_INST_TRACK_EXCLUSIVE_THREADS = 0x00000004,
  37. SHARE_LOCK_INST_ASSERT_SHARED_DEADLOCKS = 0x00000008,
  38. SHARE_LOCK_INST_TRACK_IN_GLOBAL_LIST = 0x00000010,
  39. SHARE_LOCK_INST_TRACK_NOTHING = 0x80000000,
  40. };
  41. //Define some useful flag combinations
  42. //This combination of flags has minimal perf impact, but does
  43. //allow easier exclusive deadlock detection
  44. #define SHARE_LOCK_INST_TRACK_MINIMALS ( \
  45. SHARE_LOCK_INST_TRACK_EXCLUSIVE_THREADS | \
  46. SHARE_LOCK_INST_TRACK_SHARED_THREADS | \
  47. SHARE_LOCK_INST_TRACK_IN_GLOBAL_LIST )
  48. //This combination of flags uses all of the tracking functionality of
  49. //this class.
  50. #define SHARE_LOCK_INST_TRACK_ALL (\
  51. SHARE_LOCK_INST_TRACK_CONTENTION | \
  52. SHARE_LOCK_INST_TRACK_SHARED_THREADS | \
  53. SHARE_LOCK_INST_TRACK_EXCLUSIVE_THREADS | \
  54. SHARE_LOCK_INST_ASSERT_SHARED_DEADLOCKS | \
  55. SHARE_LOCK_INST_TRACK_IN_GLOBAL_LIST )
  56. //A user can define their own defaults before including this file
  57. //$$TODO - scale back the defaults for debug builds
  58. #ifndef SHARE_LOCK_INST_TRACK_DEFAULTS
  59. #ifdef DEBUG
  60. #define SHARE_LOCK_INST_TRACK_DEFAULTS SHARE_LOCK_INST_TRACK_ALL
  61. #else //not DEBUG
  62. #define SHARE_LOCK_INST_TRACK_DEFAULTS SHARE_LOCK_INST_TRACK_MINIMALS
  63. #endif //not DEBUG
  64. #endif //SHARE_LOCK_INST_TRACK_DEFAULTS
  65. #ifndef SHARE_LOCK_INST_DEFAULT_MAX_THREADS
  66. #define SHARE_LOCK_INST_DEFAULT_MAX_THREADS 200
  67. #endif //SHARE_LOCK_INST_DEFAULT_MAX_THREADS
  68. //---[ CThreadIdBlock ]--------------------------------------------------------
  69. //
  70. //
  71. // Description:
  72. // An structure that represents a thread and the required info to
  73. // hash it.
  74. // Hungarian:
  75. // tblk, ptblk
  76. //
  77. //-----------------------------------------------------------------------------
  78. class CThreadIdBlock
  79. {
  80. protected:
  81. DWORD m_dwSignature;
  82. DWORD m_dwThreadId;
  83. DWORD m_cThreadRecursionCount;
  84. CThreadIdBlock *m_ptblkNext;
  85. public:
  86. CThreadIdBlock()
  87. {
  88. m_dwSignature = THREAD_ID_BLOCK_SIG;
  89. m_dwThreadId = THREAD_ID_BLOCK_UNUSED;
  90. m_cThreadRecursionCount = 0;
  91. m_ptblkNext = NULL;
  92. };
  93. ~CThreadIdBlock()
  94. {
  95. m_dwSignature = THREAD_ID_BLOCK_SIG_FREE;
  96. if (m_ptblkNext)
  97. delete m_ptblkNext;
  98. m_ptblkNext = NULL;
  99. };
  100. DWORD cIncThreadCount(DWORD dwThreadId);
  101. DWORD cDecThreadCount(DWORD dwThreadId);
  102. DWORD cMatchesId(DWORD dwThreadId);
  103. };
  104. //---[ dwHashThreadId ]--------------------------------------------------------
  105. //
  106. //
  107. // Description:
  108. // Given a thread ID (return by GetCurrentThreadId()) it returns a hashed
  109. // index. This is designed to be used in conjuction with a array (of
  110. // size dwMax) of CThreadIdBlock's. Each CThreadIdBlock will implement
  111. // linear chaining. A hash lookup can be implemented by somehthing as
  112. // simple as:
  113. // rgtblk[dwhashThreadId(GetCurrentThreadId()),
  114. // sizeof(rgtblk)].cIncThreadCount();
  115. // Parameters:
  116. // dwThreadId Thread Id to hash
  117. // dwMax Max hash value (actual max value +1)
  118. // Returns:
  119. // Hashed thread Id
  120. // History:
  121. // 8/9/99 - MikeSwa Created
  122. //
  123. //-----------------------------------------------------------------------------
  124. inline DWORD dwHashThreadId(DWORD dwThreadId, DWORD dwMax)
  125. {
  126. //Typically IDs are between 0x100 and 0xFFF
  127. //Also, the handles are multiples of 4 (ie end in 0, 4, 8, or C)
  128. //For these conditions, this hash will give unique results for
  129. //dwMax of 1000. (0xFFF-0x100)/4 < 1000
  130. const DWORD dwMinExpectedThread = 0x100;
  131. DWORD dwHash = dwThreadId;
  132. dwHash -= dwMinExpectedThread;
  133. dwHash >>= 2;
  134. dwHash %= dwMax;
  135. return dwHash;
  136. };
  137. typedef CShareLockNH CShareLockInstBase;
  138. //---[ CShareLockInst ]--------------------------------------------------------
  139. //
  140. //
  141. // Description:
  142. // An intstramented version of CShareLockInstBase
  143. // Hungarian:
  144. // sli, psli
  145. //
  146. //-----------------------------------------------------------------------------
  147. class CShareLockInst : public CShareLockInstBase
  148. {
  149. protected:
  150. //Static lock-tracking variables
  151. static LIST_ENTRY s_liLocks;
  152. static volatile DWORD s_dwLock;
  153. static DWORD s_cLockSpins;
  154. static DWORD s_dwSignature;
  155. static inline void AcquireStaticSpinLock();
  156. static inline void ReleaseStaticSpinLock();
  157. protected:
  158. DWORD m_dwSignature;
  159. //Flags describing types of tracking to be performed
  160. DWORD m_dwFlags;
  161. //List entry for list of all locks - used by a debugger extension
  162. LIST_ENTRY m_liLocks;
  163. //The total number of attempts to enter this lock in a shared mode
  164. DWORD m_cShareAttempts;
  165. //The total number of attempts to enter shared that blocked
  166. DWORD m_cShareAttemptsBlocked;
  167. //The total number ot attempts to enter this lock exclusively
  168. DWORD m_cExclusiveAttempts;
  169. //The total number ot attempts to enter this lock exclusively that blocked
  170. DWORD m_cExclusiveAttemptsBlocked;
  171. //Constant string descrition passed in
  172. LPCSTR m_szDescription;
  173. //ID of the thread that holds this lock exclusively
  174. DWORD m_dwExclusiveThread;
  175. //Array of thread IDs that hold this lock shared
  176. CThreadIdBlock *m_rgtblkSharedThreadIDs;
  177. //Maximum number of shared threads that can be tracked
  178. DWORD m_cMaxTrackedSharedThreadIDs;
  179. //The current number of shared threads
  180. DWORD m_cCurrentSharedThreads;
  181. //The most theads that have ever held this lock shared
  182. DWORD m_cMaxConcurrentSharedThreads;
  183. //Used internally, to see if the private functions need to be called
  184. inline BOOL fTrackingEnabled();
  185. BOOL fTrackContention()
  186. {return (SHARE_LOCK_INST_TRACK_CONTENTION & m_dwFlags);};
  187. BOOL fTrackSharedThreads()
  188. {return (m_cMaxTrackedSharedThreadIDs &&
  189. (SHARE_LOCK_INST_TRACK_SHARED_THREADS & m_dwFlags));};
  190. BOOL fTrackExclusiveThreads()
  191. {return (SHARE_LOCK_INST_TRACK_EXCLUSIVE_THREADS & m_dwFlags);};
  192. BOOL fAssertSharedDeadlocks()
  193. {return (fTrackSharedThreads() &&
  194. (SHARE_LOCK_INST_ASSERT_SHARED_DEADLOCKS & m_dwFlags));};
  195. BOOL fTrackInGlobalList()
  196. {return (SHARE_LOCK_INST_TRACK_IN_GLOBAL_LIST & m_dwFlags);};
  197. //statisics helper functions
  198. void LogAcquireShareLock(BOOL fTry);
  199. void LogReleaseShareLock();
  200. void PrvShareLock();
  201. void PrvShareUnlock();
  202. BOOL PrvTryShareLock();
  203. void PrvExclusiveLock();
  204. void PrvExclusiveUnlock();
  205. BOOL PrvTryExclusiveLock();
  206. void PrvAssertIsLocked();
  207. public:
  208. CShareLockInst(
  209. LPCSTR szDescription = NULL,
  210. DWORD dwFlags = SHARE_LOCK_INST_TRACK_DEFAULTS,
  211. DWORD cMaxTrackedSharedThreadIDs = SHARE_LOCK_INST_DEFAULT_MAX_THREADS);
  212. ~CShareLockInst();
  213. //wrappers for sharelock functions
  214. inline void ShareLock();
  215. inline void ShareUnlock();
  216. inline BOOL TryShareLock();
  217. inline void ExclusiveLock();
  218. inline void ExclusiveUnlock();
  219. inline BOOL TryExclusiveLock();
  220. inline void AssertIsLocked();
  221. };
  222. //---[ inline ShareLock wrapper functions ]------------------------------------
  223. //
  224. //
  225. // Description:
  226. // These functions are all thin wrappers for the sharelock wrapper
  227. // functions. If there is any tracking enabled for this object, then
  228. // the private (non-inline) functions are called.
  229. //
  230. // The idea is that you should be able to have these sharelocks in your
  231. // code with minimal perf-impact when logging is turned off.
  232. // Parameters:
  233. //
  234. // Returns:
  235. //
  236. // History:
  237. // 5/24/99 - MikeSwa Created
  238. //
  239. //-----------------------------------------------------------------------------
  240. void CShareLockInst::ShareLock()
  241. {
  242. if (fTrackContention() || fTrackSharedThreads() || fAssertSharedDeadlocks())
  243. PrvShareLock();
  244. else
  245. CShareLockInstBase::ShareLock();
  246. };
  247. void CShareLockInst::ShareUnlock()
  248. {
  249. if (fTrackSharedThreads() || fAssertSharedDeadlocks())
  250. PrvShareUnlock();
  251. else
  252. CShareLockInstBase::ShareUnlock();
  253. };
  254. BOOL CShareLockInst::TryShareLock()
  255. {
  256. if (fTrackContention() || fTrackSharedThreads() || fAssertSharedDeadlocks())
  257. return PrvTryShareLock();
  258. else
  259. return CShareLockInstBase::TryShareLock();
  260. };
  261. void CShareLockInst::ExclusiveLock()
  262. {
  263. if (fTrackContention() || fTrackExclusiveThreads())
  264. PrvExclusiveLock();
  265. else
  266. CShareLockInstBase::ExclusiveLock();
  267. };
  268. void CShareLockInst::ExclusiveUnlock()
  269. {
  270. if (fTrackExclusiveThreads())
  271. PrvExclusiveUnlock();
  272. else
  273. CShareLockInstBase::ExclusiveUnlock();
  274. };
  275. BOOL CShareLockInst::TryExclusiveLock()
  276. {
  277. if (fTrackContention() || fTrackExclusiveThreads())
  278. return PrvTryExclusiveLock();
  279. else
  280. return CShareLockInstBase::TryExclusiveLock();
  281. };
  282. //---[ AssertIsLocked ]--------------------------------------------------------
  283. //
  284. //
  285. // Description:
  286. // In Debug code, will assert if this is not locked by the calling thread.
  287. // NOTE: This requires the following flags are specified at object
  288. // creation time:
  289. // SHARE_LOCK_INST_TRACK_SHARED_THREADS
  290. // SHARE_LOCK_INST_TRACK_EXCLUSIVE_THREADS
  291. // Parameters:
  292. // -
  293. // Returns:
  294. // -
  295. // History:
  296. // 5/24/99 - MikeSwa Created
  297. //
  298. //-----------------------------------------------------------------------------
  299. void CShareLockInst::AssertIsLocked()
  300. {
  301. #ifdef DEBUG
  302. if ((SHARE_LOCK_INST_TRACK_SHARED_THREADS & m_dwFlags) &&
  303. (SHARE_LOCK_INST_TRACK_EXCLUSIVE_THREADS & m_dwFlags))
  304. {
  305. PrvAssertIsLocked();
  306. }
  307. #endif //DEBUG
  308. };
  309. #endif //__PTRWINST_H__