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.

4141 lines
108 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. deadlock.c
  5. Abstract:
  6. This module implements a deadlock verification package for
  7. critical section operations. The initial version is based on
  8. the driver verifier deadlock checking package for kernel
  9. synchornization objects.
  10. Author:
  11. Silviu Calinoiu (SilviuC) 6-Feb-2002
  12. Revision History:
  13. --*/
  14. /*++
  15. silviuc: update this comment
  16. The Deadlock Verifier
  17. The deadlock verifier is used to detect potential deadlocks. It does this
  18. by acquiring the history of how resources are acquired and trying to figure
  19. out on the fly if there are any potential lock hierarchy issues. The algorithms
  20. for finding cycles in the lock dependency graph is totally "blind". This means
  21. that if a driver acquires lock A then B in one place and lock B then A in
  22. another this will be triggered as a deadlock issue. This will happen even if you
  23. can build a proof based on other contextual factors that the deadlock can never
  24. happen.
  25. The deadlock verifier assumes there are four operations during the lifetime
  26. of a resource: initialize(), acquire(), release() and free(). The only one that
  27. is caught 100% of the time is free() due to special support from the kernel
  28. pool manager. The other ones can be missed if the operations are performed
  29. by an unverified driver or by kernel with kernel verifier disabled. The most
  30. typical of these misses is the initialize(). For example the kernel initializes
  31. a resource and then passes it to a driver to be used in acquire()/releae() cycles.
  32. This situation is covered 100% by the deadlock verifier. It will never complain
  33. about "resource uninitialized" issues.
  34. Missing acquire() or release() operations is trickier to deal with.
  35. This can happen if the a verified driver acquires a resource and then another
  36. driver that is not verified releases it or viceversa. This is in and on itself
  37. a very bad programming practive and therefore the deadlock verifier will flag
  38. these issues. As a side note we cannot do too much about working around them
  39. given that we would like to. Also, because missing acquire() or release()
  40. operations puts deadlock verifier internal structures into inconsistent
  41. states these failures are difficult to debug.
  42. The deadlock verifier stores the lock dependency graph using three types
  43. of structures: THREAD, RESOURCE, NODE.
  44. For every active thread in the system that holds at least one resource
  45. the package maintains a THREAD structure. This gets created when a thread
  46. acquires first resource and gets destroyed when thread releases the last
  47. resource. If a thread does not hold any resource it will not have a
  48. corresponding THREAD structure.
  49. For every resource in the system there is a RESOURCE structure. This is created
  50. when Initialize() is called in a verified driver or we first encounter an
  51. Acquire() in a verified driver. Note that a resource can be initialized in
  52. an unverified driver and then passed to a verified driver for use. Therefore
  53. we can encounter Acquire() operations for resources that are not in the
  54. deadlock verifier database. The resource gets deleted from the database when
  55. the memory containing it is freed either because ExFreePool gets called or
  56. Every acquisition of a resource is modeled by a NODE structure. When a thread
  57. acquires resource B while holding A the deadlock verifier will create a NODE
  58. for B and link it to the node for A.
  59. There are three important functions that make the interface with the outside
  60. world.
  61. AVrfpDeadlockInitializeResource hook for resource initialization
  62. AVrfpDeadlockAcquireResource hook for resource acquire
  63. AVrfpDeadlockReleaseResource hook for resource release
  64. VerifierDeadlockFreePool hook called from ExFreePool for every free()
  65. --*/
  66. #include "pch.h"
  67. #include "support.h"
  68. #include "deadlock.h"
  69. #include "logging.h"
  70. //
  71. // Enable/disable the deadlock detection package. This can be used
  72. // to disable temporarily the deadlock detection package.
  73. //
  74. BOOLEAN AVrfpDeadlockDetectionEnabled;
  75. //
  76. // If true we will complain about release() without acquire() or acquire()
  77. // while we think the resource is still owned. This can happen legitimately
  78. // if a lock is shared between drivers and for example acquire() happens in
  79. // an unverified driver and release() in a verified one or viceversa. The
  80. // safest thing would be to enable this checks only if kernel verifier and
  81. // dirver verifier for all drivers are enabled.
  82. //
  83. BOOLEAN AVrfpDeadlockStrict; //silviuc: needed?
  84. //
  85. // If true we will complain about uninitialized and double initialized
  86. // resources. If false we resolve quitely these issues on the fly by
  87. // simulating an initialize ourselves during the acquire() operation.
  88. // This can happen legitimately if the resource is initialized in an
  89. // unverified driver and passed to a verified one to be used. Therefore
  90. // the safest thing would be to enable this only if kernel verifier and
  91. // all driver verifier for all dirvers are enabled.
  92. //
  93. BOOLEAN AVrfpDeadlockVeryStrict; //silviuc: needed?
  94. //
  95. // AgeWindow is used while trimming the graph nodes that have not
  96. // been accessed in a while. If the global age minus the age of the node
  97. // is bigger than the age window then the node is a candidate for trimming.
  98. //
  99. // The TrimThreshold variable controls if the trimming will start for a
  100. // resource. As long as a resource has less than TrimThreshold nodes we will
  101. // not apply the ageing algorithm to trim nodes for that resource.
  102. //
  103. ULONG AVrfpDeadlockAgeWindow = 0x2000;
  104. ULONG AVrfpDeadlockTrimThreshold = 0x100;
  105. //
  106. // Various deadlock verification flags flags
  107. //
  108. // Recursive aquisition ok: mutexes can be recursively acquired
  109. //
  110. // No initialization function: if resource type does not have such a function
  111. // we cannot expect that in acquire() the resource is already initialized
  112. // by a previous call to initialize(). Fast mutexes are like this.
  113. //
  114. // Reverse release ok: release is not done in the same order as acquire
  115. //
  116. // Reinitialize ok: sometimes they reinitialize the resource.
  117. //
  118. // Note that a resource might appear as uninitialized if it is initialized
  119. // in an unverified driver and then passed to a verified driver that calls
  120. // acquire(). This is for instance the case with device extensions that are
  121. // allocated by the kernel but used by a particular driver.
  122. //
  123. // silviuc: based on this maybe we should drop the whole not initialized thing?
  124. //
  125. // silviuc: do we need all these flags?
  126. #define AVRF_DEADLOCK_FLAG_RECURSIVE_ACQUISITION_OK 0x0001
  127. #define AVRF_DEADLOCK_FLAG_NO_INITIALIZATION_FUNCTION 0x0002
  128. #define AVRF_DEADLOCK_FLAG_REVERSE_RELEASE_OK 0x0004
  129. #define AVRF_DEADLOCK_FLAG_REINITIALIZE_OK 0x0008
  130. //
  131. // Specific verification flags for each resource type. The
  132. // indeces in the vector match the values for the enumeration
  133. // type AVRF_DEADLOCK_RESOURCE_TYPE from `deadlock.h'.
  134. //
  135. ULONG AVrfpDeadlockResourceTypeInfo[AVrfpDeadlockTypeMaximum] =
  136. {
  137. // AVrfpDeadlockTypeUnknown //
  138. 0,
  139. // AVrfpDeadlockTypeCriticalSection//
  140. AVRF_DEADLOCK_FLAG_RECURSIVE_ACQUISITION_OK |
  141. AVRF_DEADLOCK_FLAG_REVERSE_RELEASE_OK |
  142. // silviuc: delete this if not needed
  143. // AVRF_DEADLOCK_FLAG_NO_INITIALIZATION_FUNCTION |
  144. // AVRF_DEADLOCK_FLAG_REINITIALIZE_OK |
  145. 0,
  146. };
  147. //
  148. // Control debugging behavior. A zero value means bugcheck for every failure.
  149. //
  150. ULONG AVrfpDeadlockDebug;
  151. //
  152. // Various health indicators
  153. //
  154. struct {
  155. ULONG AllocationFailures : 1;
  156. ULONG KernelVerifierEnabled : 1; //silviuc:delete
  157. ULONG DriverVerifierForAllEnabled : 1; //silviuc:delete
  158. ULONG SequenceNumberOverflow : 1;
  159. ULONG DeadlockParticipantsOverflow : 1;
  160. ULONG ResourceNodeCountOverflow : 1;
  161. ULONG Reserved : 15;
  162. } AVrfpDeadlockState;
  163. //
  164. // Maximum number of locks acceptable to be hold simultaneously
  165. //
  166. ULONG AVrfpDeadlockSimultaneousLocksLimit = 10;
  167. //
  168. // Deadlock verifier specific issues (bugs)
  169. //
  170. // SELF_DEADLOCK
  171. //
  172. // Acquiring the same resource recursively.
  173. //
  174. // DEADLOCK_DETECTED
  175. //
  176. // Plain deadlock. Need the previous information
  177. // messages to build a deadlock proof.
  178. //
  179. // UNINITIALIZED_RESOURCE
  180. //
  181. // Acquiring a resource that was never initialized.
  182. //
  183. // UNEXPECTED_RELEASE
  184. //
  185. // Releasing a resource which is not the last one
  186. // acquired by the current thread. Spinlocks are handled like this
  187. // in a few drivers. It is not a bug per se.
  188. //
  189. // UNEXPECTED_THREAD
  190. //
  191. // Current thread does not have any resources acquired. This may be legit if
  192. // we acquire in one thread and release in another. This would be bad programming
  193. // practice but not a crash waiting to happen per se.
  194. //
  195. // MULTIPLE_INITIALIZATION
  196. //
  197. // Attempting to initialize a second time the same resource.
  198. //
  199. // THREAD_HOLDS_RESOURCES
  200. //
  201. // Thread was killed while holding resources or a resource is being
  202. // deleted while holding resources.
  203. //
  204. #define AVRF_DEADLOCK_ISSUE_SELF_DEADLOCK 0x1000
  205. #define AVRF_DEADLOCK_ISSUE_DEADLOCK_DETECTED 0x1001
  206. #define AVRF_DEADLOCK_ISSUE_UNINITIALIZED_RESOURCE 0x1002
  207. #define AVRF_DEADLOCK_ISSUE_UNEXPECTED_RELEASE 0x1003
  208. #define AVRF_DEADLOCK_ISSUE_UNEXPECTED_THREAD 0x1004
  209. #define AVRF_DEADLOCK_ISSUE_MULTIPLE_INITIALIZATION 0x1005
  210. #define AVRF_DEADLOCK_ISSUE_THREAD_HOLDS_RESOURCES 0x1006
  211. #define AVRF_DEADLOCK_ISSUE_UNACQUIRED_RESOURCE 0x1007
  212. //
  213. // Performance counters read from registry.
  214. //
  215. ULONG ViSearchedNodesLimitFromRegistry;//silviuc:delete
  216. ULONG ViRecursionDepthLimitFromRegistry;//silviuc:delete
  217. //
  218. // Water marks for the cache of freed structures.
  219. //
  220. // N.B. The `MAX_FREE' value will trigger a trim and the
  221. // `TRIM_TARGET' will be the trim goal. The trim target must
  222. // be meaningfully lower than the free watermark to avoid a
  223. // chainsaw effect where we get one above free highwater mark,
  224. // we trim to the mark and next free will trigger a repeat.
  225. // Since trimming is done in worker threads this will put a lot
  226. // of unnecessary strain on the system.
  227. //
  228. #define AVRF_DEADLOCK_MAX_FREE_THREAD 0x40
  229. #define AVRF_DEADLOCK_MAX_FREE_NODE 0x80
  230. #define AVRF_DEADLOCK_MAX_FREE_RESOURCE 0x80
  231. #define AVRF_DEADLOCK_TRIM_TARGET_THREAD 0x20
  232. #define AVRF_DEADLOCK_TRIM_TARGET_NODE 0x40
  233. #define AVRF_DEADLOCK_TRIM_TARGET_RESOURCE 0x40
  234. WORK_QUEUE_ITEM ViTrimDeadlockPoolWorkItem;
  235. //
  236. // Amount of memory preallocated if kernel verifier
  237. // is enabled. If kernel verifier is enabled no memory
  238. // is ever allocated from kernel pool except in the
  239. // DeadlockDetectionInitialize() routine.
  240. //
  241. ULONG AVrfpDeadlockReservedThreads = 0x200;
  242. ULONG AVrfpDeadlockReservedNodes = 0x4000;
  243. ULONG AVrfpDeadlockReservedResources = 0x2000;
  244. //
  245. // Block types that can be allocated.
  246. //
  247. typedef enum {
  248. AVrfpDeadlockUnknown = 0,
  249. AVrfpDeadlockResource,
  250. AVrfpDeadlockNode,
  251. AVrfpDeadlockThread
  252. } AVRF_DEADLOCK_ALLOC_TYPE;
  253. //
  254. // AVRF_DEADLOCK_GLOBALS
  255. //
  256. // silviuc: should have diff numbers for threads and resources.
  257. #define AVRF_DEADLOCK_HASH_BINS 0x1F
  258. PAVRF_DEADLOCK_GLOBALS AVrfpDeadlockGlobals;
  259. //
  260. // Default maximum recursion depth for the deadlock
  261. // detection algorithm. This can be overridden by registry.
  262. //
  263. #define AVRF_DEADLOCK_MAXIMUM_DEGREE 4
  264. //
  265. // Default maximum number of searched nodes for the deadlock
  266. // detection algorithm. This can be overridden by registry.
  267. //
  268. #define AVRF_DEADLOCK_MAXIMUM_SEARCH 1000
  269. //
  270. // Verifier deadlock detection pool tag.
  271. //
  272. #define AVRF_DEADLOCK_TAG 'kclD'
  273. //
  274. // Controls how often ForgetResourceHistory gets called.
  275. //
  276. #define AVRF_DEADLOCK_FORGET_HISTORY_FREQUENCY 16
  277. //
  278. // Function to capture runtime stack traces.
  279. //
  280. NTSYSAPI
  281. USHORT
  282. NTAPI
  283. RtlCaptureStackBackTrace(
  284. IN ULONG FramesToSkip,
  285. IN ULONG FramesToCapture,
  286. OUT PVOID *BackTrace,
  287. OUT PULONG BackTraceHash
  288. );
  289. /////////////////////////////////////////////////////////////////////
  290. /////////////////////////////// Internal deadlock detection functions
  291. /////////////////////////////////////////////////////////////////////
  292. VOID
  293. AVrfpDeadlockDetectionInitialize (
  294. VOID
  295. );
  296. VOID
  297. AVrfpDeadlockDetectionCleanup (
  298. VOID
  299. );
  300. PLIST_ENTRY
  301. AVrfpDeadlockDatabaseHash (
  302. IN PLIST_ENTRY Database,
  303. IN PVOID Address
  304. );
  305. PAVRF_DEADLOCK_RESOURCE
  306. AVrfpDeadlockSearchResource (
  307. IN PVOID ResourceAddress
  308. );
  309. BOOLEAN
  310. AVrfpDeadlockSimilarNode (
  311. IN PVOID Resource,
  312. IN BOOLEAN TryNode,
  313. IN PAVRF_DEADLOCK_NODE Node
  314. );
  315. BOOLEAN
  316. AVrfpDeadlockCanProceed (
  317. VOID
  318. );
  319. BOOLEAN
  320. AVrfpDeadlockAnalyze (
  321. IN PVOID ResourceAddress,
  322. IN PAVRF_DEADLOCK_NODE CurrentNode,
  323. IN BOOLEAN FirstCall,
  324. IN ULONG Degree
  325. );
  326. PAVRF_DEADLOCK_THREAD
  327. AVrfpDeadlockSearchThread (
  328. HANDLE Thread
  329. );
  330. PAVRF_DEADLOCK_THREAD
  331. AVrfpDeadlockAddThread (
  332. HANDLE Thread,
  333. PVOID ReservedThread
  334. );
  335. VOID
  336. AVrfpDeadlockDeleteThread (
  337. PAVRF_DEADLOCK_THREAD Thread,
  338. BOOLEAN Cleanup
  339. );
  340. BOOLEAN
  341. AVrfpDeadlockAddResource(
  342. IN PVOID Resource,
  343. IN AVRF_DEADLOCK_RESOURCE_TYPE Type,
  344. IN PVOID Caller,
  345. IN PVOID ReservedResource
  346. );
  347. PVOID
  348. AVrfpDeadlockAllocate (
  349. AVRF_DEADLOCK_ALLOC_TYPE Type
  350. );
  351. VOID
  352. AVrfpDeadlockFree (
  353. PVOID Object,
  354. AVRF_DEADLOCK_ALLOC_TYPE Type
  355. );
  356. VOID
  357. AVrfpDeadlockTrimPoolCache (
  358. VOID
  359. );
  360. VOID
  361. AVrfpDeadlockTrimPoolCacheWorker (
  362. PVOID
  363. );
  364. PVOID
  365. AVrfpDeadlockAllocateFromPoolCache (
  366. PULONG Count,
  367. ULONG MaximumCount,
  368. PLIST_ENTRY List,
  369. SIZE_T Offset
  370. );
  371. VOID
  372. AVrfpDeadlockFreeIntoPoolCache (
  373. PVOID Object,
  374. PULONG Count,
  375. PLIST_ENTRY List,
  376. SIZE_T Offset
  377. );
  378. VOID
  379. AVrfpDeadlockReportIssue (
  380. ULONG_PTR Param1,
  381. ULONG_PTR Param2,
  382. ULONG_PTR Param3,
  383. ULONG_PTR Param4
  384. );
  385. VOID
  386. AVrfpDeadlockAddParticipant(
  387. PAVRF_DEADLOCK_NODE Node
  388. );
  389. VOID
  390. AVrfpDeadlockDeleteResource (
  391. PAVRF_DEADLOCK_RESOURCE Resource,
  392. BOOLEAN Cleanup
  393. );
  394. VOID
  395. AVrfpDeadlockDeleteNode (
  396. PAVRF_DEADLOCK_NODE Node,
  397. BOOLEAN Cleanup
  398. );
  399. ULONG
  400. AVrfpDeadlockNodeLevel (
  401. PAVRF_DEADLOCK_NODE Node
  402. );
  403. BOOLEAN
  404. AVrfpDeadlockCertify(
  405. VOID
  406. );
  407. VOID
  408. AVrfpDeadlockDetectionLock (
  409. VOID
  410. );
  411. VOID
  412. AVrfpDeadlockDetectionUnlock (
  413. VOID
  414. );
  415. VOID
  416. AVrfpDeadlockCheckThreadConsistency (
  417. PAVRF_DEADLOCK_THREAD Thread,
  418. BOOLEAN Recursion
  419. );
  420. VOID
  421. AVrfpDeadlockCheckNodeConsistency (
  422. PAVRF_DEADLOCK_NODE Node,
  423. BOOLEAN Recursion
  424. );
  425. VOID
  426. AVrfpDeadlockCheckResourceConsistency (
  427. PAVRF_DEADLOCK_RESOURCE Resource,
  428. BOOLEAN Recursion
  429. );
  430. PAVRF_DEADLOCK_THREAD
  431. AVrfpDeadlockCheckThreadReferences (
  432. PAVRF_DEADLOCK_NODE Node
  433. );
  434. VOID
  435. AVrfpDeadlockCheckDuplicatesAmongChildren (
  436. PAVRF_DEADLOCK_NODE Parent,
  437. PAVRF_DEADLOCK_NODE Child
  438. );
  439. VOID
  440. AVrfpDeadlockCheckDuplicatesAmongRoots (
  441. PAVRF_DEADLOCK_NODE Root
  442. );
  443. LOGICAL
  444. AVrfpDeadlockSimilarNodes (
  445. PAVRF_DEADLOCK_NODE NodeA,
  446. PAVRF_DEADLOCK_NODE NodeB
  447. );
  448. VOID
  449. AVrfpDeadlockMergeNodes (
  450. PAVRF_DEADLOCK_NODE NodeTo,
  451. PAVRF_DEADLOCK_NODE NodeFrom
  452. );
  453. VOID
  454. AVrfpDeadlockTrimResources (
  455. PLIST_ENTRY HashList
  456. );
  457. VOID
  458. AVrfpDeadlockForgetResourceHistory (
  459. PAVRF_DEADLOCK_RESOURCE Resource,
  460. ULONG TrimThreshold,
  461. ULONG AgeThreshold
  462. );
  463. VOID
  464. AVrfpDeadlockCheckStackLimits (
  465. VOID
  466. );
  467. BOOLEAN
  468. AVrfpDeadlockResourceInitialize(
  469. IN PVOID Resource,
  470. IN AVRF_DEADLOCK_RESOURCE_TYPE Type,
  471. IN PVOID Caller
  472. );
  473. VOID
  474. AVrfpDeadlockAcquireResource (
  475. IN PVOID Resource,
  476. IN AVRF_DEADLOCK_RESOURCE_TYPE Type,
  477. IN HANDLE Thread,
  478. IN BOOLEAN TryAcquire,
  479. IN PVOID Caller
  480. );
  481. VOID
  482. AVrfpDeadlockReleaseResource(
  483. IN PVOID Resource,
  484. IN AVRF_DEADLOCK_RESOURCE_TYPE Type,
  485. IN HANDLE Thread,
  486. IN PVOID Caller
  487. );
  488. /////////////////////////////////////////////////////////////////////
  489. /////////////////////////////// Deadlock verifier public entry points
  490. /////////////////////////////////////////////////////////////////////
  491. LOGICAL
  492. AVrfDeadlockResourceInitialize (
  493. PVOID Resource,
  494. PVOID Caller
  495. )
  496. {
  497. return AVrfpDeadlockResourceInitialize(Resource,
  498. AVrfpDeadlockTypeCriticalSection,
  499. Caller);
  500. }
  501. LOGICAL
  502. AVrfDeadlockResourceDelete (
  503. PVOID Resource,
  504. PVOID Caller
  505. )
  506. {
  507. PAVRF_DEADLOCK_RESOURCE Descriptor;
  508. UNREFERENCED_PARAMETER (Caller);
  509. AVrfpDeadlockDetectionLock ();
  510. Descriptor = AVrfpDeadlockSearchResource (Resource);
  511. if (Descriptor == NULL) {
  512. //silviuc: whine about bogus address.
  513. }
  514. else {
  515. AVrfpDeadlockDeleteResource (Descriptor, FALSE);
  516. }
  517. AVrfpDeadlockDetectionUnlock ();
  518. return TRUE;
  519. }
  520. LOGICAL
  521. AVrfDeadlockResourceAcquire (
  522. PVOID Resource,
  523. PVOID Caller,
  524. LOGICAL TryAcquire
  525. )
  526. { // silviuc: should use only LOGICAL instead of BOOLEAN
  527. AVrfpDeadlockAcquireResource (Resource,
  528. AVrfpDeadlockTypeCriticalSection,
  529. NtCurrentTeb()->ClientId.UniqueThread,
  530. (BOOLEAN)TryAcquire,
  531. Caller);
  532. return TRUE;
  533. }
  534. LOGICAL
  535. AVrfDeadlockResourceRelease (
  536. PVOID Resource,
  537. PVOID Caller
  538. )
  539. {
  540. AVrfpDeadlockReleaseResource (Resource,
  541. AVrfpDeadlockTypeCriticalSection,
  542. NtCurrentTeb()->ClientId.UniqueThread,
  543. Caller);
  544. return TRUE;
  545. }
  546. /////////////////////////////////////////////////////////////////////
  547. /////////////////////////////////////// Lock/unlock deadlock verifier
  548. /////////////////////////////////////////////////////////////////////
  549. //
  550. // Global `deadlock lock database' lock
  551. //
  552. RTL_CRITICAL_SECTION AVrfpDeadlockDatabaseLock;
  553. VOID
  554. AVrfpDeadlockDetectionLock (
  555. VOID
  556. )
  557. {
  558. RtlEnterCriticalSection (&AVrfpDeadlockDatabaseLock);
  559. }
  560. VOID
  561. AVrfpDeadlockDetectionUnlock (
  562. VOID
  563. )
  564. {
  565. RtlLeaveCriticalSection (&AVrfpDeadlockDatabaseLock);
  566. }
  567. /////////////////////////////////////////////////////////////////////
  568. ///////////////////// Initialization and deadlock database management
  569. /////////////////////////////////////////////////////////////////////
  570. PLIST_ENTRY
  571. AVrfpDeadlockDatabaseHash(
  572. IN PLIST_ENTRY Database,
  573. IN PVOID Address
  574. )
  575. /*++
  576. Routine Description:
  577. This routine hashes the resource address into the deadlock database.
  578. The hash bin is represented by a list entry.
  579. Arguments:
  580. ResourceAddress: Address of the resource that is being hashed
  581. Return Value:
  582. PLIST_ENTRY -- the list entry associated with the hash bin we land in.
  583. --*/
  584. {
  585. return Database + ((((ULONG_PTR)Address)) % AVRF_DEADLOCK_HASH_BINS);
  586. }
  587. VOID
  588. AVrfDeadlockDetectionInitialize(
  589. VOID
  590. )
  591. /*++
  592. Routine Description:
  593. This routine initializes the data structures necessary for detecting
  594. deadlocks in usage of synchronization objects.
  595. Arguments:
  596. None.
  597. Return Value:
  598. None. If successful AVrfpDeadlockGlobals will point to a fully initialized
  599. structure.
  600. Environment:
  601. Application verifier initialization only.
  602. --*/
  603. {
  604. ULONG I;
  605. SIZE_T TableSize;
  606. //
  607. // Allocate the globals structure. AVrfpDeadlockGlobals value is
  608. // used to figure out if the whole initialization was successful
  609. // or not.
  610. //
  611. AVrfpDeadlockGlobals = AVrfpAllocate (sizeof (AVRF_DEADLOCK_GLOBALS));
  612. if (AVrfpDeadlockGlobals == NULL) {
  613. goto Failed;
  614. }
  615. RtlZeroMemory (AVrfpDeadlockGlobals, sizeof (AVRF_DEADLOCK_GLOBALS));
  616. //
  617. // Allocate hash tables for resources and threads.
  618. //
  619. TableSize = sizeof (LIST_ENTRY) * AVRF_DEADLOCK_HASH_BINS;
  620. AVrfpDeadlockGlobals->ResourceDatabase = AVrfpAllocate (TableSize);
  621. if (AVrfpDeadlockGlobals->ResourceDatabase == NULL) {
  622. goto Failed;
  623. }
  624. AVrfpDeadlockGlobals->ThreadDatabase = AVrfpAllocate (TableSize);
  625. if (AVrfpDeadlockGlobals->ThreadDatabase == NULL) {
  626. goto Failed;
  627. }
  628. //
  629. // Initialize the free lists.
  630. //
  631. InitializeListHead(&AVrfpDeadlockGlobals->FreeResourceList);
  632. InitializeListHead(&AVrfpDeadlockGlobals->FreeThreadList);
  633. InitializeListHead(&AVrfpDeadlockGlobals->FreeNodeList);
  634. //
  635. // Initialize hash bins and database lock.
  636. //
  637. for (I = 0; I < AVRF_DEADLOCK_HASH_BINS; I += 1) {
  638. InitializeListHead(&(AVrfpDeadlockGlobals->ResourceDatabase[I]));
  639. InitializeListHead(&AVrfpDeadlockGlobals->ThreadDatabase[I]);
  640. }
  641. RtlInitializeCriticalSection (&AVrfpDeadlockDatabaseLock);
  642. //
  643. // Initialize deadlock analysis parameters
  644. //
  645. AVrfpDeadlockGlobals->RecursionDepthLimit = AVRF_DEADLOCK_MAXIMUM_DEGREE;
  646. AVrfpDeadlockGlobals->SearchedNodesLimit = AVRF_DEADLOCK_MAXIMUM_SEARCH;
  647. //
  648. // Mark that everything went fine and return
  649. //
  650. AVrfpDeadlockDetectionEnabled = TRUE;
  651. return;
  652. Failed:
  653. //
  654. // Cleanup if any of our allocations failed
  655. //
  656. if (AVrfpDeadlockGlobals) {
  657. if (AVrfpDeadlockGlobals->ResourceDatabase != NULL) {
  658. AVrfpFree (AVrfpDeadlockGlobals->ResourceDatabase);
  659. }
  660. if (AVrfpDeadlockGlobals->ThreadDatabase != NULL) {
  661. AVrfpFree (AVrfpDeadlockGlobals->ThreadDatabase);
  662. }
  663. if (AVrfpDeadlockGlobals != NULL) {
  664. AVrfpFree (AVrfpDeadlockGlobals);
  665. //
  666. // Important to set this to null for failure because it is
  667. // used to figure out if the package got initialized or not.
  668. //
  669. AVrfpDeadlockGlobals = NULL;
  670. }
  671. }
  672. return;
  673. }
  674. VOID
  675. AVrfpDeadlockDetectionCleanup (
  676. VOID
  677. )
  678. /*++
  679. Routine Description:
  680. This routine tears down all deadlock verifier internal structures.
  681. Arguments:
  682. None.
  683. Return Value:
  684. None.
  685. --*/
  686. {
  687. ULONG Index;
  688. PLIST_ENTRY Current;
  689. PAVRF_DEADLOCK_RESOURCE Resource;
  690. PAVRF_DEADLOCK_THREAD Thread;
  691. PVOID Block;
  692. // silviuc: no locks?
  693. //
  694. // If we are not initialized then nothing to do.
  695. //
  696. if (AVrfpDeadlockGlobals == NULL) {
  697. return;
  698. }
  699. //
  700. // Iterate all resources and delete them. This will also delete
  701. // all nodes associated with resources.
  702. //
  703. for (Index = 0; Index < AVRF_DEADLOCK_HASH_BINS; Index += 1) {
  704. Current = AVrfpDeadlockGlobals->ResourceDatabase[Index].Flink;
  705. while (Current != &(AVrfpDeadlockGlobals->ResourceDatabase[Index])) {
  706. Resource = CONTAINING_RECORD (Current,
  707. AVRF_DEADLOCK_RESOURCE,
  708. HashChainList);
  709. Current = Current->Flink;
  710. AVrfpDeadlockDeleteResource (Resource, TRUE);
  711. }
  712. }
  713. //
  714. // Iterate all threads and delete them.
  715. //
  716. for (Index = 0; Index < AVRF_DEADLOCK_HASH_BINS; Index += 1) {
  717. Current = AVrfpDeadlockGlobals->ThreadDatabase[Index].Flink;
  718. while (Current != &(AVrfpDeadlockGlobals->ThreadDatabase[Index])) {
  719. Thread = CONTAINING_RECORD (Current,
  720. AVRF_DEADLOCK_THREAD,
  721. ListEntry);
  722. Current = Current->Flink;
  723. AVrfpDeadlockDeleteThread (Thread, TRUE);
  724. }
  725. }
  726. //
  727. // Everything should be in the pool caches by now.
  728. //
  729. ASSERT (AVrfpDeadlockGlobals->BytesAllocated == 0);
  730. //
  731. // Free pool caches.
  732. //
  733. Current = AVrfpDeadlockGlobals->FreeNodeList.Flink;
  734. while (Current != &(AVrfpDeadlockGlobals->FreeNodeList)) {
  735. Block = (PVOID) CONTAINING_RECORD (Current,
  736. AVRF_DEADLOCK_NODE,
  737. FreeListEntry);
  738. Current = Current->Flink;
  739. AVrfpFree (Block);
  740. }
  741. Current = AVrfpDeadlockGlobals->FreeResourceList.Flink;
  742. while (Current != &(AVrfpDeadlockGlobals->FreeResourceList)) {
  743. Block = (PVOID) CONTAINING_RECORD (Current,
  744. AVRF_DEADLOCK_RESOURCE,
  745. FreeListEntry);
  746. Current = Current->Flink;
  747. AVrfpFree (Block);
  748. }
  749. Current = AVrfpDeadlockGlobals->FreeThreadList.Flink;
  750. while (Current != &(AVrfpDeadlockGlobals->FreeThreadList)) {
  751. Block = (PVOID) CONTAINING_RECORD (Current,
  752. AVRF_DEADLOCK_THREAD,
  753. FreeListEntry);
  754. Current = Current->Flink;
  755. AVrfpFree (Block);
  756. }
  757. //
  758. // Free databases and global structure
  759. //
  760. AVrfpFree (AVrfpDeadlockGlobals->ResourceDatabase);
  761. AVrfpFree (AVrfpDeadlockGlobals->ThreadDatabase);
  762. AVrfpFree (AVrfpDeadlockGlobals);
  763. AVrfpDeadlockGlobals = NULL;
  764. AVrfpDeadlockDetectionEnabled = FALSE;
  765. }
  766. BOOLEAN
  767. AVrfpDeadlockCanProceed (
  768. VOID
  769. )
  770. /*++
  771. Routine Description:
  772. This routine is called by deadlock verifier exports (initialize,
  773. acquire, release) to figure out if deadlock verification should
  774. proceed for the current operation. There are several reasons
  775. why the return should be false. For example we failed to initialize
  776. the deadlock verifier package etc.
  777. Arguments:
  778. None.
  779. Return Value:
  780. True if deadlock verification should proceed for the current
  781. operation.
  782. Environment:
  783. Internal. Called by deadlock verifier exports.
  784. --*/
  785. {
  786. //
  787. // Skip if process is shutting down.
  788. //
  789. if (RtlDllShutdownInProgress()) {
  790. return FALSE;
  791. }
  792. //
  793. // Skip if package not initialized
  794. //
  795. if (AVrfpDeadlockGlobals == NULL) {
  796. return FALSE;
  797. }
  798. //
  799. // Skip if package is disabled
  800. //
  801. if (! AVrfpDeadlockDetectionEnabled) {
  802. return FALSE;
  803. }
  804. //
  805. // Skip if we ever encountered an allocation failure
  806. //
  807. if (AVrfpDeadlockGlobals->AllocationFailures > 0) {
  808. return FALSE;
  809. }
  810. return TRUE;
  811. }
  812. /////////////////////////////////////////////////////////////////////
  813. //////////////////////////////////////////// Deadlock detection logic
  814. /////////////////////////////////////////////////////////////////////
  815. BOOLEAN
  816. AVrfpDeadlockAnalyze(
  817. IN PVOID ResourceAddress,
  818. IN PAVRF_DEADLOCK_NODE AcquiredNode,
  819. IN BOOLEAN FirstCall,
  820. IN ULONG Degree
  821. )
  822. /*++
  823. Routine Description:
  824. This routine determines whether the acquisition of a certain resource
  825. could result in a deadlock.
  826. The routine assumes the deadlock database lock is held.
  827. Arguments:
  828. ResourceAddress - address of the resource that will be acquired
  829. AcquiredNode - a node representing the most recent resource acquisition
  830. made by the thread trying to acquire `ResourceAddress'.
  831. FirstCall - true if this is not a recursive call made from within the
  832. function. It is used for doing one time per analysis only operations.
  833. Degree - depth of recursion.
  834. Return Value:
  835. True if deadlock detected, false otherwise.
  836. --*/
  837. {
  838. PAVRF_DEADLOCK_NODE CurrentNode;
  839. PAVRF_DEADLOCK_RESOURCE CurrentResource;
  840. PAVRF_DEADLOCK_NODE CurrentParent;
  841. BOOLEAN FoundDeadlock;
  842. PLIST_ENTRY Current;
  843. ASSERT (AcquiredNode);
  844. //
  845. // Setup global counters.
  846. //
  847. if (FirstCall) {
  848. AVrfpDeadlockGlobals->NodesSearched = 0;
  849. AVrfpDeadlockGlobals->SequenceNumber += 1;
  850. AVrfpDeadlockGlobals->NumberOfParticipants = 0;
  851. AVrfpDeadlockGlobals->Instigator = NULL;
  852. if (AVrfpDeadlockGlobals->SequenceNumber == ((1 << 30) - 2)) {
  853. AVrfpDeadlockState.SequenceNumberOverflow = 1;
  854. }
  855. }
  856. //
  857. // If our node is already stamped with the current sequence number
  858. // then we have been here before in the current search. There is a very
  859. // remote possibility that the node was not touched in the last
  860. // 2^N calls to this function and the sequence number counter
  861. // overwrapped but we can live with this.
  862. //
  863. if (AcquiredNode->SequenceNumber == AVrfpDeadlockGlobals->SequenceNumber) {
  864. return FALSE;
  865. }
  866. //
  867. // Update the counter of nodes touched in this search
  868. //
  869. AVrfpDeadlockGlobals->NodesSearched += 1;
  870. //
  871. // Stamp node with current sequence number.
  872. //
  873. AcquiredNode->SequenceNumber = AVrfpDeadlockGlobals->SequenceNumber;
  874. //
  875. // Stop recursion if it gets too deep.
  876. //
  877. if (Degree > AVrfpDeadlockGlobals->RecursionDepthLimit) {
  878. AVrfpDeadlockGlobals->DepthLimitHits += 1;
  879. return FALSE;
  880. }
  881. //
  882. // Stop recursion if it gets too lengthy
  883. //
  884. if (AVrfpDeadlockGlobals->NodesSearched >= AVrfpDeadlockGlobals->SearchedNodesLimit) {
  885. AVrfpDeadlockGlobals->SearchLimitHits += 1;
  886. return FALSE;
  887. }
  888. //
  889. // Check if AcquiredNode's resource equals ResourceAddress.
  890. // This is the final point for a deadlock detection because
  891. // we managed to find a path in the graph that leads us to the
  892. // same resource as the one to be acquired. From now on we
  893. // will start returning from recursive calls and build the
  894. // deadlock proof along the way.
  895. //
  896. ASSERT (AcquiredNode->Root);
  897. if (ResourceAddress == AcquiredNode->Root->ResourceAddress) {
  898. if (AcquiredNode->ReleasedOutOfOrder == 0) {
  899. ASSERT (FALSE == FirstCall);
  900. FoundDeadlock = TRUE;
  901. AVrfpDeadlockAddParticipant (AcquiredNode);
  902. goto Exit;
  903. }
  904. }
  905. //
  906. // Iterate all nodes in the graph using the same resource from AcquiredNode.
  907. //
  908. FoundDeadlock = FALSE;
  909. CurrentResource = AcquiredNode->Root;
  910. Current = CurrentResource->ResourceList.Flink;
  911. while (Current != &(CurrentResource->ResourceList)) {
  912. CurrentNode = CONTAINING_RECORD (Current,
  913. AVRF_DEADLOCK_NODE,
  914. ResourceList);
  915. ASSERT (CurrentNode->Root);
  916. ASSERT (CurrentNode->Root == CurrentResource);
  917. //
  918. // Mark node as visited
  919. //
  920. CurrentNode->SequenceNumber = AVrfpDeadlockGlobals->SequenceNumber;
  921. //
  922. // Check recursively the parent of the CurrentNode. This will check the
  923. // whole parent chain eventually through recursive calls.
  924. //
  925. CurrentParent = CurrentNode->Parent;
  926. if (CurrentParent != NULL) {
  927. //
  928. // If we are traversing the Parent chain of AcquiredNode we do not
  929. // increment the recursion Degree because we know the chain will
  930. // end. For calls to other similar nodes we have to protect against
  931. // too much recursion (time consuming).
  932. //
  933. if (CurrentNode != AcquiredNode) {
  934. //
  935. // Recurse across the graph
  936. //
  937. FoundDeadlock = AVrfpDeadlockAnalyze (ResourceAddress,
  938. CurrentParent,
  939. FALSE,
  940. Degree + 1);
  941. }
  942. else {
  943. //
  944. // Recurse down the graph
  945. //
  946. FoundDeadlock = AVrfpDeadlockAnalyze (ResourceAddress,
  947. CurrentParent,
  948. FALSE,
  949. Degree);
  950. }
  951. if (FoundDeadlock) {
  952. //
  953. // Here we might skip adding a node that was released out of order.
  954. // This will make cycle reporting cleaner but it will be more
  955. // difficult to understand the actual issue. So we will pass
  956. // for now.
  957. //
  958. AVrfpDeadlockAddParticipant(CurrentNode);
  959. if (CurrentNode != AcquiredNode) {
  960. AVrfpDeadlockAddParticipant(AcquiredNode);
  961. }
  962. goto Exit;
  963. }
  964. }
  965. Current = Current->Flink;
  966. }
  967. Exit:
  968. if (FoundDeadlock && FirstCall) {
  969. //
  970. // Make sure that the deadlock does not look like ABC - ACB.
  971. // These sequences are protected by a common resource and therefore
  972. // this is not a real deadlock.
  973. //
  974. if (AVrfpDeadlockCertify ()) {
  975. //
  976. // Print deadlock information and save the address so the
  977. // debugger knows who caused the deadlock.
  978. //
  979. AVrfpDeadlockGlobals->Instigator = ResourceAddress;
  980. DbgPrint("****************************************************************************\n");
  981. DbgPrint("** **\n");
  982. DbgPrint("** Potential deadlock detected! **\n");
  983. DbgPrint("** Type !avrf -dlck in the debugger for more information. **\n");
  984. DbgPrint("** **\n");
  985. DbgPrint("****************************************************************************\n");
  986. AVrfpDeadlockReportIssue (AVRF_DEADLOCK_ISSUE_DEADLOCK_DETECTED,
  987. (ULONG_PTR)ResourceAddress,
  988. (ULONG_PTR)AcquiredNode,
  989. 0);
  990. //
  991. // It is impossible to continue at this point.
  992. //
  993. return FALSE;
  994. }
  995. else {
  996. //
  997. // If we decided that this was not a deadlock after all, set the return value
  998. // to not return a deadlock
  999. //
  1000. FoundDeadlock = FALSE;
  1001. }
  1002. }
  1003. if (FirstCall) {
  1004. if (AVrfpDeadlockGlobals->NodesSearched > AVrfpDeadlockGlobals->MaxNodesSearched) {
  1005. AVrfpDeadlockGlobals->MaxNodesSearched = AVrfpDeadlockGlobals->NodesSearched;
  1006. }
  1007. }
  1008. return FoundDeadlock;
  1009. }
  1010. BOOLEAN
  1011. AVrfpDeadlockCertify(
  1012. VOID
  1013. )
  1014. /*++
  1015. Routine Description:
  1016. A potential deadlock has been detected. However our algorithm will generate
  1017. false positives in a certain case -- if two deadlocking nodes are ever taken
  1018. after the same node -- i.e. A->B->C A->C->B. While this can be considered
  1019. bad programming practice it is not really a deadlock and we should not
  1020. bugcheck.
  1021. Also we must check to make sure that there are no nodes at the top of the
  1022. deadlock chains that have only been acquired with try-acquire... this does
  1023. not cause a real deadlock.
  1024. The deadlock database lock should be held.
  1025. Arguments:
  1026. None.
  1027. Return Value:
  1028. True if this is really a deadlock, false to exonerate.
  1029. --*/
  1030. {
  1031. PAVRF_DEADLOCK_NODE innerNode,outerNode;
  1032. ULONG innerParticipant,outerParticipant;
  1033. ULONG numberOfParticipants;
  1034. ULONG currentParticipant;
  1035. numberOfParticipants = AVrfpDeadlockGlobals->NumberOfParticipants;
  1036. //
  1037. // Note -- this isn't a particularly efficient way to do this. However,
  1038. // it is a particularly easy way to do it. This function should be called
  1039. // extremely rarely -- so IMO there isn't really a problem here.
  1040. //
  1041. //
  1042. // Outer loop
  1043. //
  1044. outerParticipant = numberOfParticipants;
  1045. while (outerParticipant > 1) {
  1046. outerParticipant--;
  1047. for (outerNode = AVrfpDeadlockGlobals->Participant[outerParticipant]->Parent;
  1048. outerNode != NULL;
  1049. outerNode = outerNode->Parent ) {
  1050. //
  1051. // Inner loop
  1052. //
  1053. innerParticipant = outerParticipant-1;
  1054. while (innerParticipant) {
  1055. innerParticipant--;
  1056. for (innerNode = AVrfpDeadlockGlobals->Participant[innerParticipant]->Parent;
  1057. innerNode != NULL;
  1058. innerNode = innerNode->Parent) {
  1059. if (innerNode->Root->ResourceAddress == outerNode->Root->ResourceAddress) {
  1060. //
  1061. // The twain shall meet -- this is not a deadlock
  1062. //
  1063. AVrfpDeadlockGlobals->ABC_ACB_Skipped++;
  1064. return FALSE;
  1065. }
  1066. }
  1067. }
  1068. }
  1069. }
  1070. for (currentParticipant = 1; currentParticipant < numberOfParticipants; currentParticipant += 1) {
  1071. if (AVrfpDeadlockGlobals->Participant[currentParticipant]->Root->ResourceAddress ==
  1072. AVrfpDeadlockGlobals->Participant[currentParticipant-1]->Root->ResourceAddress) {
  1073. //
  1074. // This is the head of a chain...
  1075. //
  1076. if (AVrfpDeadlockGlobals->Participant[currentParticipant-1]->OnlyTryAcquireUsed == TRUE) {
  1077. //
  1078. // Head of a chain used only try acquire. This can never cause a deadlock.
  1079. //
  1080. return FALSE;
  1081. }
  1082. }
  1083. }
  1084. return TRUE;
  1085. }
  1086. /////////////////////////////////////////////////////////////////////
  1087. ///////////////////////////////////////////////// Resource management
  1088. /////////////////////////////////////////////////////////////////////
  1089. PAVRF_DEADLOCK_RESOURCE
  1090. AVrfpDeadlockSearchResource(
  1091. IN PVOID ResourceAddress
  1092. )
  1093. /*++
  1094. Routine Description:
  1095. This routine finds the resource descriptor structure for a
  1096. resource if one exists.
  1097. Arguments:
  1098. ResourceAddress: Address of the resource in question (as used by
  1099. the kernel).
  1100. Return Value:
  1101. PAVRF_DEADLOCK_RESOURCE structure describing the resource, if available,
  1102. or else NULL
  1103. Note. The caller of the function should hold the database lock.
  1104. --*/
  1105. {
  1106. PLIST_ENTRY ListHead;
  1107. PLIST_ENTRY Current;
  1108. PAVRF_DEADLOCK_RESOURCE Resource;
  1109. ListHead = AVrfpDeadlockDatabaseHash (AVrfpDeadlockGlobals->ResourceDatabase,
  1110. ResourceAddress);
  1111. if (IsListEmpty (ListHead)) {
  1112. return NULL;
  1113. }
  1114. //
  1115. // Trim resources from this hash list. It has nothing to do with searching
  1116. // but it is a good place to do this operation.
  1117. //
  1118. AVrfpDeadlockTrimResources (ListHead);
  1119. //
  1120. // Now search the bucket for our resource.
  1121. //
  1122. Current = ListHead->Flink;
  1123. while (Current != ListHead) {
  1124. Resource = CONTAINING_RECORD(Current,
  1125. AVRF_DEADLOCK_RESOURCE,
  1126. HashChainList);
  1127. if (Resource->ResourceAddress == ResourceAddress) {
  1128. return Resource;
  1129. }
  1130. Current = Current->Flink;
  1131. }
  1132. return NULL;
  1133. }
  1134. BOOLEAN
  1135. AVrfpDeadlockResourceInitialize(
  1136. IN PVOID Resource,
  1137. IN AVRF_DEADLOCK_RESOURCE_TYPE Type,
  1138. IN PVOID Caller
  1139. )
  1140. /*++
  1141. Routine Description:
  1142. This routine adds an entry for a new resource to our deadlock detection
  1143. database.
  1144. Arguments:
  1145. Resource: Address of the resource in question as used by the kernel.
  1146. Type: Type of the resource.
  1147. Caller: address of the caller
  1148. DoNotAcquireLock: if true it means the call is done internally and the
  1149. deadlock verifier lock is already held.
  1150. Return Value:
  1151. True if we created and initialized a new RESOURCE structure.
  1152. --*/
  1153. {
  1154. PVOID ReservedResource;
  1155. BOOLEAN Result;
  1156. //
  1157. // If we are not initialized or package is not enabled
  1158. // we return immediately.
  1159. //
  1160. if (! AVrfpDeadlockCanProceed()) {
  1161. return FALSE;
  1162. }
  1163. // silviuc: I do not need all this gymnastics with allocations out of locks.
  1164. ReservedResource = AVrfpDeadlockAllocate (AVrfpDeadlockResource);
  1165. AVrfpDeadlockDetectionLock ();
  1166. Result = AVrfpDeadlockAddResource (Resource,
  1167. Type,
  1168. Caller,
  1169. ReservedResource);
  1170. AVrfpDeadlockDetectionUnlock ();
  1171. return Result;
  1172. }
  1173. BOOLEAN
  1174. AVrfpDeadlockAddResource(
  1175. IN PVOID Resource,
  1176. IN AVRF_DEADLOCK_RESOURCE_TYPE Type,
  1177. IN PVOID Caller,
  1178. IN PVOID ReservedResource
  1179. )
  1180. /*++
  1181. Routine Description:
  1182. This routine adds an entry for a new resource to our deadlock detection
  1183. database.
  1184. Arguments:
  1185. Resource: Address of the resource in question as used by the kernel.
  1186. Type: Type of the resource.
  1187. Caller: address of the caller
  1188. ReservedResource: block of memory to be used by the new resource.
  1189. Return Value:
  1190. True if we created and initialized a new RESOURCE structure.
  1191. --*/
  1192. {
  1193. PLIST_ENTRY HashBin;
  1194. PAVRF_DEADLOCK_RESOURCE ResourceRoot;
  1195. ULONG HashValue;
  1196. ULONG DeadlockFlags;
  1197. BOOLEAN ReturnValue = FALSE;
  1198. //
  1199. // Check if this resource was initialized before.
  1200. // This would be a bug in most of the cases.
  1201. //
  1202. ResourceRoot = AVrfpDeadlockSearchResource (Resource);
  1203. if (ResourceRoot) {
  1204. DeadlockFlags = AVrfpDeadlockResourceTypeInfo[Type];
  1205. //
  1206. // Check if we are reinitializing a good resource.
  1207. //
  1208. AVrfpDeadlockReportIssue (AVRF_DEADLOCK_ISSUE_MULTIPLE_INITIALIZATION,
  1209. (ULONG_PTR)Resource,
  1210. (ULONG_PTR)ResourceRoot,
  1211. 0);
  1212. ReturnValue = TRUE;
  1213. goto Exit;
  1214. }
  1215. //
  1216. // At this point we know for sure the resource is not represented in the
  1217. // deadlock verifier database.
  1218. //
  1219. ASSERT (AVrfpDeadlockSearchResource (Resource) == NULL);
  1220. //
  1221. // Use reserved memory for the new resource.
  1222. // Set ReservedResource to null to signal that memory has
  1223. // been used. This will prevent freeing it at the end.
  1224. //
  1225. ResourceRoot = ReservedResource;
  1226. ReservedResource = NULL;
  1227. if (ResourceRoot == NULL) {
  1228. ReturnValue = FALSE;
  1229. goto Exit;
  1230. }
  1231. //
  1232. // Fill information about resource.
  1233. //
  1234. RtlZeroMemory (ResourceRoot, sizeof(AVRF_DEADLOCK_RESOURCE));
  1235. ResourceRoot->Type = Type;
  1236. ResourceRoot->ResourceAddress = Resource;
  1237. InitializeListHead (&ResourceRoot->ResourceList);
  1238. //
  1239. // Capture the stack trace of the guy that creates the resource first.
  1240. // This should happen when resource gets initialized or during the first
  1241. // acquire.
  1242. //
  1243. RtlCaptureStackBackTrace (2,
  1244. MAX_TRACE_DEPTH,
  1245. ResourceRoot->StackTrace,
  1246. &HashValue);
  1247. ResourceRoot->StackTrace[0] = Caller;
  1248. //
  1249. // Figure out which hash bin this resource corresponds to.
  1250. //
  1251. HashBin = AVrfpDeadlockDatabaseHash (AVrfpDeadlockGlobals->ResourceDatabase, Resource);
  1252. //
  1253. // Now add to the corresponding hash bin
  1254. //
  1255. InsertHeadList(HashBin, &ResourceRoot->HashChainList);
  1256. ReturnValue = TRUE;
  1257. Exit:
  1258. if (ReservedResource) {
  1259. AVrfpDeadlockFree (ReservedResource, AVrfpDeadlockResource);
  1260. }
  1261. return ReturnValue;
  1262. }
  1263. BOOLEAN
  1264. AVrfpDeadlockSimilarNode (
  1265. IN PVOID Resource,
  1266. IN BOOLEAN TryNode,
  1267. IN PAVRF_DEADLOCK_NODE Node
  1268. )
  1269. /*++
  1270. Routine description:
  1271. This routine determines if an acquisition with the (resource, try)
  1272. characteristics is already represented in the Node parameter.
  1273. We used to match nodes based on (resource, thread, stack trace, try)
  1274. 4-tuplet but this really causes an explosion in the number of nodes.
  1275. Such a method would yield more accurate proofs but does not affect
  1276. the correctness of the deadlock detection algorithms.
  1277. Return value:
  1278. True if similar node.
  1279. --*/
  1280. {
  1281. ASSERT (Node);
  1282. ASSERT (Node->Root);
  1283. if (Resource == Node->Root->ResourceAddress
  1284. && TryNode == Node->OnlyTryAcquireUsed) {
  1285. //
  1286. // Second condition is important to keep nodes for TryAcquire operations
  1287. // separated from normal acquires. A TryAcquire cannot cause a deadlock
  1288. // and therefore we have to be careful not to report bogus deadlocks.
  1289. //
  1290. return TRUE;
  1291. }
  1292. else {
  1293. return FALSE;
  1294. }
  1295. }
  1296. VOID
  1297. AVrfpDeadlockAcquireResource (
  1298. IN PVOID Resource,
  1299. IN AVRF_DEADLOCK_RESOURCE_TYPE Type,
  1300. IN HANDLE Thread,
  1301. IN BOOLEAN TryAcquire,
  1302. IN PVOID Caller
  1303. )
  1304. /*++
  1305. Routine Description:
  1306. This routine makes sure that it is ok to acquire the resource without
  1307. causing a deadlock. It will also update the resource graph with the new
  1308. resource acquisition.
  1309. Arguments:
  1310. Resource: Address of the resource in question as used by kernel.
  1311. Type: Type of the resource.
  1312. Thread: thread attempting to acquire the resource
  1313. TryAcquire: true if this is a tryacquire() operation
  1314. Caller: address of the caller
  1315. Return Value:
  1316. None.
  1317. --*/
  1318. {
  1319. HANDLE CurrentThread;
  1320. PAVRF_DEADLOCK_THREAD ThreadEntry;
  1321. PAVRF_DEADLOCK_NODE CurrentNode;
  1322. PAVRF_DEADLOCK_NODE NewNode;
  1323. PAVRF_DEADLOCK_RESOURCE ResourceRoot;
  1324. PLIST_ENTRY Current;
  1325. ULONG HashValue;
  1326. ULONG DeadlockFlags;
  1327. BOOLEAN CreatingRootNode = FALSE;
  1328. BOOLEAN ThreadCreated = FALSE;
  1329. BOOLEAN AddResult;
  1330. PVOID ReservedThread;
  1331. PVOID ReservedNode;
  1332. PVOID ReservedResource;
  1333. PAVRF_DEADLOCK_NODE ThreadCurrentNode;
  1334. CurrentNode = NULL;
  1335. ThreadEntry = NULL;
  1336. ThreadCurrentNode = NULL;
  1337. //
  1338. // If we are not initialized or package is not enabled
  1339. // we return immediately.
  1340. //
  1341. if (! AVrfpDeadlockCanProceed()) {
  1342. return;
  1343. }
  1344. CurrentThread = Thread;
  1345. DeadlockFlags = AVrfpDeadlockResourceTypeInfo[Type];
  1346. //
  1347. // Before getting into the real stuff trim the pool cache.
  1348. // This needs to happen out of any locks.
  1349. //
  1350. AVrfpDeadlockTrimPoolCache ();
  1351. //
  1352. // Reserve resources that might be needed. If upon exit these
  1353. // variables are null it means the allocation either failed or was used.
  1354. // In both cases we do not need to free anything.
  1355. //
  1356. ReservedThread = AVrfpDeadlockAllocate (AVrfpDeadlockThread);
  1357. ReservedNode = AVrfpDeadlockAllocate (AVrfpDeadlockNode);
  1358. ReservedResource = AVrfpDeadlockAllocate (AVrfpDeadlockResource);
  1359. //
  1360. // Lock the deadlock database.
  1361. //
  1362. AVrfpDeadlockDetectionLock();
  1363. //
  1364. // Allocate a node that might be needed. If we will not use it
  1365. // we will deallocate it at the end. If we fail to allocate
  1366. // we will return immediately.
  1367. //
  1368. NewNode = ReservedNode;
  1369. ReservedNode = NULL;
  1370. if (NewNode == NULL) {
  1371. goto Exit;
  1372. }
  1373. //
  1374. // Find the thread descriptor. If there is none we will create one.
  1375. //
  1376. ThreadEntry = AVrfpDeadlockSearchThread (CurrentThread);
  1377. if (ThreadEntry == NULL) {
  1378. ThreadEntry = AVrfpDeadlockAddThread (CurrentThread, ReservedThread);
  1379. ReservedThread = NULL;
  1380. if (ThreadEntry == NULL) {
  1381. //
  1382. // If we cannot allocate a new thread entry then
  1383. // no deadlock detection will happen.
  1384. //
  1385. goto Exit;
  1386. }
  1387. ThreadCreated = TRUE;
  1388. }
  1389. #if DBG
  1390. if (ThreadEntry->CurrentTopNode != NULL) {
  1391. ASSERT(ThreadEntry->CurrentTopNode->Root->ThreadOwner == ThreadEntry);
  1392. ASSERT(ThreadEntry->CurrentTopNode->ThreadEntry == ThreadEntry);
  1393. ASSERT(ThreadEntry->NodeCount != 0);
  1394. ASSERT(ThreadEntry->CurrentTopNode->Active != 0);
  1395. ASSERT(ThreadEntry->CurrentTopNode->Root->NodeCount != 0);
  1396. }
  1397. #endif
  1398. //
  1399. // Find the resource descriptor. If we do not find a descriptor
  1400. // we will create one on the fly.
  1401. //
  1402. ResourceRoot = AVrfpDeadlockSearchResource (Resource);
  1403. if (ResourceRoot == NULL) {
  1404. //
  1405. // Complain about the resource not being initialized. After that
  1406. // in order to continue we initialize a resource.
  1407. //
  1408. AVrfpDeadlockReportIssue (AVRF_DEADLOCK_ISSUE_UNINITIALIZED_RESOURCE,
  1409. (ULONG_PTR) Resource,
  1410. (ULONG_PTR) NULL,
  1411. (ULONG_PTR) NULL);
  1412. AddResult = AVrfpDeadlockAddResource (Resource,
  1413. Type,
  1414. Caller,
  1415. ReservedResource);
  1416. ReservedResource = NULL;
  1417. if (AddResult == FALSE) {
  1418. //
  1419. // If we failed to add the resource then no deadlock detection.
  1420. //
  1421. if (ThreadCreated) {
  1422. AVrfpDeadlockDeleteThread (ThreadEntry, FALSE);
  1423. }
  1424. goto Exit;
  1425. }
  1426. //
  1427. // Search again the resource. This time we should find it.
  1428. //
  1429. ResourceRoot = AVrfpDeadlockSearchResource (Resource);
  1430. }
  1431. //
  1432. // At this point we have a THREAD and a RESOURCE to play with.
  1433. // In addition we are just about to acquire the resource which means
  1434. // there should not be another thread owning unless it is a recursive
  1435. // acquisition.
  1436. //
  1437. ASSERT (ResourceRoot);
  1438. ASSERT (ThreadEntry);
  1439. ThreadCurrentNode = ThreadEntry->CurrentTopNode;
  1440. //
  1441. // silviuc: update comment and maybe break?
  1442. // Since we just acquired the resource the valid value for ThreadOwner is
  1443. // null or ThreadEntry (for a recursive acquisition). This might not be
  1444. // true if we missed a release() from an unverified driver. So we will
  1445. // not complain about it. We will just put the resource in a consistent
  1446. // state and continue;
  1447. //
  1448. if (ResourceRoot->ThreadOwner) {
  1449. if (ResourceRoot->ThreadOwner != ThreadEntry) {
  1450. ResourceRoot->RecursionCount = 0;
  1451. }
  1452. else {
  1453. ASSERT (ResourceRoot->RecursionCount > 0);
  1454. }
  1455. }
  1456. else {
  1457. ASSERT (ResourceRoot->RecursionCount == 0);
  1458. }
  1459. ResourceRoot->ThreadOwner = ThreadEntry;
  1460. ResourceRoot->RecursionCount += 1;
  1461. //
  1462. // Check if thread holds any resources. If it does we will have to determine
  1463. // at that local point in the dependency graph if we need to create a
  1464. // new node. If this is the first resource acquired by the thread we need
  1465. // to create a new root node or reuse one created in the past.
  1466. //
  1467. if (ThreadCurrentNode != NULL) {
  1468. //
  1469. // If we get here, the current thread had already acquired resources.
  1470. // Check to see if this resource has already been acquired.
  1471. //
  1472. if (ResourceRoot->RecursionCount > 1) {
  1473. //
  1474. // Recursive acquisition is OK for some resources...
  1475. //
  1476. if ((DeadlockFlags & AVRF_DEADLOCK_FLAG_RECURSIVE_ACQUISITION_OK) != 0) {
  1477. //
  1478. // Recursion can't cause a deadlock. Don't set CurrentNode
  1479. // since we don't want to move any pointers.
  1480. //
  1481. goto Exit;
  1482. }
  1483. else {
  1484. //
  1485. // This is a recursive acquire for a resource type that is not allowed
  1486. // to acquire recursively. Note on continuing from here: we have a recursion
  1487. // count of two which will come in handy when the resources are released.
  1488. //
  1489. AVrfpDeadlockReportIssue (AVRF_DEADLOCK_ISSUE_SELF_DEADLOCK,
  1490. (ULONG_PTR)Resource,
  1491. (ULONG_PTR)ResourceRoot,
  1492. (ULONG_PTR)ThreadEntry);
  1493. goto Exit;
  1494. }
  1495. }
  1496. //
  1497. // If link already exists, update pointers and exit.
  1498. // otherwise check for deadlocks and create a new node
  1499. //
  1500. Current = ThreadCurrentNode->ChildrenList.Flink;
  1501. while (Current != &(ThreadCurrentNode->ChildrenList)) {
  1502. CurrentNode = CONTAINING_RECORD (Current,
  1503. AVRF_DEADLOCK_NODE,
  1504. SiblingsList);
  1505. Current = Current->Flink;
  1506. if (AVrfpDeadlockSimilarNode (Resource, TryAcquire, CurrentNode)) {
  1507. //
  1508. // We have found a link. A link that already exists doesn't have
  1509. // to be checked for a deadlock because it would have been caught
  1510. // when the link was created in the first place. We can just update
  1511. // the pointers to reflect the new resource acquired and exit.
  1512. //
  1513. // We apply our graph compression function to minimize duplicates.
  1514. //
  1515. AVrfpDeadlockCheckDuplicatesAmongChildren (ThreadCurrentNode,
  1516. CurrentNode);
  1517. goto Exit;
  1518. }
  1519. }
  1520. //
  1521. // Now we know that we're in it for the long haul. We must create a new
  1522. // link and make sure that it doesn't cause a deadlock. Later in the
  1523. // function CurrentNode being null will signify that we need to create
  1524. // a new node.
  1525. //
  1526. CurrentNode = NULL;
  1527. //
  1528. // We will analyze deadlock if the resource just about to be acquired
  1529. // was acquired before and there are nodes in the graph for the
  1530. // resource. Try acquire can not be the cause of a deadlock.
  1531. // Don't analyze on try acquires.
  1532. //
  1533. if (ResourceRoot->NodeCount > 0 && TryAcquire == FALSE) {
  1534. if (AVrfpDeadlockAnalyze (Resource, ThreadCurrentNode, TRUE, 0)) {
  1535. //
  1536. // If we are here we detected deadlock. The analyze() function
  1537. // does all the reporting. Being here means we hit `g' in the
  1538. // debugger. We will just exit and do not add this resource
  1539. // to the graph.
  1540. //
  1541. goto Exit;
  1542. }
  1543. }
  1544. }
  1545. else {
  1546. //
  1547. // Thread does not have any resources acquired. We have to figure out
  1548. // if this is a scenario we have encountered in the past by looking
  1549. // at all nodes (that are roots) for the resource to be acquired.
  1550. // Note that all this is bookkeeping but we cannot encounter a deadlock
  1551. // from now on.
  1552. //
  1553. PLIST_ENTRY CurrentListEntry;
  1554. PAVRF_DEADLOCK_NODE Node = NULL;
  1555. BOOLEAN FoundNode = FALSE;
  1556. CurrentListEntry = ResourceRoot->ResourceList.Flink;
  1557. while (CurrentListEntry != &(ResourceRoot->ResourceList)) {
  1558. Node = CONTAINING_RECORD (CurrentListEntry,
  1559. AVRF_DEADLOCK_NODE,
  1560. ResourceList);
  1561. CurrentListEntry = Node->ResourceList.Flink;
  1562. if (Node->Parent == NULL) {
  1563. if (AVrfpDeadlockSimilarNode (Resource, TryAcquire, Node)) {
  1564. //
  1565. // We apply our graph compression function to minimize duplicates.
  1566. //
  1567. AVrfpDeadlockCheckDuplicatesAmongRoots (Node);
  1568. FoundNode = TRUE;
  1569. break;
  1570. }
  1571. }
  1572. }
  1573. if (FoundNode) {
  1574. CurrentNode = Node;
  1575. goto Exit;
  1576. }
  1577. else {
  1578. CreatingRootNode = TRUE;
  1579. }
  1580. }
  1581. //
  1582. // At this moment we know for sure the new link will not cause
  1583. // a deadlock. We will create the new resource node.
  1584. //
  1585. if (NewNode != NULL) {
  1586. CurrentNode = NewNode;
  1587. //
  1588. // Set newnode to NULL to signify it has been used -- otherwise it
  1589. // will get freed at the end of this function.
  1590. //
  1591. NewNode = NULL;
  1592. //
  1593. // Initialize the new resource node
  1594. //
  1595. RtlZeroMemory (CurrentNode, sizeof *CurrentNode);
  1596. CurrentNode->Active = 0;
  1597. CurrentNode->Parent = ThreadCurrentNode;
  1598. CurrentNode->Root = ResourceRoot;
  1599. CurrentNode->SequenceNumber = AVrfpDeadlockGlobals->SequenceNumber;
  1600. InitializeListHead (&(CurrentNode->ChildrenList));
  1601. //
  1602. // Mark the TryAcquire type of the node.
  1603. //
  1604. CurrentNode->OnlyTryAcquireUsed = TryAcquire;
  1605. //
  1606. // Add to the children list of the parent.
  1607. //
  1608. if (! CreatingRootNode) {
  1609. InsertHeadList(&(ThreadCurrentNode->ChildrenList),
  1610. &(CurrentNode->SiblingsList));
  1611. }
  1612. //
  1613. // Register the new resource node in the list of nodes maintained
  1614. // for this resource.
  1615. //
  1616. InsertHeadList(&(ResourceRoot->ResourceList),
  1617. &(CurrentNode->ResourceList));
  1618. ResourceRoot->NodeCount += 1;
  1619. if (ResourceRoot->NodeCount > 0xFFF0) {
  1620. AVrfpDeadlockState.ResourceNodeCountOverflow = 1;
  1621. }
  1622. //
  1623. // Add to the graph statistics.
  1624. //
  1625. {
  1626. ULONG Level;
  1627. Level = AVrfpDeadlockNodeLevel (CurrentNode);
  1628. if (Level < 8) {
  1629. AVrfpDeadlockGlobals->GraphNodes[Level] += 1;
  1630. }
  1631. }
  1632. }
  1633. //
  1634. // Exit point.
  1635. //
  1636. Exit:
  1637. //
  1638. // Add information we use to identify the culprit should
  1639. // a deadlock occur
  1640. //
  1641. if (CurrentNode) {
  1642. ASSERT (ThreadEntry);
  1643. ASSERT (ThreadCurrentNode == CurrentNode->Parent);
  1644. CurrentNode->Active = 1;
  1645. //
  1646. // The node should have thread entry field null either because
  1647. // it was newly created or because the node was released in the
  1648. // past and therefore the field was zeroed.
  1649. //
  1650. // silviuc: true? What about if we miss release() operations.
  1651. //
  1652. ASSERT (CurrentNode->ThreadEntry == NULL);
  1653. CurrentNode->ThreadEntry = ThreadEntry;
  1654. ThreadEntry->CurrentTopNode = CurrentNode;
  1655. ThreadEntry->NodeCount += 1;
  1656. if (ThreadEntry->NodeCount <= 8) {
  1657. AVrfpDeadlockGlobals->NodeLevelCounter[ThreadEntry->NodeCount - 1] += 1;
  1658. }
  1659. else {
  1660. AVrfpDeadlockGlobals->NodeLevelCounter[7] += 1;
  1661. }
  1662. //
  1663. // If we have a parent, save the parent's stack trace
  1664. //
  1665. if (CurrentNode->Parent) {
  1666. RtlCopyMemory(CurrentNode->ParentStackTrace,
  1667. CurrentNode->Parent->StackTrace,
  1668. sizeof (CurrentNode->ParentStackTrace));
  1669. }
  1670. //
  1671. // Capture stack trace for the current acquire.
  1672. //
  1673. RtlCaptureStackBackTrace (2,
  1674. MAX_TRACE_DEPTH,
  1675. CurrentNode->StackTrace,
  1676. &HashValue);
  1677. if (CurrentNode->Parent) {
  1678. CurrentNode->ParentStackTrace[0] = CurrentNode->Parent->StackTrace[0];
  1679. }
  1680. CurrentNode->StackTrace[0] = Caller;
  1681. //
  1682. // Copy the trace for the last acquire in the resource object.
  1683. //
  1684. RtlCopyMemory (CurrentNode->Root->LastAcquireTrace,
  1685. CurrentNode->StackTrace,
  1686. sizeof (CurrentNode->Root->LastAcquireTrace));
  1687. }
  1688. //
  1689. // We allocated space for a new node but it didn't get used -- put it back
  1690. // in the list (don't worry this doesn't do a real 'free' it just puts it
  1691. // in a free list).
  1692. //
  1693. if (NewNode != NULL) {
  1694. AVrfpDeadlockFree (NewNode, AVrfpDeadlockNode);
  1695. }
  1696. //
  1697. // Free up unused reserved resources.
  1698. // Release deadlock database and return.
  1699. //
  1700. if (ReservedResource) {
  1701. AVrfpDeadlockFree (ReservedResource, AVrfpDeadlockResource);
  1702. }
  1703. if (ReservedNode) {
  1704. AVrfpDeadlockFree (ReservedNode, AVrfpDeadlockNode);
  1705. }
  1706. if (ReservedThread) {
  1707. AVrfpDeadlockFree (ReservedThread, AVrfpDeadlockThread);
  1708. }
  1709. AVrfpDeadlockDetectionUnlock();
  1710. return;
  1711. }
  1712. VOID
  1713. AVrfpDeadlockReleaseResource(
  1714. IN PVOID Resource,
  1715. IN AVRF_DEADLOCK_RESOURCE_TYPE Type,
  1716. IN HANDLE Thread,
  1717. IN PVOID Caller
  1718. )
  1719. /*++
  1720. Routine Description:
  1721. This routine does the maintenance necessary to release resources from our
  1722. deadlock detection database.
  1723. Arguments:
  1724. Resource: Address of the resource in question.
  1725. Thread: thread releasing the resource. In most of the cases this is the
  1726. current thread but it might be different for resources that can be
  1727. acquired in one thread and released in another one.
  1728. Caller: address of the caller of release()
  1729. Return Value:
  1730. None.
  1731. --*/
  1732. {
  1733. HANDLE CurrentThread;
  1734. PAVRF_DEADLOCK_THREAD ThreadEntry;
  1735. PAVRF_DEADLOCK_RESOURCE ResourceRoot;
  1736. PAVRF_DEADLOCK_NODE ReleasedNode;
  1737. ULONG HashValue;
  1738. PAVRF_DEADLOCK_NODE ThreadCurrentNode;
  1739. UNREFERENCED_PARAMETER (Caller);
  1740. UNREFERENCED_PARAMETER (Type);
  1741. //
  1742. // If we aren't initialized or package is not enabled
  1743. // we return immediately.
  1744. //
  1745. if (! AVrfpDeadlockCanProceed()) {
  1746. return;
  1747. }
  1748. ReleasedNode = NULL;
  1749. CurrentThread = Thread;
  1750. ThreadEntry = NULL;
  1751. AVrfpDeadlockDetectionLock();
  1752. ResourceRoot = AVrfpDeadlockSearchResource (Resource);
  1753. if (ResourceRoot == NULL) {
  1754. // silviuc: we should report an issue. It cannot happen in u-mode.
  1755. //
  1756. // Release called with a resource address that was never
  1757. // stored in our resource database. This can happen in
  1758. // the following circumstances:
  1759. //
  1760. // (a) resource is released but we never seen it before
  1761. // because it was acquired in an unverified driver.
  1762. //
  1763. // (b) we have encountered allocation failures that prevented
  1764. // us from completing an acquire() or initialize().
  1765. //
  1766. // All are legitimate cases and therefore we just ignore the
  1767. // release operation.
  1768. //
  1769. goto Exit;
  1770. }
  1771. //
  1772. // Check if we are trying to release a resource that was never
  1773. // acquired.
  1774. //
  1775. if (ResourceRoot->RecursionCount == 0) {
  1776. AVrfpDeadlockReportIssue (AVRF_DEADLOCK_ISSUE_UNACQUIRED_RESOURCE,
  1777. (ULONG_PTR)Resource,
  1778. (ULONG_PTR)ResourceRoot,
  1779. (ULONG_PTR)AVrfpDeadlockSearchThread(CurrentThread));
  1780. goto Exit;
  1781. }
  1782. //
  1783. // Look for this thread in our thread list. Note we are looking actually
  1784. // for the thread that acquired the resource -- not the current one
  1785. // It should, in fact be the current one, but if the resource is being released
  1786. // in a different thread from the one it was acquired in, we need the original.
  1787. //
  1788. ASSERT (ResourceRoot->RecursionCount > 0);
  1789. ASSERT (ResourceRoot->ThreadOwner);
  1790. ThreadEntry = ResourceRoot->ThreadOwner;
  1791. if (ThreadEntry->Thread != CurrentThread) {
  1792. //
  1793. // silviuc: we have to report this. It is not allowed in U-mode.
  1794. //
  1795. // Someone acquired a resource that is released in another thread.
  1796. // This is bad design but we have to live with it.
  1797. //
  1798. // NB. If this occurrs, we may call a non-deadlock a deadlock.
  1799. // For example, we see a simple deadlock -- AB BA
  1800. // If another thread releases B, there won't actually
  1801. // be a deadlock. Kind of annoying and ugly.
  1802. //
  1803. #if DBG
  1804. DbgPrint("Thread %p acquired resource %p but thread %p released it\n",
  1805. ThreadEntry->Thread, Resource, CurrentThread );
  1806. AVrfpDeadlockReportIssue (AVRF_DEADLOCK_ISSUE_UNEXPECTED_THREAD,
  1807. (ULONG_PTR)Resource,
  1808. (ULONG_PTR)ThreadEntry->Thread,
  1809. (ULONG_PTR)CurrentThread
  1810. );
  1811. #endif
  1812. //
  1813. // If we don't want this to be fatal, in order to
  1814. // continue we must pretend that the current
  1815. // thread is the resource's owner.
  1816. //
  1817. CurrentThread = ThreadEntry->Thread;
  1818. }
  1819. //
  1820. // In this moment we have a resource (ResourceRoot) and a
  1821. // thread (ThreadEntry) to play with.
  1822. //
  1823. ThreadCurrentNode = ThreadEntry->CurrentTopNode;
  1824. ASSERT (ResourceRoot && ThreadEntry);
  1825. ASSERT (ThreadCurrentNode);
  1826. ASSERT (ThreadCurrentNode->Root);
  1827. ASSERT (ThreadEntry->NodeCount > 0);
  1828. ResourceRoot->RecursionCount -= 1;
  1829. if (ResourceRoot->RecursionCount > 0) {
  1830. //
  1831. // Just decrement the recursion count and do not change any state
  1832. //
  1833. goto Exit;
  1834. }
  1835. //
  1836. // Wipe out the resource owner.
  1837. //
  1838. ResourceRoot->ThreadOwner = NULL;
  1839. AVrfpDeadlockGlobals->TotalReleases += 1;
  1840. //
  1841. // Check for out of order releases
  1842. //
  1843. if (ThreadCurrentNode->Root != ResourceRoot) {
  1844. AVrfpDeadlockGlobals->OutOfOrderReleases += 1;
  1845. //
  1846. // Getting here means that somebody acquires a then b then tries
  1847. // to release a before b. This is bad for certain kinds of resources,
  1848. // and for others we have to look the other way.
  1849. //
  1850. if ((AVrfpDeadlockResourceTypeInfo[ThreadCurrentNode->Root->Type] &
  1851. AVRF_DEADLOCK_FLAG_REVERSE_RELEASE_OK) == 0) {
  1852. // silviuc: In u-mode is always allowed.
  1853. DbgPrint("Deadlock detection: Must release resources in reverse-order\n");
  1854. DbgPrint("Resource %p acquired before resource %p -- \n"
  1855. "Current thread (%p) is trying to release it first\n",
  1856. Resource,
  1857. ThreadCurrentNode->Root->ResourceAddress,
  1858. ThreadEntry);
  1859. AVrfpDeadlockReportIssue (AVRF_DEADLOCK_ISSUE_UNEXPECTED_RELEASE,
  1860. (ULONG_PTR)Resource,
  1861. (ULONG_PTR)ThreadCurrentNode->Root->ResourceAddress,
  1862. (ULONG_PTR)ThreadEntry);
  1863. }
  1864. //
  1865. // We need to mark the node for the out of order released resource as
  1866. // not active so that other threads will be able to acquire it.
  1867. //
  1868. {
  1869. PAVRF_DEADLOCK_NODE Current;
  1870. ASSERT (ThreadCurrentNode->Active == 1);
  1871. ASSERT (ThreadCurrentNode->ThreadEntry == ThreadEntry);
  1872. Current = ThreadCurrentNode;
  1873. while (Current != NULL) {
  1874. if (Current->Root == ResourceRoot) {
  1875. ASSERT (Current->Active == 1);
  1876. ASSERT (Current->Root->RecursionCount == 0);
  1877. ASSERT (Current->ThreadEntry == ThreadEntry);
  1878. Current->Active = 0;
  1879. ReleasedNode = Current;
  1880. break;
  1881. }
  1882. Current = Current->Parent;
  1883. }
  1884. if (Current == NULL) {
  1885. //
  1886. // If we do not manage to find an active node we must be in an
  1887. // weird state. The resource must be here or else we would have
  1888. // gotten an `unxpected release' bugcheck.
  1889. //
  1890. ASSERT (0);
  1891. }
  1892. else {
  1893. //
  1894. // Mark the fact that this node represents a resource
  1895. // that can be released out of order. This information is
  1896. // important while looking for cycles because this type of
  1897. // nodes cannot cause a deadlock.
  1898. //
  1899. if (Current->ReleasedOutOfOrder == 0) {
  1900. AVrfpDeadlockGlobals->NodesReleasedOutOfOrder += 1;
  1901. }
  1902. Current->ReleasedOutOfOrder = 1;
  1903. }
  1904. }
  1905. }
  1906. else {
  1907. //
  1908. // We need to release the top node held by the thread.
  1909. //
  1910. ASSERT (ThreadCurrentNode->Active);
  1911. ReleasedNode = ThreadCurrentNode;
  1912. ReleasedNode->Active = 0;
  1913. }
  1914. //
  1915. // Put the `CurrentNode' field of the thread in a consistent state.
  1916. // It should point to the most recent active node that it owns.
  1917. //
  1918. while (ThreadEntry->CurrentTopNode) {
  1919. if (ThreadEntry->CurrentTopNode->Active == 1) {
  1920. if (ThreadEntry->CurrentTopNode->ThreadEntry == ThreadEntry) {
  1921. break;
  1922. }
  1923. }
  1924. ThreadEntry->CurrentTopNode = ThreadEntry->CurrentTopNode->Parent;
  1925. }
  1926. Exit:
  1927. //
  1928. // Properly release the node if there is one to be released.
  1929. //
  1930. if (ReleasedNode) {
  1931. ASSERT (ReleasedNode->Active == 0);
  1932. ASSERT (ReleasedNode->Root->ThreadOwner == 0);
  1933. ASSERT (ReleasedNode->Root->RecursionCount == 0);
  1934. ASSERT (ReleasedNode->ThreadEntry == ThreadEntry);
  1935. ASSERT (ThreadEntry->NodeCount > 0);
  1936. ASSERT (ThreadEntry->CurrentTopNode != ReleasedNode);
  1937. ReleasedNode->ThreadEntry = NULL;
  1938. ThreadEntry->NodeCount -= 1;
  1939. #if DBG
  1940. AVrfpDeadlockCheckNodeConsistency (ReleasedNode, FALSE);
  1941. AVrfpDeadlockCheckResourceConsistency (ReleasedNode->Root, FALSE);
  1942. AVrfpDeadlockCheckThreadConsistency (ThreadEntry, FALSE);
  1943. #endif
  1944. if (ThreadEntry && ThreadEntry->NodeCount == 0) {
  1945. AVrfpDeadlockDeleteThread (ThreadEntry, FALSE);
  1946. }
  1947. //
  1948. // N.B. Since this is a root node with no children we can delete
  1949. // the node too. This would be important to keep memory low. A single node
  1950. // can never be the cause of a deadlock. However there are thousands of
  1951. // resources used like this and constantly creating and deleting them
  1952. // will create a bottleneck. So we prefer to keep them around.
  1953. //
  1954. #if 0
  1955. if (ReleasedNode->Parent == NULL && IsListEmpty(&(ReleasedNode->ChildrenList))) {
  1956. AVrfpDeadlockDeleteNode (ReleasedNode, FALSE);
  1957. AVrfpDeadlockGlobals->RootNodesDeleted += 1;
  1958. }
  1959. #endif
  1960. }
  1961. //
  1962. // Capture the trace for the last release in the resource object.
  1963. //
  1964. if (ResourceRoot) {
  1965. RtlCaptureStackBackTrace (2,
  1966. MAX_TRACE_DEPTH,
  1967. ResourceRoot->LastReleaseTrace,
  1968. &HashValue);
  1969. }
  1970. AVrfpDeadlockDetectionUnlock ();
  1971. }
  1972. /////////////////////////////////////////////////////////////////////
  1973. /////////////////////////////////////////////////// Thread management
  1974. /////////////////////////////////////////////////////////////////////
  1975. PAVRF_DEADLOCK_THREAD
  1976. AVrfpDeadlockSearchThread (
  1977. HANDLE Thread
  1978. )
  1979. /*++
  1980. Routine Description:
  1981. This routine searches for a thread in the thread database.
  1982. The function assumes the deadlock database lock is held.
  1983. Arguments:
  1984. Thread - thread address
  1985. Return Value:
  1986. Address of AVRF_DEADLOCK_THREAD structure if thread was found.
  1987. Null otherwise.
  1988. --*/
  1989. {
  1990. PLIST_ENTRY Current;
  1991. PLIST_ENTRY ListHead;
  1992. PAVRF_DEADLOCK_THREAD ThreadInfo;
  1993. ThreadInfo = NULL;
  1994. ListHead = AVrfpDeadlockDatabaseHash (AVrfpDeadlockGlobals->ThreadDatabase, Thread);
  1995. if (IsListEmpty(ListHead)) {
  1996. return NULL;
  1997. }
  1998. Current = ListHead->Flink;
  1999. while (Current != ListHead) {
  2000. ThreadInfo = CONTAINING_RECORD (Current,
  2001. AVRF_DEADLOCK_THREAD,
  2002. ListEntry);
  2003. if (ThreadInfo->Thread == Thread) {
  2004. return ThreadInfo;
  2005. }
  2006. Current = Current->Flink;
  2007. }
  2008. return NULL;
  2009. }
  2010. PAVRF_DEADLOCK_THREAD
  2011. AVrfpDeadlockAddThread (
  2012. HANDLE Thread,
  2013. PVOID ReservedThread
  2014. )
  2015. /*++
  2016. Routine Description:
  2017. This routine adds a new thread to the thread database.
  2018. The function assumes the deadlock database lock is held.
  2019. Arguments:
  2020. Thread - thread address
  2021. Return Value:
  2022. Address of the AVRF_DEADLOCK_THREAD structure just added.
  2023. Null if allocation failed.
  2024. --*/
  2025. {
  2026. PAVRF_DEADLOCK_THREAD ThreadInfo;
  2027. PLIST_ENTRY HashBin;
  2028. //
  2029. // Use reserved block for the new thread. Set ReservedThread
  2030. // to null to signal that block was used.
  2031. //
  2032. ThreadInfo = ReservedThread;
  2033. ReservedThread = NULL;
  2034. if (ThreadInfo == NULL) {
  2035. return NULL;
  2036. }
  2037. RtlZeroMemory (ThreadInfo, sizeof *ThreadInfo);
  2038. ThreadInfo->Thread = Thread;
  2039. HashBin = AVrfpDeadlockDatabaseHash (AVrfpDeadlockGlobals->ThreadDatabase, Thread);
  2040. InsertHeadList(HashBin, &ThreadInfo->ListEntry);
  2041. return ThreadInfo;
  2042. }
  2043. VOID
  2044. AVrfpDeadlockDeleteThread (
  2045. PAVRF_DEADLOCK_THREAD Thread,
  2046. BOOLEAN Cleanup
  2047. )
  2048. /*++
  2049. Routine Description:
  2050. This routine deletes a thread.
  2051. Arguments:
  2052. Thread - thread address
  2053. Cleanup - true if this is a call generated from DeadlockDetectionCleanup().
  2054. Return Value:
  2055. None.
  2056. --*/
  2057. {
  2058. if (Cleanup == FALSE) {
  2059. if (Thread->NodeCount != 0
  2060. || Thread->CurrentTopNode != NULL) {
  2061. //
  2062. // A thread should not be deleted while it has resources acquired.
  2063. //
  2064. AVrfpDeadlockReportIssue (AVRF_DEADLOCK_ISSUE_THREAD_HOLDS_RESOURCES,
  2065. (ULONG_PTR)(Thread->Thread),
  2066. (ULONG_PTR)(Thread),
  2067. (ULONG_PTR)0);
  2068. }
  2069. else {
  2070. ASSERT (Thread->NodeCount == 0);
  2071. }
  2072. }
  2073. RemoveEntryList (&(Thread->ListEntry));
  2074. AVrfpDeadlockFree (Thread, AVrfpDeadlockThread);
  2075. }
  2076. /////////////////////////////////////////////////////////////////////
  2077. /////////////////////////////////////////////////////// Allocate/Free
  2078. /////////////////////////////////////////////////////////////////////
  2079. PVOID
  2080. AVrfpDeadlockAllocateFromPoolCache (
  2081. PULONG Count,
  2082. ULONG MaximumCount,
  2083. PLIST_ENTRY List,
  2084. SIZE_T Offset
  2085. )
  2086. {
  2087. PVOID Address = NULL;
  2088. PLIST_ENTRY Entry;
  2089. UNREFERENCED_PARAMETER (MaximumCount);
  2090. if (*Count > 0) {
  2091. *Count -= 1;
  2092. Entry = RemoveHeadList (List);
  2093. Address = (PVOID)((SIZE_T)Entry - Offset);
  2094. }
  2095. return Address;
  2096. }
  2097. VOID
  2098. AVrfpDeadlockFreeIntoPoolCache (
  2099. PVOID Object,
  2100. PULONG Count,
  2101. PLIST_ENTRY List,
  2102. SIZE_T Offset
  2103. )
  2104. {
  2105. PLIST_ENTRY Entry;
  2106. Entry = (PLIST_ENTRY)((SIZE_T)Object + Offset);
  2107. *Count += 1;
  2108. InsertHeadList(List, Entry);
  2109. }
  2110. PVOID
  2111. AVrfpDeadlockAllocate (
  2112. AVRF_DEADLOCK_ALLOC_TYPE Type
  2113. )
  2114. /*++
  2115. Routine Description:
  2116. This routine is used to allocate deadlock verifier structures,
  2117. that is nodes, resources and threads.
  2118. Arguments:
  2119. Type - what structure do we need to allocate (node, resource or thread).
  2120. Return Value:
  2121. Address of the newly allocate structure or null if allocation failed.
  2122. Side effects:
  2123. If allocation fails the routine will bump the AllocationFailures field
  2124. from AVrfpDeadlockGlobals.
  2125. --*/
  2126. {
  2127. PVOID Address = NULL;
  2128. SIZE_T Offset;
  2129. SIZE_T Size = 0;
  2130. //
  2131. // If it is a resource, thread, or node alocation, see
  2132. // if we have a pre-allocated one on the free list.
  2133. //
  2134. AVrfpDeadlockDetectionLock ();
  2135. switch (Type) {
  2136. case AVrfpDeadlockThread:
  2137. Offset = (SIZE_T)(&(((PAVRF_DEADLOCK_THREAD)0)->FreeListEntry));
  2138. Size = sizeof (AVRF_DEADLOCK_THREAD);
  2139. Address = AVrfpDeadlockAllocateFromPoolCache (&(AVrfpDeadlockGlobals->FreeThreadCount),
  2140. AVRF_DEADLOCK_MAX_FREE_THREAD,
  2141. &(AVrfpDeadlockGlobals->FreeThreadList),
  2142. Offset);
  2143. break;
  2144. case AVrfpDeadlockResource:
  2145. Offset = (SIZE_T)(&(((PAVRF_DEADLOCK_RESOURCE)0)->FreeListEntry));
  2146. Size = sizeof (AVRF_DEADLOCK_RESOURCE);
  2147. Address = AVrfpDeadlockAllocateFromPoolCache (&(AVrfpDeadlockGlobals->FreeResourceCount),
  2148. AVRF_DEADLOCK_MAX_FREE_RESOURCE,
  2149. &(AVrfpDeadlockGlobals->FreeResourceList),
  2150. Offset);
  2151. break;
  2152. case AVrfpDeadlockNode:
  2153. Offset = (SIZE_T)(&(((PAVRF_DEADLOCK_NODE)0)->FreeListEntry));
  2154. Size = sizeof (AVRF_DEADLOCK_NODE);
  2155. Address = AVrfpDeadlockAllocateFromPoolCache (&(AVrfpDeadlockGlobals->FreeNodeCount),
  2156. AVRF_DEADLOCK_MAX_FREE_NODE,
  2157. &(AVrfpDeadlockGlobals->FreeNodeList),
  2158. Offset);
  2159. break;
  2160. default:
  2161. ASSERT (0);
  2162. break;
  2163. }
  2164. //
  2165. // If we did not find anything then go to the process heap for a
  2166. // direct allocation.
  2167. //
  2168. if (Address == NULL) {
  2169. // silviuc: it is nice to release the lock but should we?
  2170. AVrfpDeadlockDetectionUnlock ();
  2171. Address = AVrfpAllocate (Size);
  2172. AVrfpDeadlockDetectionLock ();
  2173. }
  2174. if (Address) {
  2175. switch (Type) {
  2176. case AVrfpDeadlockThread:
  2177. AVrfpDeadlockGlobals->Threads[0] += 1;
  2178. if (AVrfpDeadlockGlobals->Threads[0] > AVrfpDeadlockGlobals->Threads[1]) {
  2179. AVrfpDeadlockGlobals->Threads[1] = AVrfpDeadlockGlobals->Threads[0];
  2180. }
  2181. break;
  2182. case AVrfpDeadlockResource:
  2183. AVrfpDeadlockGlobals->Resources[0] += 1;
  2184. if (AVrfpDeadlockGlobals->Resources[0] > AVrfpDeadlockGlobals->Resources[1]) {
  2185. AVrfpDeadlockGlobals->Resources[1] = AVrfpDeadlockGlobals->Resources[0];
  2186. }
  2187. break;
  2188. case AVrfpDeadlockNode:
  2189. AVrfpDeadlockGlobals->Nodes[0] += 1;
  2190. if (AVrfpDeadlockGlobals->Nodes[0] > AVrfpDeadlockGlobals->Nodes[1]) {
  2191. AVrfpDeadlockGlobals->Nodes[1] = AVrfpDeadlockGlobals->Nodes[0];
  2192. }
  2193. break;
  2194. default:
  2195. ASSERT (0);
  2196. break;
  2197. }
  2198. }
  2199. else {
  2200. AVrfpDeadlockState.AllocationFailures = 1;
  2201. AVrfpDeadlockGlobals->AllocationFailures += 1;
  2202. //
  2203. // Note that making the AllocationFailures counter bigger than zero
  2204. // essentially disables deadlock verification because the CanProceed()
  2205. // routine will start returning false.
  2206. //
  2207. }
  2208. //
  2209. // Update statistics. No need to zero the block since every
  2210. // call site takes care of this.
  2211. //
  2212. if (Address) {
  2213. #if DBG
  2214. RtlFillMemory (Address, Size, 0xFF);
  2215. #endif
  2216. AVrfpDeadlockGlobals->BytesAllocated += Size;
  2217. }
  2218. AVrfpDeadlockDetectionUnlock ();
  2219. return Address;
  2220. }
  2221. VOID
  2222. AVrfpDeadlockFree (
  2223. PVOID Object,
  2224. AVRF_DEADLOCK_ALLOC_TYPE Type
  2225. )
  2226. /*++
  2227. Routine Description:
  2228. This routine deallocates a deadlock verifier structure (node, resource
  2229. or thread). The function will place the block in the corrsponding cache
  2230. based on the type of the structure. The routine never calls ExFreePool.
  2231. The reason for not calling ExFreePool is that we get notifications from
  2232. ExFreePool every time it gets called. Sometimes the notification comes
  2233. with pool locks held and therefore we cannot call again.
  2234. Arguments:
  2235. Object - block to deallocate
  2236. Type - type of object (node, resource, thread).
  2237. Return Value:
  2238. None.
  2239. --*/
  2240. //
  2241. // silviuc: update comment
  2242. // Note ... if a thread, node, or resource is being freed, we must not
  2243. // call ExFreePool. Since the pool lock may be already held, calling ExFreePool
  2244. // would cause a recursive spinlock acquisition (which is bad).
  2245. // Instead, we move everything to a 'free' list and try to reuse.
  2246. // Non-thread-node-resource frees get ExFreePooled
  2247. //
  2248. {
  2249. SIZE_T Offset;
  2250. SIZE_T Size = 0;
  2251. switch (Type) {
  2252. case AVrfpDeadlockThread:
  2253. AVrfpDeadlockGlobals->Threads[0] -= 1;
  2254. Size = sizeof (AVRF_DEADLOCK_THREAD);
  2255. Offset = (SIZE_T)(&(((PAVRF_DEADLOCK_THREAD)0)->FreeListEntry));
  2256. AVrfpDeadlockFreeIntoPoolCache (Object,
  2257. &(AVrfpDeadlockGlobals->FreeThreadCount),
  2258. &(AVrfpDeadlockGlobals->FreeThreadList),
  2259. Offset);
  2260. break;
  2261. case AVrfpDeadlockResource:
  2262. AVrfpDeadlockGlobals->Resources[0] -= 1;
  2263. Size = sizeof (AVRF_DEADLOCK_RESOURCE);
  2264. Offset = (SIZE_T)(&(((PAVRF_DEADLOCK_RESOURCE)0)->FreeListEntry));
  2265. AVrfpDeadlockFreeIntoPoolCache (Object,
  2266. &(AVrfpDeadlockGlobals->FreeResourceCount),
  2267. &(AVrfpDeadlockGlobals->FreeResourceList),
  2268. Offset);
  2269. break;
  2270. case AVrfpDeadlockNode:
  2271. AVrfpDeadlockGlobals->Nodes[0] -= 1;
  2272. Size = sizeof (AVRF_DEADLOCK_NODE);
  2273. Offset = (SIZE_T)(&(((PAVRF_DEADLOCK_NODE)0)->FreeListEntry));
  2274. AVrfpDeadlockFreeIntoPoolCache (Object,
  2275. &(AVrfpDeadlockGlobals->FreeNodeCount),
  2276. &(AVrfpDeadlockGlobals->FreeNodeList),
  2277. Offset);
  2278. break;
  2279. default:
  2280. ASSERT (0);
  2281. break;
  2282. }
  2283. AVrfpDeadlockGlobals->BytesAllocated -= Size;
  2284. }
  2285. VOID
  2286. AVrfpDeadlockTrimPoolCache (
  2287. VOID
  2288. )
  2289. /*++
  2290. Routine Description:
  2291. // silviuc: update comment
  2292. This function trims the pool caches to decent levels. It is carefully
  2293. written to queue a work item to do the actual processing (freeing of pool)
  2294. because the caller may hold various pool mutexes above us.
  2295. Arguments:
  2296. None.
  2297. Return Value:
  2298. None.
  2299. --*/
  2300. {
  2301. LOGICAL ShouldTrim = FALSE;
  2302. AVrfpDeadlockDetectionLock ();
  2303. if (AVrfpDeadlockGlobals->CacheReductionInProgress == TRUE) {
  2304. AVrfpDeadlockDetectionUnlock ();
  2305. return;
  2306. }
  2307. if ((AVrfpDeadlockGlobals->FreeThreadCount > AVRF_DEADLOCK_MAX_FREE_THREAD) ||
  2308. (AVrfpDeadlockGlobals->FreeNodeCount > AVRF_DEADLOCK_MAX_FREE_NODE) ||
  2309. (AVrfpDeadlockGlobals->FreeResourceCount > AVRF_DEADLOCK_MAX_FREE_RESOURCE)) {
  2310. ShouldTrim = TRUE;
  2311. AVrfpDeadlockGlobals->CacheReductionInProgress = TRUE;
  2312. AVrfpDeadlockGlobals->PoolTrimCounter += 1;
  2313. }
  2314. AVrfpDeadlockDetectionUnlock ();
  2315. if (ShouldTrim) {
  2316. AVrfpDeadlockTrimPoolCacheWorker (NULL);
  2317. }
  2318. return;
  2319. }
  2320. VOID
  2321. AVrfpDeadlockTrimPoolCacheWorker (
  2322. PVOID Parameter
  2323. )
  2324. /*++
  2325. Routine Description:
  2326. This function trims the pool caches to decent levels. It is carefully
  2327. written so that ExFreePool is called without holding any deadlock
  2328. verifier locks.
  2329. Arguments:
  2330. None.
  2331. Return Value:
  2332. None.
  2333. Environment:
  2334. Worker thread, PASSIVE_LEVEL, no locks held.
  2335. --*/
  2336. {
  2337. LIST_ENTRY ListOfThreads;
  2338. LIST_ENTRY ListOfNodes;
  2339. LIST_ENTRY ListOfResources;
  2340. PLIST_ENTRY Entry;
  2341. LOGICAL CacheReductionNeeded;
  2342. UNREFERENCED_PARAMETER (Parameter);
  2343. CacheReductionNeeded = FALSE;
  2344. InitializeListHead (&ListOfThreads);
  2345. InitializeListHead (&ListOfNodes);
  2346. InitializeListHead (&ListOfResources);
  2347. AVrfpDeadlockDetectionLock ();
  2348. while (AVrfpDeadlockGlobals->FreeThreadCount > AVRF_DEADLOCK_TRIM_TARGET_THREAD) {
  2349. Entry = RemoveHeadList (&(AVrfpDeadlockGlobals->FreeThreadList));
  2350. InsertTailList (&ListOfThreads, Entry);
  2351. AVrfpDeadlockGlobals->FreeThreadCount -= 1;
  2352. CacheReductionNeeded = TRUE;
  2353. }
  2354. while (AVrfpDeadlockGlobals->FreeNodeCount > AVRF_DEADLOCK_TRIM_TARGET_NODE) {
  2355. Entry = RemoveHeadList (&(AVrfpDeadlockGlobals->FreeNodeList));
  2356. InsertTailList (&ListOfNodes, Entry);
  2357. AVrfpDeadlockGlobals->FreeNodeCount -= 1;
  2358. CacheReductionNeeded = TRUE;
  2359. }
  2360. while (AVrfpDeadlockGlobals->FreeResourceCount > AVRF_DEADLOCK_TRIM_TARGET_RESOURCE) {
  2361. Entry = RemoveHeadList (&(AVrfpDeadlockGlobals->FreeResourceList));
  2362. InsertTailList (&ListOfResources, Entry);
  2363. AVrfpDeadlockGlobals->FreeResourceCount -= 1;
  2364. CacheReductionNeeded = TRUE;
  2365. }
  2366. //
  2367. // Don't clear CacheReductionInProgress until the pool allocations are
  2368. // freed to prevent needless recursion.
  2369. //
  2370. if (CacheReductionNeeded == FALSE) {
  2371. AVrfpDeadlockGlobals->CacheReductionInProgress = FALSE;
  2372. AVrfpDeadlockDetectionUnlock ();
  2373. return;
  2374. }
  2375. AVrfpDeadlockDetectionUnlock ();
  2376. //
  2377. // Now, out of the deadlock verifier lock we can deallocate the
  2378. // blocks trimmed.
  2379. //
  2380. Entry = ListOfThreads.Flink;
  2381. while (Entry != &ListOfThreads) {
  2382. PAVRF_DEADLOCK_THREAD Block;
  2383. Block = CONTAINING_RECORD (Entry,
  2384. AVRF_DEADLOCK_THREAD,
  2385. FreeListEntry);
  2386. Entry = Entry->Flink;
  2387. AVrfpFree (Block);
  2388. }
  2389. Entry = ListOfNodes.Flink;
  2390. while (Entry != &ListOfNodes) {
  2391. PAVRF_DEADLOCK_NODE Block;
  2392. Block = CONTAINING_RECORD (Entry,
  2393. AVRF_DEADLOCK_NODE,
  2394. FreeListEntry);
  2395. Entry = Entry->Flink;
  2396. AVrfpFree (Block);
  2397. }
  2398. Entry = ListOfResources.Flink;
  2399. while (Entry != &ListOfResources) {
  2400. PAVRF_DEADLOCK_RESOURCE Block;
  2401. Block = CONTAINING_RECORD (Entry,
  2402. AVRF_DEADLOCK_RESOURCE,
  2403. FreeListEntry);
  2404. Entry = Entry->Flink;
  2405. AVrfpFree (Block);
  2406. }
  2407. //
  2408. // It's safe to clear CacheReductionInProgress now that the pool
  2409. // allocations are freed.
  2410. //
  2411. AVrfpDeadlockDetectionLock ();
  2412. AVrfpDeadlockGlobals->CacheReductionInProgress = FALSE;
  2413. AVrfpDeadlockDetectionUnlock ();
  2414. }
  2415. /////////////////////////////////////////////////////////////////////
  2416. /////////////////////////////////////// Error reporting and debugging
  2417. /////////////////////////////////////////////////////////////////////
  2418. //
  2419. // Variable accessed by the !deadlock debug extension to investigate
  2420. // failures.
  2421. //
  2422. ULONG_PTR AVrfpDeadlockIssue[4];
  2423. VOID
  2424. AVrfpDeadlockReportIssue (
  2425. ULONG_PTR Param1,
  2426. ULONG_PTR Param2,
  2427. ULONG_PTR Param3,
  2428. ULONG_PTR Param4
  2429. )
  2430. /*++
  2431. Routine Description:
  2432. This routine is called to report a deadlock verifier issue.
  2433. If we are in debug mode we will just break in debugger.
  2434. Otherwise we will bugcheck,
  2435. Arguments:
  2436. Param1..Param4 - relevant information for the point of failure.
  2437. Return Value:
  2438. None.
  2439. --*/
  2440. {
  2441. AVrfpDeadlockIssue[0] = Param1;
  2442. AVrfpDeadlockIssue[1] = Param2;
  2443. AVrfpDeadlockIssue[2] = Param3;
  2444. AVrfpDeadlockIssue[3] = Param4;
  2445. if (AVrfpDeadlockDebug) {
  2446. DbgPrint ("AVRF: deadlock: stop: %p %p %p %p %p \n",
  2447. DRIVER_VERIFIER_DETECTED_VIOLATION,
  2448. Param1,
  2449. Param2,
  2450. Param3,
  2451. Param4);
  2452. DbgBreakPoint ();
  2453. }
  2454. else {
  2455. // silviuc: APPLICATION_VERIFIER_DEADLOCK_ISSUE
  2456. VERIFIER_STOP (APPLICATION_VERIFIER_UNKNOWN_ERROR,
  2457. "Application verifier deadlock/resource issue",
  2458. Param1, "",
  2459. Param2, "",
  2460. Param3, "",
  2461. Param4, "");
  2462. }
  2463. }
  2464. VOID
  2465. AVrfpDeadlockAddParticipant(
  2466. PAVRF_DEADLOCK_NODE Node
  2467. )
  2468. /*++
  2469. Routine Description:
  2470. Adds a new node to the set of nodes involved in a deadlock.
  2471. The function is called only from AVrfpDeadlockAnalyze().
  2472. Arguments:
  2473. Node - node to be added to the deadlock participants collection.
  2474. Return Value:
  2475. None.
  2476. --*/
  2477. {
  2478. ULONG Index;
  2479. Index = AVrfpDeadlockGlobals->NumberOfParticipants;
  2480. if (Index >= NO_OF_DEADLOCK_PARTICIPANTS) {
  2481. AVrfpDeadlockState.DeadlockParticipantsOverflow = 1;
  2482. return;
  2483. }
  2484. AVrfpDeadlockGlobals->Participant[Index] = Node;
  2485. AVrfpDeadlockGlobals->NumberOfParticipants += 1;
  2486. }
  2487. /////////////////////////////////////////////////////////////////////
  2488. //////////////////////////////////////////////////// Resource cleanup
  2489. /////////////////////////////////////////////////////////////////////
  2490. VOID
  2491. AVrfpDeadlockDeleteResource (
  2492. PAVRF_DEADLOCK_RESOURCE Resource,
  2493. BOOLEAN Cleanup
  2494. )
  2495. /*++
  2496. Routine Description:
  2497. This routine deletes a routine and all nodes representing
  2498. acquisitions of that resource.
  2499. Arguments:
  2500. Resource - resource to be deleted
  2501. Cleanup - true if are called from AVrfpDeadlockDetectionCleanup
  2502. Return Value:
  2503. None.
  2504. --*/
  2505. {
  2506. PLIST_ENTRY Current;
  2507. PAVRF_DEADLOCK_NODE Node;
  2508. ASSERT (Resource != NULL);
  2509. //
  2510. // Check if the resource being deleted is still acquired.
  2511. // If it is we will release it ourselves in order to put in
  2512. // order all internal deadlock verifier structures. Unfortunately
  2513. // it is not a bug to delete a critical section that is not released.
  2514. // Too many people already do it to change the rules in mid flight.
  2515. //
  2516. if (Cleanup == FALSE && Resource->ThreadOwner != NULL) {
  2517. while (Resource->RecursionCount > 0) {
  2518. AVrfDeadlockResourceRelease (Resource->ResourceAddress,
  2519. _ReturnAddress());
  2520. }
  2521. }
  2522. ASSERT (Resource->ThreadOwner == NULL);
  2523. ASSERT (Resource->RecursionCount == 0);
  2524. //
  2525. // If this is a normal delete (not a cleanup) we will collapse all trees
  2526. // containing nodes for this resource. If it is a cleanup we will just
  2527. // wipe out the node.
  2528. //
  2529. Current = Resource->ResourceList.Flink;
  2530. while (Current != &(Resource->ResourceList)) {
  2531. Node = CONTAINING_RECORD (Current,
  2532. AVRF_DEADLOCK_NODE,
  2533. ResourceList);
  2534. Current = Current->Flink;
  2535. ASSERT (Node->Root == Resource);
  2536. AVrfpDeadlockDeleteNode (Node, Cleanup);
  2537. }
  2538. //
  2539. // There should not be any NODEs for the resource at this moment.
  2540. //
  2541. ASSERT (&(Resource->ResourceList) == Resource->ResourceList.Flink);
  2542. ASSERT (&(Resource->ResourceList) == Resource->ResourceList.Blink);
  2543. //
  2544. // Remote the resource from the hash table and
  2545. // delete the resource structure.
  2546. //
  2547. RemoveEntryList (&(Resource->HashChainList));
  2548. AVrfpDeadlockFree (Resource, AVrfpDeadlockResource);
  2549. }
  2550. VOID
  2551. AVrfpDeadlockTrimResources (
  2552. PLIST_ENTRY HashList
  2553. )
  2554. {
  2555. PLIST_ENTRY Current;
  2556. PAVRF_DEADLOCK_RESOURCE Resource;
  2557. ULONG Counter;
  2558. AVrfpDeadlockGlobals->ForgetHistoryCounter += 1;
  2559. Counter = AVrfpDeadlockGlobals->ForgetHistoryCounter;
  2560. Counter %= AVRF_DEADLOCK_FORGET_HISTORY_FREQUENCY;
  2561. if (Counter == 0) {
  2562. Current = HashList->Flink;
  2563. while (Current != HashList) {
  2564. Resource = CONTAINING_RECORD (Current,
  2565. AVRF_DEADLOCK_RESOURCE,
  2566. HashChainList);
  2567. Current = Current->Flink;
  2568. AVrfpDeadlockForgetResourceHistory (Resource,
  2569. AVrfpDeadlockTrimThreshold,
  2570. AVrfpDeadlockAgeWindow);
  2571. }
  2572. }
  2573. }
  2574. VOID
  2575. AVrfpDeadlockForgetResourceHistory (
  2576. PAVRF_DEADLOCK_RESOURCE Resource,
  2577. ULONG TrimThreshold,
  2578. ULONG AgeThreshold
  2579. )
  2580. /*++
  2581. Routine Description:
  2582. This routine deletes sone of the nodes representing
  2583. acquisitions of that resource. In essence we forget
  2584. part of the history of that resource.
  2585. Arguments:
  2586. Resource - resource for which we wipe out nodes.
  2587. TrimThreshold - how many nodes should remain
  2588. AgeThreshold - nodes older than this will go away
  2589. Return Value:
  2590. None.
  2591. --*/
  2592. {
  2593. PLIST_ENTRY Current;
  2594. PAVRF_DEADLOCK_NODE Node;
  2595. ULONG NodesTrimmed = 0;
  2596. ULONG SequenceNumber;
  2597. ASSERT (Resource != NULL);
  2598. //
  2599. // If resource is owned we cannot do anything,
  2600. //
  2601. if (Resource->ThreadOwner) {
  2602. return;
  2603. }
  2604. //
  2605. // If resource has less than TrimThreshold nodes it is still fine.
  2606. //
  2607. if (Resource->NodeCount < TrimThreshold) {
  2608. return;
  2609. }
  2610. //
  2611. // Delete some nodes of the resource based on ageing.
  2612. //
  2613. SequenceNumber = AVrfpDeadlockGlobals->SequenceNumber;
  2614. Current = Resource->ResourceList.Flink;
  2615. while (Current != &(Resource->ResourceList)) {
  2616. Node = CONTAINING_RECORD (Current,
  2617. AVRF_DEADLOCK_NODE,
  2618. ResourceList);
  2619. Current = Current->Flink;
  2620. ASSERT (Node->Root == Resource);
  2621. //
  2622. // Special care here because the sequence numbers are 32bits
  2623. // and they can overflow. In an ideal world the global sequence
  2624. // is always greater or equal to the node sequence but if it
  2625. // overwrapped it can be the other way around.
  2626. //
  2627. if (SequenceNumber > Node->SequenceNumber) {
  2628. if (SequenceNumber - Node->SequenceNumber > AgeThreshold) {
  2629. AVrfpDeadlockDeleteNode (Node, FALSE);
  2630. NodesTrimmed += 1;
  2631. }
  2632. }
  2633. else {
  2634. if (Node->SequenceNumber - SequenceNumber < AgeThreshold) {
  2635. AVrfpDeadlockDeleteNode (Node, FALSE);
  2636. NodesTrimmed += 1;
  2637. }
  2638. }
  2639. }
  2640. AVrfpDeadlockGlobals->NodesTrimmedBasedOnAge += NodesTrimmed;
  2641. //
  2642. // If resource has less than TrimThreshold nodes it is fine.
  2643. //
  2644. if (Resource->NodeCount < TrimThreshold) {
  2645. return;
  2646. }
  2647. //
  2648. // If we did not manage to trim the nodes by the age algorithm then
  2649. // we trim everything that we encounter.
  2650. //
  2651. NodesTrimmed = 0;
  2652. Current = Resource->ResourceList.Flink;
  2653. while (Current != &(Resource->ResourceList)) {
  2654. if (Resource->NodeCount < TrimThreshold) {
  2655. break;
  2656. }
  2657. Node = CONTAINING_RECORD (Current,
  2658. AVRF_DEADLOCK_NODE,
  2659. ResourceList);
  2660. Current = Current->Flink;
  2661. ASSERT (Node->Root == Resource);
  2662. AVrfpDeadlockDeleteNode (Node, FALSE);
  2663. NodesTrimmed += 1;
  2664. }
  2665. AVrfpDeadlockGlobals->NodesTrimmedBasedOnCount += NodesTrimmed;
  2666. }
  2667. VOID
  2668. AVrfpDeadlockDeleteNode (
  2669. PAVRF_DEADLOCK_NODE Node,
  2670. BOOLEAN Cleanup
  2671. )
  2672. /*++
  2673. Routine Description:
  2674. This routine deletes a node from a graph and collapses the tree,
  2675. that is connects its childrend with its parent.
  2676. If we are during a cleanup we will just delete the node without
  2677. collapsing the tree.
  2678. Arguments:
  2679. Node - node to be deleted.
  2680. Cleanup - true if we are during a total cleanup
  2681. Return Value:
  2682. None.
  2683. --*/
  2684. {
  2685. PLIST_ENTRY Current;
  2686. PAVRF_DEADLOCK_NODE Child;
  2687. ULONG Children;
  2688. ASSERT (Node);
  2689. //
  2690. // If are during a cleanup just delete the node and return.
  2691. //
  2692. if (Cleanup) {
  2693. RemoveEntryList (&(Node->ResourceList));
  2694. AVrfpDeadlockFree (Node, AVrfpDeadlockNode);
  2695. return;
  2696. }
  2697. //
  2698. // If we are here we need to collapse the tree
  2699. //
  2700. if (Node->Parent) {
  2701. //
  2702. // All Node's children must become Parent's children
  2703. //
  2704. Current = Node->ChildrenList.Flink;
  2705. while (Current != &(Node->ChildrenList)) {
  2706. Child = CONTAINING_RECORD (Current,
  2707. AVRF_DEADLOCK_NODE,
  2708. SiblingsList);
  2709. Current = Current->Flink;
  2710. RemoveEntryList (&(Child->SiblingsList));
  2711. Child->Parent = Node->Parent;
  2712. InsertTailList (&(Node->Parent->ChildrenList),
  2713. &(Child->SiblingsList));
  2714. }
  2715. RemoveEntryList (&(Node->SiblingsList));
  2716. }
  2717. else {
  2718. //
  2719. // All Node's children must become roots of the graph
  2720. //
  2721. Current = Node->ChildrenList.Flink;
  2722. Children = 0;
  2723. Child = NULL;
  2724. while (Current != &(Node->ChildrenList)) {
  2725. Children += 1;
  2726. Child = CONTAINING_RECORD (Current,
  2727. AVRF_DEADLOCK_NODE,
  2728. SiblingsList);
  2729. Current = Current->Flink;
  2730. RemoveEntryList (&(Child->SiblingsList));
  2731. Child->Parent = NULL;
  2732. Child->SiblingsList.Flink = NULL;
  2733. Child->SiblingsList.Blink = NULL;
  2734. }
  2735. }
  2736. ASSERT (Node->Root);
  2737. ASSERT (Node->Root->NodeCount > 0);
  2738. Node->Root->NodeCount -= 1;
  2739. RemoveEntryList (&(Node->ResourceList));
  2740. AVrfpDeadlockFree (Node, AVrfpDeadlockNode);
  2741. }
  2742. ULONG
  2743. AVrfpDeadlockNodeLevel (
  2744. PAVRF_DEADLOCK_NODE Node
  2745. )
  2746. /*++
  2747. Routine Description:
  2748. This routine computes the level of a graph node.
  2749. Arguments:
  2750. Node - graph node
  2751. Return Value:
  2752. Level of the node. A root node has level zero.
  2753. --*/
  2754. {
  2755. PAVRF_DEADLOCK_NODE Current;
  2756. ULONG Level = 0;
  2757. Current = Node->Parent;
  2758. while (Current) {
  2759. Level += 1;
  2760. Current = Current->Parent;
  2761. }
  2762. return Level;
  2763. }
  2764. /////////////////////////////////////////////////////////////////////
  2765. /////////////////////////////////////// Incremental graph compression
  2766. /////////////////////////////////////////////////////////////////////
  2767. //
  2768. // SilviuC: should write a comment about graph compression
  2769. // This is a very smart and tricky algorithm :-)
  2770. //
  2771. VOID
  2772. AVrfpDeadlockCheckDuplicatesAmongChildren (
  2773. PAVRF_DEADLOCK_NODE Parent,
  2774. PAVRF_DEADLOCK_NODE Child
  2775. )
  2776. {
  2777. PLIST_ENTRY Current;
  2778. PAVRF_DEADLOCK_NODE Node;
  2779. LOGICAL FoundOne;
  2780. FoundOne = FALSE;
  2781. Current = Parent->ChildrenList.Flink;
  2782. while (Current != &(Parent->ChildrenList)) {
  2783. Node = CONTAINING_RECORD (Current,
  2784. AVRF_DEADLOCK_NODE,
  2785. SiblingsList);
  2786. ASSERT (Current->Flink);
  2787. Current = Current->Flink;
  2788. if (AVrfpDeadlockSimilarNodes (Node, Child)) {
  2789. if (FoundOne == FALSE) {
  2790. ASSERT (Node == Child);
  2791. FoundOne = TRUE;
  2792. }
  2793. else {
  2794. AVrfpDeadlockMergeNodes (Child, Node);
  2795. }
  2796. }
  2797. }
  2798. }
  2799. VOID
  2800. AVrfpDeadlockCheckDuplicatesAmongRoots (
  2801. PAVRF_DEADLOCK_NODE Root
  2802. )
  2803. {
  2804. PLIST_ENTRY Current;
  2805. PAVRF_DEADLOCK_NODE Node;
  2806. PAVRF_DEADLOCK_RESOURCE Resource;
  2807. LOGICAL FoundOne;
  2808. FoundOne = FALSE;
  2809. Resource = Root->Root;
  2810. Current = Resource->ResourceList.Flink;
  2811. while (Current != &(Resource->ResourceList)) {
  2812. Node = CONTAINING_RECORD (Current,
  2813. AVRF_DEADLOCK_NODE,
  2814. ResourceList);
  2815. ASSERT (Current->Flink);
  2816. Current = Current->Flink;
  2817. if (Node->Parent == NULL && AVrfpDeadlockSimilarNodes (Node, Root)) {
  2818. if (FoundOne == FALSE) {
  2819. ASSERT (Node == Root);
  2820. FoundOne = TRUE;
  2821. }
  2822. else {
  2823. AVrfpDeadlockMergeNodes (Root, Node);
  2824. }
  2825. }
  2826. }
  2827. }
  2828. LOGICAL
  2829. AVrfpDeadlockSimilarNodes (
  2830. PAVRF_DEADLOCK_NODE NodeA,
  2831. PAVRF_DEADLOCK_NODE NodeB
  2832. )
  2833. {
  2834. if (NodeA->Root == NodeB->Root
  2835. && NodeA->OnlyTryAcquireUsed == NodeB->OnlyTryAcquireUsed) {
  2836. return TRUE;
  2837. }
  2838. else {
  2839. return FALSE;
  2840. }
  2841. }
  2842. VOID
  2843. AVrfpDeadlockMergeNodes (
  2844. PAVRF_DEADLOCK_NODE NodeTo,
  2845. PAVRF_DEADLOCK_NODE NodeFrom
  2846. )
  2847. {
  2848. PLIST_ENTRY Current;
  2849. PAVRF_DEADLOCK_NODE Node;
  2850. //
  2851. // If NodeFrom is currently acquired then copy the same
  2852. // characteristics to NodeTo. Since the locks are exclusive
  2853. // it is impossible to have NodeTo also acquired.
  2854. //
  2855. if (NodeFrom->ThreadEntry) {
  2856. ASSERT (NodeTo->ThreadEntry == NULL);
  2857. NodeTo->ThreadEntry = NodeFrom->ThreadEntry;
  2858. RtlCopyMemory (NodeTo->StackTrace,
  2859. NodeFrom->StackTrace,
  2860. sizeof (NodeTo->StackTrace));
  2861. RtlCopyMemory (NodeTo->ParentStackTrace,
  2862. NodeFrom->ParentStackTrace,
  2863. sizeof (NodeTo->ParentStackTrace));
  2864. }
  2865. if (NodeFrom->Active) {
  2866. ASSERT (NodeTo->Active == 0);
  2867. NodeTo->Active = NodeFrom->Active;
  2868. }
  2869. //
  2870. // Move each child of NodeFrom as a child of NodeTo.
  2871. //
  2872. Current = NodeFrom->ChildrenList.Flink;
  2873. while (Current != &(NodeFrom->ChildrenList)) {
  2874. Node = CONTAINING_RECORD (Current,
  2875. AVRF_DEADLOCK_NODE,
  2876. SiblingsList);
  2877. ASSERT (Current->Flink);
  2878. Current = Current->Flink;
  2879. RemoveEntryList (&(Node->SiblingsList));
  2880. ASSERT (Node->Parent == NodeFrom);
  2881. Node->Parent = NodeTo;
  2882. InsertTailList (&(NodeTo->ChildrenList),
  2883. &(Node->SiblingsList));
  2884. }
  2885. //
  2886. // NodeFrom is empty. Delete it.
  2887. //
  2888. ASSERT (IsListEmpty(&(NodeFrom->ChildrenList)));
  2889. if (NodeFrom->Parent) {
  2890. RemoveEntryList (&(NodeFrom->SiblingsList));
  2891. }
  2892. NodeFrom->Root->NodeCount -= 1;
  2893. RemoveEntryList (&(NodeFrom->ResourceList));
  2894. AVrfpDeadlockFree (NodeFrom, AVrfpDeadlockNode);
  2895. }
  2896. /////////////////////////////////////////////////////////////////////
  2897. ////////////////////////////////////////////////// Consistency checks
  2898. /////////////////////////////////////////////////////////////////////
  2899. //
  2900. // Node Resource Thread
  2901. //
  2902. // Root ThreadOwner CurrentNode
  2903. // ThreadEntry RecursionCount NodeCount
  2904. // Active ResourceAddress Thread
  2905. //
  2906. //
  2907. //
  2908. //
  2909. VOID
  2910. AVrfpDeadlockCheckThreadConsistency (
  2911. PAVRF_DEADLOCK_THREAD Thread,
  2912. BOOLEAN Recursion
  2913. )
  2914. {
  2915. if (Thread->CurrentTopNode == NULL) {
  2916. ASSERT (Thread->NodeCount == 0);
  2917. return;
  2918. }
  2919. if (Thread->CurrentTopNode) {
  2920. ASSERT (Thread->NodeCount > 0);
  2921. ASSERT (Thread->CurrentTopNode->Active);
  2922. if (Recursion == FALSE) {
  2923. AVrfpDeadlockCheckNodeConsistency (Thread->CurrentTopNode, TRUE);
  2924. AVrfpDeadlockCheckResourceConsistency (Thread->CurrentTopNode->Root, TRUE);
  2925. }
  2926. }
  2927. if (Thread->CurrentTopNode) {
  2928. ASSERT (Thread->NodeCount > 0);
  2929. ASSERT (Thread->CurrentTopNode->Active);
  2930. if (Recursion == FALSE) {
  2931. AVrfpDeadlockCheckNodeConsistency (Thread->CurrentTopNode, TRUE);
  2932. AVrfpDeadlockCheckResourceConsistency (Thread->CurrentTopNode->Root, TRUE);
  2933. }
  2934. }
  2935. }
  2936. VOID
  2937. AVrfpDeadlockCheckNodeConsistency (
  2938. PAVRF_DEADLOCK_NODE Node,
  2939. BOOLEAN Recursion
  2940. )
  2941. {
  2942. if (Node->ThreadEntry) {
  2943. ASSERT (Node->Active == 1);
  2944. if (Recursion == FALSE) {
  2945. AVrfpDeadlockCheckThreadConsistency (Node->ThreadEntry, TRUE);
  2946. AVrfpDeadlockCheckResourceConsistency (Node->Root, TRUE);
  2947. }
  2948. }
  2949. else {
  2950. ASSERT (Node->Active == 0);
  2951. if (Recursion == FALSE) {
  2952. AVrfpDeadlockCheckResourceConsistency (Node->Root, TRUE);
  2953. }
  2954. }
  2955. }
  2956. VOID
  2957. AVrfpDeadlockCheckResourceConsistency (
  2958. PAVRF_DEADLOCK_RESOURCE Resource,
  2959. BOOLEAN Recursion
  2960. )
  2961. {
  2962. if (Resource->ThreadOwner) {
  2963. ASSERT (Resource->RecursionCount > 0);
  2964. if (Recursion == FALSE) {
  2965. AVrfpDeadlockCheckThreadConsistency (Resource->ThreadOwner, TRUE);
  2966. AVrfpDeadlockCheckNodeConsistency (Resource->ThreadOwner->CurrentTopNode, TRUE);
  2967. }
  2968. }
  2969. else {
  2970. ASSERT (Resource->RecursionCount == 0);
  2971. }
  2972. }
  2973. PAVRF_DEADLOCK_THREAD
  2974. AVrfpDeadlockCheckThreadReferences (
  2975. PAVRF_DEADLOCK_NODE Node
  2976. )
  2977. /*++
  2978. Routine Description:
  2979. This routine iterates all threads in order to check if `Node' is
  2980. referred in the `CurrentNode' field in any of them.
  2981. Arguments:
  2982. Node - node to search
  2983. Return Value:
  2984. If everything goes ok we should not find the node and the return
  2985. value is null. Otherwise we return the thread referring to the node.
  2986. --*/
  2987. {
  2988. ULONG Index;
  2989. PLIST_ENTRY Current;
  2990. PAVRF_DEADLOCK_THREAD Thread;
  2991. for (Index = 0; Index < AVRF_DEADLOCK_HASH_BINS; Index += 1) {
  2992. Current = AVrfpDeadlockGlobals->ThreadDatabase[Index].Flink;
  2993. while (Current != &(AVrfpDeadlockGlobals->ThreadDatabase[Index])) {
  2994. Thread = CONTAINING_RECORD (Current,
  2995. AVRF_DEADLOCK_THREAD,
  2996. ListEntry);
  2997. if (Thread->CurrentTopNode == Node) {
  2998. return Thread;
  2999. }
  3000. if (Thread->CurrentTopNode == Node) {
  3001. return Thread;
  3002. }
  3003. Current = Current->Flink;
  3004. }
  3005. }
  3006. return NULL;
  3007. }