Source code of Windows XP (NT5)
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.

421 lines
9.3 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. vfpdlock.c
  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. // SequenceNumber: field that gets a unique stamp during each deadlock
  94. // analysis run. It helps figure out if the node was touched
  95. // already in the current graph traversal.
  96. //
  97. struct {
  98. ULONG Active : 1;
  99. ULONG OnlyTryAcquireUsed : 1;
  100. ULONG SequenceNumber : 30;
  101. };
  102. //
  103. // Stack traces for the resource acquisition moment.
  104. // Used when displaying deadlock proofs. On free builds
  105. // anything other than the first entry (return address)
  106. // may be bogus in case stack trace capturing failed.
  107. //
  108. PVOID StackTrace[VI_MAX_STACK_DEPTH];
  109. PVOID ParentStackTrace[VI_MAX_STACK_DEPTH];
  110. } VI_DEADLOCK_NODE, *PVI_DEADLOCK_NODE;
  111. //
  112. // VI_DEADLOCK_RESOURCE
  113. //
  114. typedef struct _VI_DEADLOCK_RESOURCE {
  115. //
  116. // Resource type (mutex, spinlock, etc.).
  117. //
  118. VI_DEADLOCK_RESOURCE_TYPE Type;
  119. //
  120. // Resource flags
  121. //
  122. // NodeCount : number of resource nodes created for this resource.
  123. //
  124. // RecursionCount : number of times this resource has been recursively acquired
  125. // It makes sense to put this counter in the resource because as long as
  126. // resource is acquired only one thread can operate on it.
  127. //
  128. struct {
  129. ULONG NodeCount : 16;
  130. ULONG RecursionCount : 16;
  131. };
  132. //
  133. // The address of the synchronization object used by the kernel.
  134. //
  135. PVOID ResourceAddress;
  136. //
  137. // The thread that currently owns the resource. The field is
  138. // null if nobody owns the resource.
  139. //
  140. struct _VI_DEADLOCK_THREAD * ThreadOwner;
  141. //
  142. // List of resource nodes representing acquisitions of this resource.
  143. //
  144. LIST_ENTRY ResourceList;
  145. union {
  146. //
  147. // List used for chaining resources from a hash bucket.
  148. //
  149. LIST_ENTRY HashChainList;
  150. //
  151. // Used to chain free resources. This list is used only after
  152. // the resource has been freed and we put the structure
  153. // into a cache to reduce kernel pool contention.
  154. //
  155. LIST_ENTRY FreeListEntry;
  156. };
  157. //
  158. // Stack trace of the resource creator. On free builds we
  159. // may have here only a return address that is bubbled up
  160. // from verifier thunks.
  161. //
  162. PVOID StackTrace [VI_MAX_STACK_DEPTH];
  163. //
  164. // Stack trace for last acquire
  165. //
  166. PVOID LastAcquireTrace [VI_MAX_STACK_DEPTH];
  167. //
  168. // Stack trace for last release
  169. //
  170. PVOID LastReleaseTrace [VI_MAX_STACK_DEPTH];
  171. } VI_DEADLOCK_RESOURCE, * PVI_DEADLOCK_RESOURCE;
  172. //
  173. // VI_DEADLOCK_THREAD
  174. //
  175. typedef struct _VI_DEADLOCK_THREAD {
  176. //
  177. // Kernel thread address
  178. //
  179. PKTHREAD Thread;
  180. //
  181. // The node representing the last resource acquisition made by
  182. // this thread.
  183. //
  184. //
  185. // We have separate graph branches for spinlocks and other types
  186. // of locks (fast mutex, mutex). The thread keeps a list of both types
  187. // so that we can properly release locks
  188. //
  189. PVI_DEADLOCK_NODE CurrentSpinNode;
  190. PVI_DEADLOCK_NODE CurrentOtherNode;
  191. union {
  192. //
  193. // Thread list. It is used for chaining into a hash bucket.
  194. //
  195. LIST_ENTRY ListEntry;
  196. //
  197. // Used to chain free nodes. The list is used only after we decide
  198. // to delete the thread structure (possibly because it does not
  199. // hold resources anymore). Keeping the structures in a cache
  200. // reduces pool contention.
  201. //
  202. LIST_ENTRY FreeListEntry;
  203. };
  204. //
  205. // Count of resources currently acquired by a thread. When this becomes
  206. // zero the thread will be destroyed. The count goes up during acquire
  207. // and down during release.
  208. //
  209. ULONG NodeCount;
  210. //
  211. // This counter is used to count how many IoCallDriver() calls with
  212. // paging IRPs are active for this thread. This information is necessary
  213. // to decide if we should temporarily disable deadlock verification
  214. // to avoid known lack of lock hierarchy issues in file system drivers.
  215. //
  216. ULONG PagingCount;
  217. } VI_DEADLOCK_THREAD, *PVI_DEADLOCK_THREAD;
  218. //
  219. // Deadlock verifier globals
  220. //
  221. typedef struct _VI_DEADLOCK_GLOBALS {
  222. //
  223. // Structure counters: [0] - current, [1] - maximum
  224. //
  225. ULONG Nodes[2];
  226. ULONG Resources[2];
  227. ULONG Threads[2];
  228. //
  229. // Maximum times for Acquire() and Release() in ticks.
  230. //
  231. LONGLONG TimeAcquire;
  232. LONGLONG TimeRelease;
  233. //
  234. // Total number of kernel pool bytes used by the deadlock verifier
  235. //
  236. SIZE_T BytesAllocated;
  237. //
  238. // Resource and thread collection.
  239. //
  240. PLIST_ENTRY ResourceDatabase;
  241. PLIST_ENTRY ThreadDatabase;
  242. //
  243. // How many times ExAllocatePool failed on us?
  244. // If this is >0 we stop deadlock verification.
  245. //
  246. ULONG AllocationFailures;
  247. //
  248. // How many nodes have been trimmed when we decided to forget
  249. // partially the history of some resources.
  250. //
  251. ULONG NodesTrimmedBasedOnAge;
  252. ULONG NodesTrimmedBasedOnCount;
  253. //
  254. // Deadlock analysis statistics
  255. //
  256. ULONG NodesSearched;
  257. ULONG MaxNodesSearched;
  258. ULONG SequenceNumber;
  259. ULONG RecursionDepthLimit;
  260. ULONG SearchedNodesLimit;
  261. ULONG DepthLimitHits;
  262. ULONG SearchLimitHits;
  263. //
  264. // Number of times we have to exonerate a deadlock because
  265. // it was protected by a common resource (e.g. thread 1 takes ABC,
  266. // thread 2 takes ACB -- this will get flagged initially by our algorithm
  267. // since B&C are taken out of order but is not actually a deadlock.
  268. //
  269. ULONG ABC_ACB_Skipped;
  270. //
  271. // How many locks are held simultaneously while the system is running?
  272. //
  273. #if DBG
  274. ULONG NodeLevelCounter[8];
  275. ULONG GraphNodes[8];
  276. ULONG TotalReleases;
  277. ULONG OutOfOrderReleases;
  278. ULONG RootNodesDeleted;
  279. #endif
  280. //
  281. // Caches of freed structures (thread, resource, node) used to
  282. // decrease kernel pool contention.
  283. //
  284. LIST_ENTRY FreeResourceList;
  285. LIST_ENTRY FreeThreadList;
  286. LIST_ENTRY FreeNodeList;
  287. ULONG FreeResourceCount;
  288. ULONG FreeThreadCount;
  289. ULONG FreeNodeCount;
  290. //
  291. // Resource address that caused the deadlock
  292. //
  293. PVOID Instigator;
  294. //
  295. // Number of participants in the deadlock
  296. //
  297. ULONG NumberOfParticipants;
  298. //
  299. // List of the nodes that participate in the deadlock
  300. //
  301. PVI_DEADLOCK_NODE Participant [NO_OF_DEADLOCK_PARTICIPANTS];
  302. LOGICAL CacheReductionInProgress;
  303. } VI_DEADLOCK_GLOBALS, *PVI_DEADLOCK_GLOBALS;
  304. #endif