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.

443 lines
10 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. vfdeadlock.h
  5. Abstract:
  6. Detect deadlocks in arbitrary synchronization objects.
  7. Author:
  8. Jordan Tigani (jtigani) 2-May-2000
  9. Silviu Calinoiu (silviuc) 9-May-2000
  10. Revision History:
  11. --*/
  12. #ifndef _VF_DEADLOCK_
  13. #define _VF_DEADLOCK_
  14. //
  15. // Deadlock detection package initialization.
  16. //
  17. VOID
  18. VfDeadlockDetectionInitialize(
  19. );
  20. //
  21. // Functions called from IovCallDriver (driver verifier replacement for
  22. // IoCallDriver) just before and after the real call to the driver is made.
  23. //
  24. BOOLEAN
  25. VfDeadlockBeforeCallDriver (
  26. IN PDEVICE_OBJECT DeviceObject,
  27. IN OUT PIRP Irp
  28. );
  29. VOID
  30. VfDeadlockAfterCallDriver (
  31. IN PDEVICE_OBJECT DeviceObject,
  32. IN OUT PIRP Irp,
  33. IN BOOLEAN PagingIrp
  34. );
  35. //
  36. // Maximum depth of stack traces captured.
  37. //
  38. #define VI_MAX_STACK_DEPTH 8
  39. #define NO_OF_DEADLOCK_PARTICIPANTS 32
  40. //
  41. // VI_DEADLOCK_NODE
  42. //
  43. typedef struct _VI_DEADLOCK_NODE {
  44. //
  45. // Node representing the acquisition of the previous resource.
  46. //
  47. struct _VI_DEADLOCK_NODE * Parent;
  48. //
  49. // Node representing the next resource acquisitions, that are
  50. // done after acquisition of the current resource.
  51. //
  52. struct _LIST_ENTRY ChildrenList;
  53. //
  54. // Field used to chain siblings in the tree. A parent node has the
  55. // ChildrenList field as the head of the children list that is chained
  56. // with the Siblings field.
  57. //
  58. struct _LIST_ENTRY SiblingsList;
  59. union {
  60. //
  61. // List of nodes representing the same resource acquisition
  62. // as the current node but in different contexts (lock combinations).
  63. //
  64. struct _LIST_ENTRY ResourceList;
  65. //
  66. // Used to chain free nodes. This is used only after the node has
  67. // been deleted (resource was freed). Nodes are kept in a cache
  68. // to reduce contention for the kernel pool.
  69. //
  70. struct _LIST_ENTRY FreeListEntry;
  71. };
  72. //
  73. // Back pointer to the descriptor for this resource.
  74. //
  75. struct _VI_DEADLOCK_RESOURCE * Root;
  76. //
  77. // When we find a deadlock, we keep this info around in order to
  78. // be able to identify the parties involved who have caused
  79. // the deadlock.
  80. //
  81. struct _VI_DEADLOCK_THREAD * ThreadEntry;
  82. //
  83. // Fields used for decision making within the deadlock analysis
  84. // algorithm.
  85. //
  86. // Active: 1 if the node represents a resource currently acquired,
  87. // 0 if resource was acquired in the past.
  88. //
  89. // OnlyTryAcquiredUsed: 1 if resource was always acquired with TryAcquire.
  90. // 0 if at least once normal acquire was used. A node that uses
  91. // only TryAcquire cannot be involved in a deadlock.
  92. //
  93. // ReleasedOutOfOrder: 1 if the resource was at least once released
  94. // out of order. The flag is used while looking for cycles because
  95. // this type of nodes will appear as part of the cycle but there is
  96. // no deadlock.
  97. //
  98. // SequenceNumber: field that gets a unique stamp during each deadlock
  99. // analysis run. It helps figure out if the node was touched
  100. // already in the current graph traversal.
  101. //
  102. struct {
  103. ULONG Active : 1;
  104. ULONG OnlyTryAcquireUsed : 1;
  105. ULONG ReleasedOutOfOrder : 1;
  106. ULONG SequenceNumber : 29;
  107. };
  108. //
  109. // Stack traces for the resource acquisition moment.
  110. // Used when displaying deadlock proofs. On free builds
  111. // anything other than the first entry (return address)
  112. // may be bogus in case stack trace capturing failed.
  113. //
  114. PVOID StackTrace[VI_MAX_STACK_DEPTH];
  115. PVOID ParentStackTrace[VI_MAX_STACK_DEPTH];
  116. } VI_DEADLOCK_NODE, *PVI_DEADLOCK_NODE;
  117. //
  118. // VI_DEADLOCK_RESOURCE
  119. //
  120. typedef struct _VI_DEADLOCK_RESOURCE {
  121. //
  122. // Resource type (mutex, spinlock, etc.).
  123. //
  124. VI_DEADLOCK_RESOURCE_TYPE Type;
  125. //
  126. // Resource flags
  127. //
  128. // NodeCount : number of resource nodes created for this resource.
  129. //
  130. // RecursionCount : number of times this resource has been recursively acquired
  131. // It makes sense to put this counter in the resource because as long as
  132. // resource is acquired only one thread can operate on it.
  133. //
  134. struct {
  135. ULONG NodeCount : 16;
  136. ULONG RecursionCount : 16;
  137. };
  138. //
  139. // The address of the synchronization object used by the kernel.
  140. //
  141. PVOID ResourceAddress;
  142. //
  143. // The thread that currently owns the resource. The field is
  144. // null if nobody owns the resource.
  145. //
  146. struct _VI_DEADLOCK_THREAD * ThreadOwner;
  147. //
  148. // List of resource nodes representing acquisitions of this resource.
  149. //
  150. LIST_ENTRY ResourceList;
  151. union {
  152. //
  153. // List used for chaining resources from a hash bucket.
  154. //
  155. LIST_ENTRY HashChainList;
  156. //
  157. // Used to chain free resources. This list is used only after
  158. // the resource has been freed and we put the structure
  159. // into a cache to reduce kernel pool contention.
  160. //
  161. LIST_ENTRY FreeListEntry;
  162. };
  163. //
  164. // Stack trace of the resource creator. On free builds we
  165. // may have here only a return address that is bubbled up
  166. // from verifier thunks.
  167. //
  168. PVOID StackTrace [VI_MAX_STACK_DEPTH];
  169. //
  170. // Stack trace for last acquire
  171. //
  172. PVOID LastAcquireTrace [VI_MAX_STACK_DEPTH];
  173. //
  174. // Stack trace for last release
  175. //
  176. PVOID LastReleaseTrace [VI_MAX_STACK_DEPTH];
  177. } VI_DEADLOCK_RESOURCE, * PVI_DEADLOCK_RESOURCE;
  178. //
  179. // VI_DEADLOCK_THREAD
  180. //
  181. typedef struct _VI_DEADLOCK_THREAD {
  182. //
  183. // Kernel thread address
  184. //
  185. PKTHREAD Thread;
  186. //
  187. // The node representing the last resource acquisition made by
  188. // this thread.
  189. //
  190. //
  191. // We have separate graph branches for spinlocks and other types
  192. // of locks (fast mutex, mutex). The thread keeps a list of both types
  193. // so that we can properly release locks
  194. //
  195. PVI_DEADLOCK_NODE CurrentSpinNode;
  196. PVI_DEADLOCK_NODE CurrentOtherNode;
  197. union {
  198. //
  199. // Thread list. It is used for chaining into a hash bucket.
  200. //
  201. LIST_ENTRY ListEntry;
  202. //
  203. // Used to chain free nodes. The list is used only after we decide
  204. // to delete the thread structure (possibly because it does not
  205. // hold resources anymore). Keeping the structures in a cache
  206. // reduces pool contention.
  207. //
  208. LIST_ENTRY FreeListEntry;
  209. };
  210. //
  211. // Count of resources currently acquired by a thread. When this becomes
  212. // zero the thread will be destroyed. The count goes up during acquire
  213. // and down during release.
  214. //
  215. ULONG NodeCount;
  216. //
  217. // This counter is used to count how many IoCallDriver() calls with
  218. // paging IRPs are active for this thread. This information is necessary
  219. // to decide if we should temporarily disable deadlock verification
  220. // to avoid known lack of lock hierarchy issues in file system drivers.
  221. //
  222. ULONG PagingCount;
  223. } VI_DEADLOCK_THREAD, *PVI_DEADLOCK_THREAD;
  224. //
  225. // Deadlock verifier globals
  226. //
  227. typedef struct _VI_DEADLOCK_GLOBALS {
  228. //
  229. // Structure counters: [0] - current, [1] - maximum
  230. //
  231. ULONG Nodes[2];
  232. ULONG Resources[2];
  233. ULONG Threads[2];
  234. //
  235. // Maximum times for Acquire() and Release() in ticks.
  236. //
  237. LONGLONG TimeAcquire;
  238. LONGLONG TimeRelease;
  239. //
  240. // Total number of kernel pool bytes used by the deadlock verifier
  241. //
  242. SIZE_T BytesAllocated;
  243. //
  244. // Resource and thread collection.
  245. //
  246. PLIST_ENTRY ResourceDatabase;
  247. PLIST_ENTRY ThreadDatabase;
  248. //
  249. // How many times ExAllocatePool failed on us?
  250. // If this is >0 we stop deadlock verification.
  251. //
  252. ULONG AllocationFailures;
  253. //
  254. // How many nodes have been trimmed when we decided to forget
  255. // partially the history of some resources.
  256. //
  257. ULONG NodesTrimmedBasedOnAge;
  258. ULONG NodesTrimmedBasedOnCount;
  259. //
  260. // Deadlock analysis statistics
  261. //
  262. ULONG NodesSearched;
  263. ULONG MaxNodesSearched;
  264. ULONG SequenceNumber;
  265. ULONG RecursionDepthLimit;
  266. ULONG SearchedNodesLimit;
  267. ULONG DepthLimitHits;
  268. ULONG SearchLimitHits;
  269. //
  270. // Number of times we have to exonerate a deadlock because
  271. // it was protected by a common resource (e.g. thread 1 takes ABC,
  272. // thread 2 takes ACB -- this will get flagged initially by our algorithm
  273. // since B&C are taken out of order but is not actually a deadlock.
  274. //
  275. ULONG ABC_ACB_Skipped;
  276. ULONG OutOfOrderReleases;
  277. ULONG NodesReleasedOutOfOrder;
  278. #if DBG
  279. //
  280. // How many locks are held simultaneously while the system is running?
  281. //
  282. ULONG NodeLevelCounter[8];
  283. ULONG GraphNodes[8];
  284. #endif
  285. ULONG TotalReleases;
  286. ULONG RootNodesDeleted;
  287. //
  288. // Used to control how often we delete portions of the dependency
  289. // graph.
  290. //
  291. ULONG ForgetHistoryCounter;
  292. //
  293. // How often was a worker items dispatched to trim the
  294. // pool cache.
  295. //
  296. ULONG PoolTrimCounter;
  297. //
  298. // Caches of freed structures (thread, resource, node) used to
  299. // decrease kernel pool contention.
  300. //
  301. LIST_ENTRY FreeResourceList;
  302. LIST_ENTRY FreeThreadList;
  303. LIST_ENTRY FreeNodeList;
  304. ULONG FreeResourceCount;
  305. ULONG FreeThreadCount;
  306. ULONG FreeNodeCount;
  307. //
  308. // Resource address that caused the deadlock
  309. //
  310. PVOID Instigator;
  311. //
  312. // Number of participants in the deadlock
  313. //
  314. ULONG NumberOfParticipants;
  315. //
  316. // List of the nodes that participate in the deadlock
  317. //
  318. PVI_DEADLOCK_NODE Participant [NO_OF_DEADLOCK_PARTICIPANTS];
  319. LOGICAL CacheReductionInProgress;
  320. } VI_DEADLOCK_GLOBALS, *PVI_DEADLOCK_GLOBALS;
  321. #endif