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.

3573 lines
81 KiB

  1. /*++
  2. Copyright (c) 1998-2002 Microsoft Corporation
  3. Module Name:
  4. debug.c
  5. Abstract:
  6. This module contains debug support routines.
  7. Author:
  8. Keith Moore (keithmo) 10-Jun-1998
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #include "debugp.h"
  13. #if DBG
  14. #undef ExAllocatePool
  15. #undef ExFreePool
  16. #ifdef ALLOC_PRAGMA
  17. #if DBG
  18. #pragma alloc_text( INIT, UlDbgInitializeDebugData )
  19. #pragma alloc_text( PAGE, UlDbgTerminateDebugData )
  20. #pragma alloc_text( PAGE, UlDbgAcquireResourceExclusive )
  21. #pragma alloc_text( PAGE, UlDbgAcquireResourceShared )
  22. #pragma alloc_text( PAGE, UlDbgReleaseResource )
  23. #pragma alloc_text( PAGE, UlDbgConvertExclusiveToShared)
  24. #pragma alloc_text( PAGE, UlDbgTryToAcquireResourceExclusive)
  25. #pragma alloc_text( PAGE, UlDbgResourceOwnedExclusive )
  26. #pragma alloc_text( PAGE, UlDbgResourceUnownedExclusive )
  27. #pragma alloc_text( PAGE, UlDbgAcquirePushLockExclusive )
  28. #pragma alloc_text( PAGE, UlDbgReleasePushLockExclusive )
  29. #pragma alloc_text( PAGE, UlDbgAcquirePushLockShared )
  30. #pragma alloc_text( PAGE, UlDbgReleasePushLockShared )
  31. #pragma alloc_text( PAGE, UlDbgReleasePushLock )
  32. #pragma alloc_text( PAGE, UlDbgPushLockOwnedExclusive )
  33. #pragma alloc_text( PAGE, UlDbgPushLockUnownedExclusive )
  34. #endif // DBG
  35. #if 0
  36. NOT PAGEABLE -- UlDbgAllocatePool
  37. NOT PAGEABLE -- UlDbgFreePool
  38. NOT PAGEABLE -- UlDbgInitializeSpinLock
  39. NOT PAGEABLE -- UlDbgAcquireSpinLock
  40. NOT PAGEABLE -- UlDbgReleaseSpinLock
  41. NOT PAGEABLE -- UlDbgAcquireSpinLockAtDpcLevel
  42. NOT PAGEABLE -- UlDbgReleaseSpinLockFromDpcLevel
  43. NOT PAGEABLE -- UlDbgSpinLockOwned
  44. NOT PAGEABLE -- UlDbgSpinLockUnowned
  45. NOT PAGEABLE -- UlDbgExceptionFilter
  46. NOT PAGEABLE -- UlDbgInvalidCompletionRoutine
  47. NOT PAGEABLE -- UlDbgStatus
  48. NOT PAGEABLE -- UlDbgEnterDriver
  49. NOT PAGEABLE -- UlDbgLeaveDriver
  50. NOT PAGEABLE -- UlDbgInitializeResource
  51. NOT PAGEABLE -- UlDbgDeleteResource
  52. NOT PAGEABLE -- UlDbgInitializePushLock
  53. NOT PAGEABLE -- UlDbgDeletePushLock
  54. NOT PAGEABLE -- UlDbgAllocateIrp
  55. NOT PAGEABLE -- UlDbgFreeIrp
  56. NOT PAGEABLE -- UlDbgCallDriver
  57. NOT PAGEABLE -- UlDbgCompleteRequest
  58. NOT PAGEABLE -- UlDbgAllocateMdl
  59. NOT PAGEABLE -- UlDbgFreeMdl
  60. NOT PAGEABLE -- UlDbgFindFilePart
  61. NOT PAGEABLE -- UlpDbgUpdatePoolCounter
  62. NOT PAGEABLE -- UlpDbgFindThread
  63. NOT PAGEABLE -- UlpDbgDereferenceThread
  64. NOT PAGEABLE -- UlDbgIoSetCancelRoutine
  65. #endif
  66. #endif // ALLOC_PRAGMA
  67. //
  68. // Private globals.
  69. //
  70. UL_THREAD_HASH_BUCKET g_DbgThreadHashBuckets[NUM_THREAD_HASH_BUCKETS];
  71. // Count of threads
  72. LONG g_DbgThreadCreated;
  73. LONG g_DbgThreadDestroyed;
  74. KSPIN_LOCK g_DbgSpinLock; // protects global debug data
  75. LIST_ENTRY g_DbgGlobalResourceListHead;
  76. LIST_ENTRY g_DbgGlobalPushLockListHead;
  77. #if ENABLE_MDL_TRACKER
  78. LIST_ENTRY g_DbgMdlListHead;
  79. #endif
  80. //
  81. // Public functions.
  82. //
  83. /***************************************************************************++
  84. Routine Description:
  85. Initializes global debug-specific data.
  86. --***************************************************************************/
  87. VOID
  88. UlDbgInitializeDebugData(
  89. VOID
  90. )
  91. {
  92. ULONG i;
  93. //
  94. // Initialize the lock lists.
  95. //
  96. KeInitializeSpinLock( &g_DbgSpinLock );
  97. InitializeListHead( &g_DbgGlobalResourceListHead );
  98. InitializeListHead( &g_DbgGlobalPushLockListHead );
  99. #if ENABLE_MDL_TRACKER
  100. InitializeListHead( &g_DbgMdlListHead );
  101. #endif
  102. //
  103. // Initialize the thread hash buckets.
  104. //
  105. for (i = 0 ; i < NUM_THREAD_HASH_BUCKETS ; i++)
  106. {
  107. KeInitializeSpinLock(&g_DbgThreadHashBuckets[i].BucketSpinLock);
  108. g_DbgThreadHashBuckets[i].Count = 0;
  109. g_DbgThreadHashBuckets[i].Max = 0;
  110. InitializeListHead(&g_DbgThreadHashBuckets[i].BucketListHead);
  111. }
  112. } // UlDbgInitializeDebugData
  113. /***************************************************************************++
  114. Routine Description:
  115. Undoes any initialization performed in UlDbgInitializeDebugData().
  116. --***************************************************************************/
  117. VOID
  118. UlDbgTerminateDebugData(
  119. VOID
  120. )
  121. {
  122. ULONG i;
  123. //
  124. // Ensure the thread hash buckets are empty.
  125. //
  126. for (i = 0 ; i < NUM_THREAD_HASH_BUCKETS ; i++)
  127. {
  128. ASSERT( IsListEmpty( &g_DbgThreadHashBuckets[i].BucketListHead ) );
  129. ASSERT( g_DbgThreadHashBuckets[i].Count == 0 );
  130. // UlDeleteMutex(&g_DbgThreadHashBuckets[i].BucketSpinLock);
  131. }
  132. //
  133. // Ensure the lock lists are empty.
  134. //
  135. ASSERT( IsListEmpty( &g_DbgGlobalResourceListHead ) );
  136. ASSERT( IsListEmpty( &g_DbgGlobalPushLockListHead ) );
  137. #if ENABLE_MDL_TRACKER
  138. ASSERT( IsListEmpty( &g_DbgMdlListHead ) );
  139. #endif
  140. // UlDeleteMutex( &g_DbgSpinLock );
  141. } // UlDbgTerminateDebugData
  142. /***************************************************************************++
  143. Routine Description:
  144. Prettyprints a buffer to DbgPrint output (or the global STRING_LOG).
  145. More or less turns it back into a C-style string.
  146. CODEWORK: produce a Unicode version of this helper function
  147. Arguments:
  148. Buffer - Buffer to prettyprint
  149. BufferSize - number of bytes to prettyprint
  150. --***************************************************************************/
  151. VOID
  152. UlDbgPrettyPrintBuffer(
  153. IN const UCHAR* pBuffer,
  154. IN ULONG_PTR BufferSize
  155. )
  156. {
  157. ULONG i;
  158. CHAR OutputBuffer[200];
  159. PCHAR pOut;
  160. BOOLEAN CrLfNeeded = FALSE, JustCrLfd = FALSE;
  161. #define PRETTY_PREFIX(pOut) \
  162. pOut = OutputBuffer; *pOut++ = '|'; *pOut++ = '>'; \
  163. *pOut++ = ' '; *pOut++ = ' '
  164. #define PRETTY_SUFFIX(pOut) \
  165. *pOut++ = ' '; *pOut++ = '<'; *pOut++ = '|'; \
  166. *pOut++ = '\n'; *pOut++ = '\0'; \
  167. ASSERT(DIFF(pOut - OutputBuffer) <= sizeof(OutputBuffer))
  168. const ULONG SuffixLength = 5; // strlen(" <|\n\0")
  169. const ULONG MaxTokenLength = 4; // strlen('\xAB')
  170. if (pBuffer == NULL || BufferSize == 0)
  171. return;
  172. PRETTY_PREFIX(pOut);
  173. for (i = 0; i < BufferSize; ++i)
  174. {
  175. UCHAR ch = pBuffer[i];
  176. if ('\r' == ch) // CR
  177. {
  178. *pOut++ = '\\'; *pOut++ = 'r';
  179. if (i + 1 == BufferSize || '\n' != pBuffer[i + 1])
  180. CrLfNeeded = TRUE;
  181. }
  182. else if ('\n' == ch) // LF
  183. {
  184. *pOut++ = '\\'; *pOut++ = 'n';
  185. CrLfNeeded = TRUE;
  186. }
  187. else if ('\t' == ch) // TAB
  188. {
  189. *pOut++ = '\\'; *pOut++ = 't';
  190. }
  191. else if ('\0' == ch) // NUL
  192. {
  193. *pOut++ = '\\'; *pOut++ = '0';
  194. }
  195. else if ('\\' == ch) // \ (backslash)
  196. {
  197. *pOut++ = '\\'; *pOut++ = '\\';
  198. }
  199. else if ('%' == ch) // an unescaped '%' will confuse printf
  200. {
  201. *pOut++ = '%'; *pOut++ = '%';
  202. }
  203. else if (ch < 0x20 || 127 == ch) // control chars
  204. {
  205. const UCHAR HexString[] = "0123456789abcdef";
  206. *pOut++ = '\\'; *pOut++ = 'x';
  207. *pOut++ = HexString[ch >> 4];
  208. *pOut++ = HexString[ch & 0xf];
  209. }
  210. else
  211. {
  212. *pOut++ = ch;
  213. }
  214. if ((ULONG)(pOut - OutputBuffer)
  215. >= sizeof(OutputBuffer) - MaxTokenLength - SuffixLength)
  216. {
  217. CrLfNeeded = TRUE;
  218. }
  219. if (CrLfNeeded)
  220. {
  221. PRETTY_SUFFIX(pOut);
  222. WriteGlobalStringLog(OutputBuffer);
  223. PRETTY_PREFIX(pOut);
  224. CrLfNeeded = FALSE;
  225. JustCrLfd = TRUE;
  226. }
  227. else
  228. {
  229. JustCrLfd = FALSE;
  230. }
  231. }
  232. if (!JustCrLfd)
  233. {
  234. PRETTY_SUFFIX(pOut);
  235. WriteGlobalStringLog(OutputBuffer);
  236. }
  237. } // UlDbgPrettyPrintBuffer
  238. /***************************************************************************++
  239. Routine Description:
  240. Debug memory allocator. Allocates a block of pool with a header
  241. containing the filename & line number of the caller, plus the
  242. tag for the data.
  243. Arguments:
  244. PoolType - Supplies the pool to allocate from. Must be either
  245. NonPagedPool or PagedPool.
  246. NumberOfBytes - Supplies the number of bytes to allocate.
  247. Tag - Supplies a four-byte tag for the pool block. Useful for
  248. debugging leaks.
  249. pFileName - Supplies the filename of the caller.
  250. function.
  251. LineNumber - Supplies the line number of the caller.
  252. Return Value:
  253. PVOID - Pointer to the allocated block if successful, NULL otherwise.
  254. --***************************************************************************/
  255. PVOID
  256. UlDbgAllocatePool(
  257. IN POOL_TYPE PoolType,
  258. IN SIZE_T NumberOfBytes,
  259. IN ULONG Tag,
  260. IN PCSTR pFileName,
  261. IN USHORT LineNumber,
  262. IN PEPROCESS pProcess
  263. )
  264. {
  265. //
  266. // CODEWORK: factor out the different portions that depend
  267. // on ENABLE_POOL_HEADER, ENABLE_POOL_TRAILER, and
  268. // ENABLE_POOL_TRAILER_BYTE_SIGNATURE.
  269. //
  270. PUL_POOL_HEADER pHeader;
  271. PUL_POOL_TRAILER pTrailer;
  272. USHORT TrailerPadSize;
  273. USHORT i;
  274. PUCHAR pBody;
  275. SIZE_T Size;
  276. //
  277. // Sanity check.
  278. //
  279. ASSERT( PoolType == NonPagedPool || PoolType == PagedPool );
  280. ASSERT( IS_VALID_TAG( Tag ) );
  281. ASSERT(NumberOfBytes > 0);
  282. TrailerPadSize
  283. = (USHORT) (sizeof(UL_POOL_TRAILER)
  284. - (NumberOfBytes & (sizeof(UL_POOL_TRAILER) - 1)));
  285. ASSERT(0 < TrailerPadSize && TrailerPadSize <= sizeof(UL_POOL_TRAILER));
  286. ASSERT(((NumberOfBytes+TrailerPadSize) & (sizeof(UL_POOL_TRAILER)-1)) == 0);
  287. //
  288. // Allocate the block with additional space for the header and trailer.
  289. //
  290. Size = sizeof(UL_POOL_HEADER) + NumberOfBytes + TrailerPadSize
  291. + sizeof(UL_POOL_TRAILER);
  292. pHeader = (PUL_POOL_HEADER)(
  293. ExAllocatePoolWithTagPriority(
  294. PoolType,
  295. Size,
  296. Tag,
  297. LowPoolPriority
  298. )
  299. );
  300. if (pHeader == NULL)
  301. {
  302. WRITE_REF_TRACE_LOG(
  303. g_pPoolAllocTraceLog,
  304. REF_ACTION_POOL_ALLOC_FAIL_NO_MEM,
  305. (LONG) NumberOfBytes,
  306. NULL,
  307. pFileName,
  308. LineNumber
  309. );
  310. return NULL;
  311. }
  312. if (pProcess)
  313. {
  314. //
  315. // We are going to charge this memory to a process.
  316. //
  317. if (PsChargeProcessPoolQuota(
  318. pProcess,
  319. PoolType,
  320. Size) != STATUS_SUCCESS)
  321. {
  322. WRITE_REF_TRACE_LOG(
  323. g_pPoolAllocTraceLog,
  324. REF_ACTION_POOL_ALLOC_FAIL_NO_QUOTA,
  325. (LONG) NumberOfBytes,
  326. NULL,
  327. pFileName,
  328. LineNumber
  329. );
  330. ExFreePoolWithTag(pHeader, Tag);
  331. return NULL;
  332. }
  333. }
  334. //
  335. // Initialize the header.
  336. //
  337. pHeader->pProcess = pProcess;
  338. pHeader->pFileName = pFileName;
  339. pHeader->Size = NumberOfBytes;
  340. pHeader->Tag = Tag;
  341. pHeader->LineNumber = LineNumber;
  342. pHeader->TrailerPadSize = TrailerPadSize;
  343. #ifdef UL_POOL_HEADER_PADDING
  344. pHeader->Padding = ~ (ULONG_PTR) pHeader;
  345. #endif
  346. //
  347. // Fill the body with garbage.
  348. //
  349. pBody = (PUCHAR) (pHeader + 1);
  350. RtlFillMemory( pBody, NumberOfBytes, (UCHAR)'\xC' );
  351. #ifdef ENABLE_POOL_TRAILER_BYTE_SIGNATURE
  352. //
  353. // Fill the padding at the end with a distinct, recognizable pattern
  354. //
  355. for (i = 0; i < TrailerPadSize; ++i)
  356. {
  357. pBody[NumberOfBytes + i]
  358. = UlpAddressToByteSignature(pBody + NumberOfBytes + i);
  359. }
  360. #endif // ENABLE_POOL_TRAILER_BYTE_SIGNATURE
  361. //
  362. // Initialize the trailer struct
  363. //
  364. pTrailer = (PUL_POOL_TRAILER) (pBody + NumberOfBytes + TrailerPadSize);
  365. ASSERT(((ULONG_PTR) pTrailer & (MEMORY_ALLOCATION_ALIGNMENT - 1)) == 0);
  366. pTrailer->pHeader = pHeader;
  367. pTrailer->CheckSum = UlpPoolHeaderChecksum(pHeader);
  368. WRITE_REF_TRACE_LOG(
  369. g_pPoolAllocTraceLog,
  370. REF_ACTION_POOL_ALLOC,
  371. (LONG) NumberOfBytes,
  372. pBody,
  373. pFileName,
  374. LineNumber
  375. );
  376. //
  377. // Return a pointer to the body.
  378. //
  379. return pBody;
  380. } // UlDbgAllocatePool
  381. /***************************************************************************++
  382. Routine Description:
  383. Frees memory allocated by UlDbgAllocatePool(), ensuring that the tags
  384. match.
  385. Arguments:
  386. pPointer - Supplies a pointer to the pool block to free.
  387. Tag - Supplies the tag for the block to be freed. If the supplied
  388. tag does not match the tag of the allocated block, an assertion
  389. failure is generated.
  390. --***************************************************************************/
  391. VOID
  392. UlDbgFreePool(
  393. IN PVOID pPointer,
  394. IN ULONG Tag,
  395. IN PCSTR pFileName,
  396. IN USHORT LineNumber,
  397. IN POOL_TYPE PoolType,
  398. IN SIZE_T NumberOfBytes,
  399. IN PEPROCESS pProcess
  400. )
  401. {
  402. PUL_POOL_HEADER pHeader;
  403. PUL_POOL_TRAILER pTrailer;
  404. USHORT TrailerPadSize;
  405. USHORT i;
  406. PUCHAR pBody = (PUCHAR) pPointer;
  407. ULONG_PTR CheckSum;
  408. //
  409. // Get a pointer to the header.
  410. //
  411. pHeader = (PUL_POOL_HEADER) pPointer - 1;
  412. CheckSum = UlpPoolHeaderChecksum(pHeader);
  413. ASSERT(pHeader->pProcess == pProcess);
  414. if (pHeader->pProcess)
  415. {
  416. SIZE_T Size;
  417. ASSERT(NumberOfBytes != 0);
  418. ASSERT(NumberOfBytes == pHeader->Size);
  419. Size = sizeof(UL_POOL_HEADER) +
  420. NumberOfBytes +
  421. pHeader->TrailerPadSize +
  422. sizeof(UL_POOL_TRAILER);
  423. PsReturnPoolQuota(
  424. pHeader->pProcess,
  425. PoolType,
  426. Size
  427. );
  428. }
  429. //
  430. // Validate the tag.
  431. //
  432. ASSERT(pHeader->Tag == Tag);
  433. ASSERT( IS_VALID_TAG( Tag ) );
  434. //
  435. // Validate the trailer
  436. //
  437. TrailerPadSize = pHeader->TrailerPadSize;
  438. ASSERT(0 < TrailerPadSize && TrailerPadSize <= sizeof(UL_POOL_TRAILER));
  439. #ifdef UL_POOL_HEADER_PADDING
  440. ASSERT(pHeader->Padding == ~ (ULONG_PTR) pHeader);
  441. #endif
  442. pTrailer = (PUL_POOL_TRAILER) (pBody + pHeader->Size + TrailerPadSize);
  443. ASSERT(((ULONG_PTR) pTrailer & (MEMORY_ALLOCATION_ALIGNMENT - 1)) == 0);
  444. ASSERT(pTrailer->pHeader == pHeader);
  445. //
  446. // Has the header been corrupted? Was there a buffer underrun?
  447. //
  448. ASSERT(CheckSum == pTrailer->CheckSum);
  449. #ifdef ENABLE_POOL_TRAILER_BYTE_SIGNATURE
  450. //
  451. // Is the pattern between the end of pBody and pTrailer still correct?
  452. // Was there a buffer overrun?
  453. //
  454. for (i = 0; i < TrailerPadSize; ++i)
  455. {
  456. ASSERT(pBody[pHeader->Size + i]
  457. == UlpAddressToByteSignature(pBody + pHeader->Size + i));
  458. }
  459. #endif // ENABLE_POOL_TRAILER_BYTE_SIGNATURE
  460. //
  461. // Fill the body with garbage.
  462. //
  463. RtlFillMemory( pBody, pHeader->Size, (UCHAR)'\xE' );
  464. pHeader->Tag = MAKE_FREE_TAG( Tag );
  465. //
  466. // Actually free the block.
  467. //
  468. WRITE_REF_TRACE_LOG(
  469. g_pPoolAllocTraceLog,
  470. REF_ACTION_POOL_FREE,
  471. (LONG) pHeader->Size,
  472. pBody,
  473. pFileName,
  474. LineNumber
  475. );
  476. MyFreePoolWithTag(
  477. (PVOID)pHeader,
  478. Tag
  479. );
  480. } // UlDbgFreePool
  481. /***************************************************************************++
  482. Routine Description:
  483. Initializes an instrumented spinlock.
  484. --***************************************************************************/
  485. VOID
  486. UlDbgInitializeSpinLock(
  487. IN PUL_SPIN_LOCK pSpinLock,
  488. IN PCSTR pSpinLockName,
  489. IN PCSTR pFileName,
  490. IN USHORT LineNumber
  491. )
  492. {
  493. UNREFERENCED_PARAMETER(pFileName);
  494. UNREFERENCED_PARAMETER(LineNumber);
  495. //
  496. // Initialize the spinlock.
  497. //
  498. RtlZeroMemory( pSpinLock, sizeof(*pSpinLock) );
  499. pSpinLock->pSpinLockName = pSpinLockName;
  500. KeInitializeSpinLock( &pSpinLock->KSpinLock );
  501. SET_SPIN_LOCK_NOT_OWNED( pSpinLock );
  502. } // UlDbgInitializeSpinLock
  503. /***************************************************************************++
  504. Routine Description:
  505. Acquires an instrumented spinlock.
  506. --***************************************************************************/
  507. VOID
  508. UlDbgAcquireSpinLock(
  509. IN PUL_SPIN_LOCK pSpinLock,
  510. OUT PKIRQL pOldIrql,
  511. IN PCSTR pFileName,
  512. IN USHORT LineNumber
  513. )
  514. {
  515. //
  516. // Sanity check.
  517. //
  518. ASSERT( !UlDbgSpinLockOwned( pSpinLock ) );
  519. //
  520. // Acquire the lock.
  521. //
  522. KeAcquireSpinLock(
  523. &pSpinLock->KSpinLock,
  524. pOldIrql
  525. );
  526. //
  527. // Mark it as owned by the current thread.
  528. //
  529. ASSERT( UlDbgSpinLockUnowned( pSpinLock ) );
  530. SET_SPIN_LOCK_OWNED( pSpinLock );
  531. //
  532. // Update the statistics.
  533. //
  534. pSpinLock->Acquisitions++;
  535. pSpinLock->pLastAcquireFileName = pFileName;
  536. pSpinLock->LastAcquireLineNumber = LineNumber;
  537. } // UlDbgAcquireSpinLock
  538. /***************************************************************************++
  539. Routine Description:
  540. Releases an instrumented spinlock.
  541. --***************************************************************************/
  542. VOID
  543. UlDbgReleaseSpinLock(
  544. IN PUL_SPIN_LOCK pSpinLock,
  545. IN KIRQL OldIrql,
  546. IN PCSTR pFileName,
  547. IN USHORT LineNumber
  548. )
  549. {
  550. //
  551. // Mark it as unowned.
  552. //
  553. ASSERT( UlDbgSpinLockOwned( pSpinLock ) );
  554. SET_SPIN_LOCK_NOT_OWNED( pSpinLock );
  555. pSpinLock->Releases++;
  556. pSpinLock->pLastReleaseFileName = pFileName;
  557. pSpinLock->LastReleaseLineNumber = LineNumber;
  558. //
  559. // Release the lock.
  560. //
  561. KeReleaseSpinLock(
  562. &pSpinLock->KSpinLock,
  563. OldIrql
  564. );
  565. } // UlDbgReleaseSpinLock
  566. /***************************************************************************++
  567. Routine Description:
  568. Acquires an instrumented spinlock while running at DPC level.
  569. --***************************************************************************/
  570. VOID
  571. UlDbgAcquireSpinLockAtDpcLevel(
  572. IN PUL_SPIN_LOCK pSpinLock,
  573. IN PCSTR pFileName,
  574. IN USHORT LineNumber
  575. )
  576. {
  577. //
  578. // Sanity check.
  579. //
  580. ASSERT( !UlDbgSpinLockOwned( pSpinLock ) );
  581. //
  582. // Acquire the lock.
  583. //
  584. KeAcquireSpinLockAtDpcLevel(
  585. &pSpinLock->KSpinLock
  586. );
  587. //
  588. // Mark it as owned by the current thread.
  589. //
  590. ASSERT( !UlDbgSpinLockOwned( pSpinLock ) );
  591. SET_SPIN_LOCK_OWNED( pSpinLock );
  592. //
  593. // Update the statistics.
  594. //
  595. pSpinLock->AcquisitionsAtDpcLevel++;
  596. pSpinLock->pLastAcquireFileName = pFileName;
  597. pSpinLock->LastAcquireLineNumber = LineNumber;
  598. } // UlDbgAcquireSpinLockAtDpcLevel
  599. /***************************************************************************++
  600. Routine Description:
  601. Releases an instrumented spinlock acquired at DPC level.
  602. --***************************************************************************/
  603. VOID
  604. UlDbgReleaseSpinLockFromDpcLevel(
  605. IN PUL_SPIN_LOCK pSpinLock,
  606. IN PCSTR pFileName,
  607. IN USHORT LineNumber
  608. )
  609. {
  610. //
  611. // Mark it as unowned.
  612. //
  613. ASSERT( UlDbgSpinLockOwned( pSpinLock ) );
  614. SET_SPIN_LOCK_NOT_OWNED( pSpinLock );
  615. pSpinLock->ReleasesFromDpcLevel++;
  616. pSpinLock->pLastReleaseFileName = pFileName;
  617. pSpinLock->LastReleaseLineNumber = LineNumber;
  618. //
  619. // Release the lock.
  620. //
  621. KeReleaseSpinLockFromDpcLevel(
  622. &pSpinLock->KSpinLock
  623. );
  624. } // UlDbgReleaseSpinLockAtDpcLevel
  625. /***************************************************************************++
  626. Routine Description:
  627. Acquires an instrumented in-stack-queue spinlock.
  628. --***************************************************************************/
  629. VOID
  630. UlDbgAcquireInStackQueuedSpinLock(
  631. IN PUL_SPIN_LOCK pSpinLock,
  632. OUT PKLOCK_QUEUE_HANDLE pLockHandle,
  633. IN PCSTR pFileName,
  634. IN USHORT LineNumber
  635. )
  636. {
  637. //
  638. // Sanity check.
  639. //
  640. ASSERT( !UlDbgSpinLockOwned( pSpinLock ) );
  641. //
  642. // Acquire the lock.
  643. //
  644. KeAcquireInStackQueuedSpinLock(
  645. &pSpinLock->KSpinLock,
  646. pLockHandle
  647. );
  648. //
  649. // Mark it as owned by the current thread.
  650. //
  651. ASSERT( UlDbgSpinLockUnowned( pSpinLock ) );
  652. SET_SPIN_LOCK_OWNED( pSpinLock );
  653. //
  654. // Update the statistics.
  655. //
  656. pSpinLock->Acquisitions++;
  657. pSpinLock->pLastAcquireFileName = pFileName;
  658. pSpinLock->LastAcquireLineNumber = LineNumber;
  659. } // UlDbgAcquireInStackQueuedSpinLock
  660. /***************************************************************************++
  661. Routine Description:
  662. Releases an instrumented in-stack-queue spinlock.
  663. --***************************************************************************/
  664. VOID
  665. UlDbgReleaseInStackQueuedSpinLock(
  666. IN PUL_SPIN_LOCK pSpinLock,
  667. IN PKLOCK_QUEUE_HANDLE pLockHandle,
  668. IN PCSTR pFileName,
  669. IN USHORT LineNumber
  670. )
  671. {
  672. //
  673. // Mark it as unowned.
  674. //
  675. ASSERT( UlDbgSpinLockOwned( pSpinLock ) );
  676. SET_SPIN_LOCK_NOT_OWNED( pSpinLock );
  677. //
  678. // Update the statistics.
  679. //
  680. pSpinLock->Releases++;
  681. pSpinLock->pLastReleaseFileName = pFileName;
  682. pSpinLock->LastReleaseLineNumber = LineNumber;
  683. //
  684. // Release the lock.
  685. //
  686. KeReleaseInStackQueuedSpinLock(
  687. pLockHandle
  688. );
  689. } // UlDbgReleaseInStackQueuedSpinLock
  690. /***************************************************************************++
  691. Routine Description:
  692. Acquires an instrumented in-stack-queue spinlock while running at DPC level.
  693. --***************************************************************************/
  694. VOID
  695. UlDbgAcquireInStackQueuedSpinLockAtDpcLevel(
  696. IN PUL_SPIN_LOCK pSpinLock,
  697. OUT PKLOCK_QUEUE_HANDLE pLockHandle,
  698. IN PCSTR pFileName,
  699. IN USHORT LineNumber
  700. )
  701. {
  702. //
  703. // Sanity check.
  704. //
  705. ASSERT( !UlDbgSpinLockOwned( pSpinLock ) );
  706. //
  707. // Acquire the lock.
  708. //
  709. KeAcquireInStackQueuedSpinLockAtDpcLevel(
  710. &pSpinLock->KSpinLock,
  711. pLockHandle
  712. );
  713. //
  714. // Mark it as owned by the current thread.
  715. //
  716. ASSERT( !UlDbgSpinLockOwned( pSpinLock ) );
  717. SET_SPIN_LOCK_OWNED( pSpinLock );
  718. //
  719. // Update the statistics.
  720. //
  721. pSpinLock->AcquisitionsAtDpcLevel++;
  722. pSpinLock->pLastAcquireFileName = pFileName;
  723. pSpinLock->LastAcquireLineNumber = LineNumber;
  724. } // UlDbgAcquireInStackQueuedSpinLockAtDpcLevel
  725. /***************************************************************************++
  726. Routine Description:
  727. Releases an instrumented in-stack-queue spinlock acquired at DPC level.
  728. --***************************************************************************/
  729. VOID
  730. UlDbgReleaseInStackQueuedSpinLockFromDpcLevel(
  731. IN PUL_SPIN_LOCK pSpinLock,
  732. IN PKLOCK_QUEUE_HANDLE pLockHandle,
  733. IN PCSTR pFileName,
  734. IN USHORT LineNumber
  735. )
  736. {
  737. //
  738. // Mark it as unowned.
  739. //
  740. ASSERT( UlDbgSpinLockOwned( pSpinLock ) );
  741. SET_SPIN_LOCK_NOT_OWNED( pSpinLock );
  742. //
  743. // Update the statistics.
  744. //
  745. pSpinLock->ReleasesFromDpcLevel++;
  746. pSpinLock->pLastReleaseFileName = pFileName;
  747. pSpinLock->LastReleaseLineNumber = LineNumber;
  748. //
  749. // Release the lock.
  750. //
  751. KeReleaseInStackQueuedSpinLockFromDpcLevel(
  752. pLockHandle
  753. );
  754. } // UlDbgReleaseInStackQueuedSpinLockFromDpcLevel
  755. /***************************************************************************++
  756. Routine Description:
  757. Determines if the specified spinlock is owned by the current thread.
  758. Arguments:
  759. pSpinLock - Supplies the spinlock to test.
  760. Return Value:
  761. BOOLEAN - TRUE if the spinlock is owned by the current thread, FALSE
  762. otherwise.
  763. --***************************************************************************/
  764. BOOLEAN
  765. UlDbgSpinLockOwned(
  766. IN PUL_SPIN_LOCK pSpinLock
  767. )
  768. {
  769. if (pSpinLock->pOwnerThread == PsGetCurrentThread())
  770. {
  771. ASSERT( pSpinLock->OwnerProcessor == (ULONG)KeGetCurrentProcessorNumber() );
  772. return TRUE;
  773. }
  774. return FALSE;
  775. } // UlDbgSpinLockOwned
  776. /***************************************************************************++
  777. Routine Description:
  778. Determines if the specified spinlock is unowned.
  779. Arguments:
  780. pSpinLock - Supplies the spinlock to test.
  781. Return Value:
  782. BOOLEAN - TRUE if the spinlock is unowned, FALSE otherwise.
  783. --***************************************************************************/
  784. BOOLEAN
  785. UlDbgSpinLockUnowned(
  786. IN PUL_SPIN_LOCK pSpinLock
  787. )
  788. {
  789. if (pSpinLock->pOwnerThread == NULL)
  790. {
  791. return TRUE;
  792. }
  793. return FALSE;
  794. } // UlDbgSpinLockUnowned
  795. /***************************************************************************++
  796. Routine Description:
  797. Filter for exceptions caught with try/except.
  798. Arguments:
  799. pExceptionPointers - Supplies information identifying the source
  800. and type of exception raised.
  801. pFileName - Supplies the name of the file generating the exception.
  802. LineNumber - Supplies the line number of the exception filter that
  803. caught the exception.
  804. Return Value:
  805. LONG - Should always be EXCEPTION_EXECUTE_HANDLER
  806. --***************************************************************************/
  807. LONG
  808. UlDbgExceptionFilter(
  809. IN PEXCEPTION_POINTERS pExceptionPointers,
  810. IN PCSTR pFileName,
  811. IN USHORT LineNumber
  812. )
  813. {
  814. //
  815. // Protect ourselves just in case the process is completely messed up.
  816. //
  817. __try
  818. {
  819. //
  820. // Whine about it.
  821. //
  822. DbgPrint(
  823. "UlDbgExceptionFilter: exception 0x%08lx @ %p, caught in %s:%d\n",
  824. pExceptionPointers->ExceptionRecord->ExceptionCode,
  825. pExceptionPointers->ExceptionRecord->ExceptionAddress,
  826. UlDbgFindFilePart( pFileName ),
  827. LineNumber
  828. );
  829. if (g_UlBreakOnError)
  830. {
  831. DbgBreakPoint();
  832. }
  833. }
  834. __except( EXCEPTION_EXECUTE_HANDLER )
  835. {
  836. //
  837. // Not much we can do here...
  838. //
  839. NOTHING;
  840. }
  841. return EXCEPTION_EXECUTE_HANDLER;
  842. } // UlDbgExceptionFilter
  843. /***************************************************************************++
  844. Routine Description:
  845. Sometimes it's not acceptable to proceed with warnings ( as status ) after
  846. we caught an exception. I.e. Caught a misaligned warning during sendresponse
  847. and called the IoCompleteRequest with status misaligned. This will cause Io
  848. Manager to complete request to port, even though we don't want it to happen.
  849. In that case we have to carefully replace warnings with a generic error.
  850. Arguments:
  851. pExceptionPointers - Supplies information identifying the source
  852. and type of exception raised.
  853. pFileName - Supplies the name of the file generating the exception.
  854. LineNumber - Supplies the line number of the exception filter that
  855. caught the exception.
  856. Return Value:
  857. NTSTATUS - Converted error value : UL_DEFAULT_ERROR_ON_EXCEPTION
  858. --***************************************************************************/
  859. NTSTATUS
  860. UlDbgConvertExceptionCode(
  861. IN NTSTATUS status,
  862. IN PCSTR pFileName,
  863. IN USHORT LineNumber
  864. )
  865. {
  866. //
  867. // Whine about it.
  868. //
  869. DbgPrint(
  870. "UlDbgConvertExceptionCode: "
  871. "exception 0x%08lx converted to 0x%08lx, at %s:%hu\n",
  872. status,
  873. UL_DEFAULT_ERROR_ON_EXCEPTION,
  874. UlDbgFindFilePart( pFileName ),
  875. LineNumber
  876. );
  877. return UL_DEFAULT_ERROR_ON_EXCEPTION;
  878. }
  879. /***************************************************************************++
  880. Routine Description:
  881. Completion handler for incomplete IRP contexts.
  882. Arguments:
  883. pCompletionContext - Supplies an uninterpreted context value
  884. as passed to the asynchronous API.
  885. Status - Supplies the final completion status of the
  886. asynchronous API.
  887. Information - Optionally supplies additional information about
  888. the completed operation, such as the number of bytes
  889. transferred.
  890. --***************************************************************************/
  891. VOID
  892. UlDbgInvalidCompletionRoutine(
  893. IN PVOID pCompletionContext,
  894. IN NTSTATUS Status,
  895. IN ULONG_PTR Information
  896. )
  897. {
  898. UlTrace(TDI, (
  899. "UlDbgInvalidCompletionRoutine called!\n"
  900. " pCompletionContext = %p\n"
  901. " Status = 0x%08lx\n"
  902. " Information = %Iu\n",
  903. pCompletionContext,
  904. Status,
  905. Information
  906. ));
  907. ASSERT( !"UlDbgInvalidCompletionRoutine called!" );
  908. } // UlDbgInvalidCompletionRoutine
  909. /***************************************************************************++
  910. Routine Description:
  911. Hook for catching failed operations. This routine is called within each
  912. routine with the completion status.
  913. Arguments:
  914. Status - Supplies the completion status.
  915. pFileName - Supplies the filename of the caller.
  916. LineNumber - Supplies the line number of the caller.
  917. Return Value:
  918. NTSTATUS - Completion status.
  919. --***************************************************************************/
  920. NTSTATUS
  921. UlDbgStatus(
  922. IN NTSTATUS Status,
  923. IN PCSTR pFileName,
  924. IN USHORT LineNumber
  925. )
  926. {
  927. UNREFERENCED_PARAMETER(pFileName);
  928. UNREFERENCED_PARAMETER(LineNumber);
  929. //
  930. // paulmcd: ignore STATUS_END_OF_FILE. this is a non-fatal return value
  931. //
  932. if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE)
  933. {
  934. if (g_UlVerboseErrors)
  935. {
  936. DbgPrint(
  937. "UlDbgStatus: %s:%hu returning 0x%08lx\n",
  938. UlDbgFindFilePart( pFileName ),
  939. LineNumber,
  940. Status
  941. );
  942. }
  943. if (g_UlBreakOnError)
  944. {
  945. DbgBreakPoint();
  946. }
  947. }
  948. return Status;
  949. } // UlDbgStatus
  950. /***************************************************************************++
  951. Routine Description:
  952. Stop at a breakpoint if g_UlBreakOnError is set
  953. Arguments:
  954. pFileName - Supplies the filename of the caller.
  955. LineNumber - Supplies the line number of the caller.
  956. Return Value:
  957. NTSTATUS - Completion status.
  958. --***************************************************************************/
  959. VOID
  960. UlDbgBreakOnError(
  961. PCSTR pFileName,
  962. ULONG LineNumber
  963. )
  964. {
  965. if (g_UlBreakOnError)
  966. {
  967. DbgPrint(
  968. "HttpCmnDebugBreakOnError @ %s:%hu\n",
  969. UlDbgFindFilePart( pFileName ),
  970. LineNumber
  971. );
  972. DbgBreakPoint();
  973. }
  974. } // UlDbgBreakOnError
  975. /***************************************************************************++
  976. Routine Description:
  977. Routine invoked upon entry into the driver.
  978. Arguments:
  979. pFunctionName - Supplies the name of the function used to enter
  980. the driver.
  981. pIrp - Supplies an optional IRP to log.
  982. pFileName - Supplies the filename of the caller.
  983. LineNumber - Supplies the line number of the caller.
  984. --***************************************************************************/
  985. VOID
  986. UlDbgEnterDriver(
  987. IN PCSTR pFunctionName,
  988. IN PIRP pIrp OPTIONAL,
  989. IN PCSTR pFileName,
  990. IN USHORT LineNumber
  991. )
  992. {
  993. #if ENABLE_THREAD_DBEUG
  994. PUL_DEBUG_THREAD_DATA pData;
  995. #endif
  996. UNREFERENCED_PARAMETER(pFunctionName);
  997. #if !ENABLE_IRP_TRACE
  998. UNREFERENCED_PARAMETER(pFileName);
  999. UNREFERENCED_PARAMETER(LineNumber);
  1000. #endif
  1001. //
  1002. // Log the IRP.
  1003. //
  1004. if (pIrp != NULL)
  1005. {
  1006. WRITE_IRP_TRACE_LOG(
  1007. g_pIrpTraceLog,
  1008. IRP_ACTION_INCOMING_IRP,
  1009. pIrp,
  1010. pFileName,
  1011. LineNumber
  1012. );
  1013. }
  1014. #if ENABLE_THREAD_DBEUG
  1015. //
  1016. // Find/create an entry for the current thread.
  1017. //
  1018. pData = ULP_DBG_FIND_OR_CREATE_THREAD();
  1019. if (pData != NULL)
  1020. {
  1021. //
  1022. // This should be the first time we enter the driver
  1023. // unless we are stealing this thread due to an interrupt,
  1024. // or we are calling another driver and they are calling
  1025. // our completion routine in-line.
  1026. //
  1027. ASSERT( KeGetCurrentIrql() > PASSIVE_LEVEL ||
  1028. pData->ExternalCallCount > 0 ||
  1029. (pData->ResourceCount == 0 && pData->PushLockCount == 0) );
  1030. }
  1031. #endif
  1032. } // UlDbgEnterDriver
  1033. /***************************************************************************++
  1034. Routine Description:
  1035. Routine invoked upon exit from the driver.
  1036. Arguments:
  1037. pFunctionName - Supplies the name of the function used to enter
  1038. the driver.
  1039. pFileName - Supplies the filename of the caller.
  1040. LineNumber - Supplies the line number of the caller.
  1041. --***************************************************************************/
  1042. VOID
  1043. UlDbgLeaveDriver(
  1044. IN PCSTR pFunctionName,
  1045. IN PCSTR pFileName,
  1046. IN USHORT LineNumber
  1047. )
  1048. {
  1049. #if ENABLE_THREAD_DBEUG
  1050. PUL_DEBUG_THREAD_DATA pData;
  1051. #endif
  1052. UNREFERENCED_PARAMETER(pFunctionName);
  1053. UNREFERENCED_PARAMETER(pFileName);
  1054. UNREFERENCED_PARAMETER(LineNumber);
  1055. #if ENABLE_THREAD_DBEUG
  1056. //
  1057. // Find an existing entry for the current thread.
  1058. //
  1059. pData = ULP_DBG_FIND_THREAD();
  1060. if (pData != NULL)
  1061. {
  1062. //
  1063. // Ensure no resources are acquired, then kill the thread data.
  1064. //
  1065. // we might have a resource acquired if we borrowed the thread
  1066. // due to an interrupt.
  1067. //
  1068. // N.B. We dereference the thread data twice: once for the
  1069. // call to ULP_DBG_FIND_THREAD() above, once for the call
  1070. // made when entering the driver.
  1071. //
  1072. ASSERT( KeGetCurrentIrql() > PASSIVE_LEVEL ||
  1073. pData->ExternalCallCount > 0 ||
  1074. (pData->ResourceCount == 0 && pData->PushLockCount == 0) );
  1075. ASSERT( pData->ReferenceCount >= 2 );
  1076. ULP_DBG_DEREFERENCE_THREAD( pData );
  1077. ULP_DBG_DEREFERENCE_THREAD( pData );
  1078. }
  1079. #endif
  1080. } // UlDbgLeaveDriver
  1081. /***************************************************************************++
  1082. Routine Description:
  1083. Initialize an instrumented resource.
  1084. Arguments:
  1085. pResource - Supplies the resource to initialize.
  1086. pResourceName - Supplies a display name for the resource.
  1087. Parameter - Supplies a ULONG_PTR parameter passed into sprintf()
  1088. when creating the resource name.
  1089. pFileName - Supplies the filename of the caller.
  1090. LineNumber - Supplies the line number of the caller.
  1091. Return Value:
  1092. NTSTATUS - Completion status.
  1093. --***************************************************************************/
  1094. NTSTATUS
  1095. UlDbgInitializeResource(
  1096. IN PUL_ERESOURCE pResource,
  1097. IN PCSTR pResourceName,
  1098. IN ULONG_PTR Parameter,
  1099. IN ULONG OwnerTag,
  1100. IN PCSTR pFileName,
  1101. IN USHORT LineNumber
  1102. )
  1103. {
  1104. NTSTATUS status;
  1105. KIRQL oldIrql;
  1106. UNREFERENCED_PARAMETER(pFileName);
  1107. UNREFERENCED_PARAMETER(LineNumber);
  1108. //
  1109. // Initialize the resource.
  1110. //
  1111. status = ExInitializeResourceLite( &pResource->Resource );
  1112. if (NT_SUCCESS(status))
  1113. {
  1114. pResource->ExclusiveRecursionCount = 0;
  1115. pResource->ExclusiveCount = 0;
  1116. pResource->SharedCount = 0;
  1117. pResource->ReleaseCount = 0;
  1118. pResource->OwnerTag = OwnerTag;
  1119. _snprintf(
  1120. (char*) pResource->ResourceName,
  1121. sizeof(pResource->ResourceName) - 1,
  1122. pResourceName,
  1123. Parameter
  1124. );
  1125. pResource->ResourceName[sizeof(pResource->ResourceName) - 1] = '\0';
  1126. SET_RESOURCE_NOT_OWNED_EXCLUSIVE( pResource );
  1127. //
  1128. // Put it on the global list.
  1129. //
  1130. KeAcquireSpinLock( &g_DbgSpinLock, &oldIrql );
  1131. InsertHeadList(
  1132. &g_DbgGlobalResourceListHead,
  1133. &pResource->GlobalResourceListEntry
  1134. );
  1135. KeReleaseSpinLock( &g_DbgSpinLock, oldIrql );
  1136. }
  1137. else
  1138. {
  1139. pResource->GlobalResourceListEntry.Flink = NULL;
  1140. }
  1141. return status;
  1142. } // UlDbgInitializeResource
  1143. /***************************************************************************++
  1144. Routine Description:
  1145. Deletes an instrumented resource.
  1146. Arguments:
  1147. pResource - Supplies the resource to delete.
  1148. pFileName - Supplies the filename of the caller.
  1149. LineNumber - Supplies the line number of the caller.
  1150. Return Value:
  1151. NTSTATUS - Completion status.
  1152. --***************************************************************************/
  1153. NTSTATUS
  1154. UlDbgDeleteResource(
  1155. IN PUL_ERESOURCE pResource,
  1156. IN PCSTR pFileName,
  1157. IN USHORT LineNumber
  1158. )
  1159. {
  1160. NTSTATUS status;
  1161. KIRQL oldIrql;
  1162. PETHREAD pExclusiveOwner;
  1163. UNREFERENCED_PARAMETER(pFileName);
  1164. UNREFERENCED_PARAMETER(LineNumber);
  1165. //
  1166. // Sanity check.
  1167. //
  1168. ASSERT(pResource);
  1169. pExclusiveOwner = pResource->pExclusiveOwner;
  1170. if (pExclusiveOwner != NULL)
  1171. {
  1172. DbgPrint(
  1173. "Resource %p [%s] owned by thread %p\n",
  1174. pResource,
  1175. pResource->ResourceName,
  1176. pExclusiveOwner
  1177. );
  1178. DbgBreakPoint();
  1179. }
  1180. // ASSERT( UlDbgResourceUnownedExclusive( pResource ) );
  1181. //
  1182. // Delete the resource.
  1183. //
  1184. status = ExDeleteResourceLite( &pResource->Resource );
  1185. //
  1186. // Remove it from the global list.
  1187. //
  1188. if (pResource->GlobalResourceListEntry.Flink != NULL)
  1189. {
  1190. KeAcquireSpinLock( &g_DbgSpinLock, &oldIrql );
  1191. RemoveEntryList( &pResource->GlobalResourceListEntry );
  1192. KeReleaseSpinLock( &g_DbgSpinLock, oldIrql );
  1193. }
  1194. return status;
  1195. } // UlDbgDeleteResource
  1196. /***************************************************************************++
  1197. Routine Description:
  1198. Acquires exclusive access to an instrumented resource.
  1199. Arguments:
  1200. pResource - Supplies the resource to acquire.
  1201. Wait - Supplies TRUE if the thread should block waiting for the
  1202. resource.
  1203. pFileName - Supplies the filename of the caller.
  1204. LineNumber - Supplies the line number of the caller.
  1205. Return Value:
  1206. BOOLEAN - Completion status.
  1207. --***************************************************************************/
  1208. BOOLEAN
  1209. UlDbgAcquireResourceExclusive(
  1210. IN PUL_ERESOURCE pResource,
  1211. IN BOOLEAN Wait,
  1212. IN PCSTR pFileName,
  1213. IN USHORT LineNumber
  1214. )
  1215. {
  1216. #if ENABLE_THREAD_DBEUG
  1217. PUL_DEBUG_THREAD_DATA pData;
  1218. #endif
  1219. BOOLEAN result;
  1220. #if !REFERENCE_DEBUG || !ENABLE_THREAD_DBEUG
  1221. UNREFERENCED_PARAMETER(pFileName);
  1222. UNREFERENCED_PARAMETER(LineNumber);
  1223. #endif
  1224. //
  1225. // Sanity check.
  1226. //
  1227. ASSERT(pResource);
  1228. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  1229. //
  1230. // Acquire the resource.
  1231. //
  1232. KeEnterCriticalRegion();
  1233. result = ExAcquireResourceExclusiveLite( &pResource->Resource, Wait );
  1234. // Did we acquire the lock exclusively?
  1235. if (! result)
  1236. {
  1237. KeLeaveCriticalRegion();
  1238. return FALSE;
  1239. }
  1240. #if ENABLE_THREAD_DBEUG
  1241. //
  1242. // Find an existing entry for the current thread.
  1243. //
  1244. pData = ULP_DBG_FIND_THREAD();
  1245. if (pData != NULL)
  1246. {
  1247. //
  1248. // Update the resource count.
  1249. //
  1250. pData->ResourceCount++;
  1251. ASSERT( pData->ResourceCount > 0 );
  1252. WRITE_REF_TRACE_LOG(
  1253. g_pThreadTraceLog,
  1254. REF_ACTION_ACQUIRE_RESOURCE_EXCLUSIVE,
  1255. pData->ResourceCount,
  1256. pResource,
  1257. pFileName,
  1258. LineNumber
  1259. );
  1260. ULP_DBG_DEREFERENCE_THREAD( pData );
  1261. }
  1262. #endif
  1263. //
  1264. // either we already own it (recursive acquisition), or nobody owns it.
  1265. //
  1266. ASSERT( UlDbgResourceUnownedExclusive( pResource ) ||
  1267. UlDbgResourceOwnedExclusive( pResource ) );
  1268. //
  1269. // Mark it as owned by the current thread.
  1270. //
  1271. if (pResource->ExclusiveRecursionCount == 0)
  1272. {
  1273. ASSERT( UlDbgResourceUnownedExclusive( pResource ) );
  1274. SET_RESOURCE_OWNED_EXCLUSIVE( pResource );
  1275. }
  1276. else
  1277. {
  1278. ASSERT( pResource->ExclusiveRecursionCount > 0 );
  1279. ASSERT( UlDbgResourceOwnedExclusive( pResource ) );
  1280. }
  1281. //
  1282. // Update the statistics.
  1283. //
  1284. InterlockedIncrement( &pResource->ExclusiveRecursionCount );
  1285. InterlockedIncrement( &pResource->ExclusiveCount );
  1286. return result;
  1287. } // UlDbgAcquireResourceExclusive
  1288. /***************************************************************************++
  1289. Routine Description:
  1290. Acquires shared access to an instrumented resource.
  1291. Arguments:
  1292. pResource - Supplies the resource to acquire.
  1293. Wait - Supplies TRUE if the thread should block waiting for the
  1294. resource.
  1295. pFileName - Supplies the filename of the caller.
  1296. LineNumber - Supplies the line number of the caller.
  1297. Return Value:
  1298. BOOLEAN - Completion status.
  1299. --***************************************************************************/
  1300. BOOLEAN
  1301. UlDbgAcquireResourceShared(
  1302. IN PUL_ERESOURCE pResource,
  1303. IN BOOLEAN Wait,
  1304. IN PCSTR pFileName,
  1305. IN USHORT LineNumber
  1306. )
  1307. {
  1308. #if ENABLE_THREAD_DBEUG
  1309. PUL_DEBUG_THREAD_DATA pData;
  1310. #endif
  1311. BOOLEAN result;
  1312. //
  1313. // Sanity check.
  1314. //
  1315. ASSERT(pResource);
  1316. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  1317. //
  1318. // Acquire the resource.
  1319. //
  1320. KeEnterCriticalRegion();
  1321. result = ExAcquireResourceSharedLite( &pResource->Resource, Wait );
  1322. // Did we acquire the lock exclusively?
  1323. if (! result)
  1324. {
  1325. KeLeaveCriticalRegion();
  1326. return FALSE;
  1327. }
  1328. #if ENABLE_THREAD_DBEUG
  1329. //
  1330. // Find an existing entry for the current thread.
  1331. //
  1332. pData = ULP_DBG_FIND_THREAD();
  1333. if (pData != NULL)
  1334. {
  1335. //
  1336. // Update the resource count.
  1337. //
  1338. pData->ResourceCount++;
  1339. ASSERT( pData->ResourceCount > 0 );
  1340. WRITE_REF_TRACE_LOG(
  1341. g_pThreadTraceLog,
  1342. REF_ACTION_ACQUIRE_RESOURCE_SHARED,
  1343. pData->ResourceCount,
  1344. pResource,
  1345. pFileName,
  1346. LineNumber
  1347. );
  1348. ULP_DBG_DEREFERENCE_THREAD( pData );
  1349. }
  1350. #else
  1351. UNREFERENCED_PARAMETER(pFileName);
  1352. UNREFERENCED_PARAMETER(LineNumber);
  1353. #endif
  1354. //
  1355. // Sanity check.
  1356. //
  1357. ASSERT( pResource->ExclusiveRecursionCount == 0 );
  1358. ASSERT( UlDbgResourceUnownedExclusive( pResource ) );
  1359. //
  1360. // Update the statistics.
  1361. //
  1362. InterlockedIncrement( &pResource->SharedCount );
  1363. return result;
  1364. } // UlDbgAcquireResourceShared
  1365. /***************************************************************************++
  1366. Routine Description:
  1367. Releases an instrumented resource.
  1368. Arguments:
  1369. pResource - Supplies the resource to release.
  1370. pFileName - Supplies the filename of the caller.
  1371. LineNumber - Supplies the line number of the caller.
  1372. --***************************************************************************/
  1373. VOID
  1374. UlDbgReleaseResource(
  1375. IN PUL_ERESOURCE pResource,
  1376. IN PCSTR pFileName,
  1377. IN USHORT LineNumber
  1378. )
  1379. {
  1380. #if ENABLE_THREAD_DBEUG
  1381. PUL_DEBUG_THREAD_DATA pData;
  1382. //
  1383. // Find an existing entry for the current thread.
  1384. //
  1385. pData = ULP_DBG_FIND_THREAD();
  1386. if (pData != NULL)
  1387. {
  1388. //
  1389. // Update the resource count.
  1390. //
  1391. ASSERT( pData->ResourceCount > 0 );
  1392. pData->ResourceCount--;
  1393. WRITE_REF_TRACE_LOG(
  1394. g_pThreadTraceLog,
  1395. REF_ACTION_RELEASE_RESOURCE,
  1396. pData->ResourceCount,
  1397. pResource,
  1398. pFileName,
  1399. LineNumber
  1400. );
  1401. ULP_DBG_DEREFERENCE_THREAD( pData );
  1402. }
  1403. #else
  1404. UNREFERENCED_PARAMETER(pFileName);
  1405. UNREFERENCED_PARAMETER(LineNumber);
  1406. #endif
  1407. //
  1408. // Handle recursive acquisitions.
  1409. //
  1410. if (pResource->ExclusiveRecursionCount > 0)
  1411. {
  1412. ASSERT( UlDbgResourceOwnedExclusive( pResource ) );
  1413. InterlockedDecrement( &pResource->ExclusiveRecursionCount );
  1414. if (pResource->ExclusiveRecursionCount == 0)
  1415. {
  1416. //
  1417. // Mark it as unowned.
  1418. //
  1419. SET_RESOURCE_NOT_OWNED_EXCLUSIVE( pResource );
  1420. }
  1421. }
  1422. else
  1423. {
  1424. ASSERT( pResource->ExclusiveRecursionCount == 0 );
  1425. ASSERT( UlDbgResourceUnownedExclusive( pResource ) );
  1426. }
  1427. //
  1428. // Release the resource.
  1429. //
  1430. ExReleaseResourceLite( &pResource->Resource );
  1431. KeLeaveCriticalRegion();
  1432. //
  1433. // Update the statistics.
  1434. //
  1435. InterlockedIncrement( &pResource->ReleaseCount );
  1436. } // UlDbgReleaseResource
  1437. /***************************************************************************++
  1438. Routine Description:
  1439. This routine converts the specified resource from acquired for exclusive
  1440. access to acquired for shared access.
  1441. Arguments:
  1442. pResource - Supplies the resource to release.
  1443. pFileName - Supplies the filename of the caller.
  1444. LineNumber - Supplies the line number of the caller.
  1445. --***************************************************************************/
  1446. VOID
  1447. UlDbgConvertExclusiveToShared(
  1448. IN PUL_ERESOURCE pResource,
  1449. IN PCSTR pFileName,
  1450. IN USHORT LineNumber
  1451. )
  1452. {
  1453. #if ENABLE_THREAD_DBEUG
  1454. PUL_DEBUG_THREAD_DATA pData;
  1455. //
  1456. // Find an existing entry for the current thread.
  1457. //
  1458. pData = ULP_DBG_FIND_THREAD();
  1459. if (pData != NULL)
  1460. {
  1461. //
  1462. // Don't update the resource count.
  1463. //
  1464. WRITE_REF_TRACE_LOG(
  1465. g_pThreadTraceLog,
  1466. REF_ACTION_CONVERT_RESOURCE_EXCLUSIVE_TO_SHARED,
  1467. pData->ResourceCount,
  1468. pResource,
  1469. pFileName,
  1470. LineNumber
  1471. );
  1472. ULP_DBG_DEREFERENCE_THREAD( pData );
  1473. }
  1474. #else
  1475. UNREFERENCED_PARAMETER(pFileName);
  1476. UNREFERENCED_PARAMETER(LineNumber);
  1477. #endif
  1478. ASSERT(UlDbgResourceOwnedExclusive(pResource));
  1479. //
  1480. // Resource will no longer be owned exclusively.
  1481. //
  1482. pResource->ExclusiveRecursionCount = 0;
  1483. SET_RESOURCE_NOT_OWNED_EXCLUSIVE( pResource );
  1484. //
  1485. // Acquire the resource.
  1486. //
  1487. ExConvertExclusiveToSharedLite( &pResource->Resource );
  1488. //
  1489. // Update the statistics.
  1490. //
  1491. InterlockedIncrement( &pResource->SharedCount );
  1492. } // UlDbgConvertExclusiveToShared
  1493. /***************************************************************************++
  1494. Routine Description:
  1495. The routine attempts to acquire the specified resource for exclusive
  1496. access.
  1497. Arguments:
  1498. pResource - Supplies the resource to release.
  1499. pFileName - Supplies the filename of the caller.
  1500. LineNumber - Supplies the line number of the caller.
  1501. --***************************************************************************/
  1502. BOOLEAN
  1503. UlDbgTryToAcquireResourceExclusive(
  1504. IN PUL_ERESOURCE pResource,
  1505. IN PCSTR pFileName,
  1506. IN USHORT LineNumber
  1507. )
  1508. {
  1509. #if ENABLE_THREAD_DBEUG
  1510. PUL_DEBUG_THREAD_DATA pData;
  1511. #endif
  1512. BOOLEAN result;
  1513. //
  1514. // Sanity check.
  1515. //
  1516. ASSERT(pResource);
  1517. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  1518. //
  1519. // Acquire the resource.
  1520. //
  1521. KeEnterCriticalRegion();
  1522. result = ExAcquireResourceExclusiveLite( &pResource->Resource, FALSE );
  1523. //
  1524. // Did we acquire the lock exclusively?
  1525. //
  1526. if (!result)
  1527. {
  1528. KeLeaveCriticalRegion();
  1529. return FALSE;
  1530. }
  1531. #if ENABLE_THREAD_DBEUG
  1532. //
  1533. // Find an existing entry for the current thread.
  1534. //
  1535. pData = ULP_DBG_FIND_THREAD();
  1536. if (pData != NULL)
  1537. {
  1538. //
  1539. // Update the resource count.
  1540. //
  1541. pData->ResourceCount++;
  1542. ASSERT( pData->ResourceCount > 0 );
  1543. WRITE_REF_TRACE_LOG(
  1544. g_pThreadTraceLog,
  1545. REF_ACTION_TRY_ACQUIRE_RESOURCE_EXCLUSIVE,
  1546. pData->ResourceCount,
  1547. pResource,
  1548. pFileName,
  1549. LineNumber
  1550. );
  1551. ULP_DBG_DEREFERENCE_THREAD( pData );
  1552. }
  1553. #else
  1554. UNREFERENCED_PARAMETER(pFileName);
  1555. UNREFERENCED_PARAMETER(LineNumber);
  1556. #endif
  1557. //
  1558. // either we already own it (recursive acquisition), or nobody owns it.
  1559. //
  1560. ASSERT( UlDbgResourceUnownedExclusive( pResource ) ||
  1561. UlDbgResourceOwnedExclusive( pResource ) );
  1562. //
  1563. // Mark it as owned by the current thread.
  1564. //
  1565. if (pResource->ExclusiveRecursionCount == 0)
  1566. {
  1567. ASSERT( UlDbgResourceUnownedExclusive( pResource ) );
  1568. SET_RESOURCE_OWNED_EXCLUSIVE( pResource );
  1569. }
  1570. else
  1571. {
  1572. ASSERT( pResource->ExclusiveRecursionCount > 0 );
  1573. ASSERT( UlDbgResourceOwnedExclusive ( pResource ) );
  1574. }
  1575. //
  1576. // Update the statistics.
  1577. //
  1578. InterlockedIncrement( &pResource->ExclusiveRecursionCount );
  1579. InterlockedIncrement( &pResource->ExclusiveCount );
  1580. return result;
  1581. } // UlDbgTryToAcquireResourceExclusive
  1582. /***************************************************************************++
  1583. Routine Description:
  1584. Determines if the specified resource is owned exclusively by the
  1585. current thread.
  1586. Arguments:
  1587. pResource - Supplies the resource to test.
  1588. Return Value:
  1589. BOOLEAN - TRUE if the resource is owned exclusively by the current
  1590. thread, FALSE otherwise.
  1591. --***************************************************************************/
  1592. BOOLEAN
  1593. UlDbgResourceOwnedExclusive(
  1594. IN PUL_ERESOURCE pResource
  1595. )
  1596. {
  1597. if (pResource->pExclusiveOwner == PsGetCurrentThread())
  1598. {
  1599. return TRUE;
  1600. }
  1601. return FALSE;
  1602. } // UlDbgResourceOwnedExclusive
  1603. /***************************************************************************++
  1604. Routine Description:
  1605. Determines if the specified resource is not currently owned exclusively
  1606. by any thread.
  1607. Arguments:
  1608. pResource - Supplies the resource to test.
  1609. Return Value:
  1610. BOOLEAN - TRUE if the resource is not currently owned exclusively by
  1611. any thread, FALSE otherwise.
  1612. --***************************************************************************/
  1613. BOOLEAN
  1614. UlDbgResourceUnownedExclusive(
  1615. IN PUL_ERESOURCE pResource
  1616. )
  1617. {
  1618. if (pResource->pExclusiveOwner == NULL)
  1619. {
  1620. return TRUE;
  1621. }
  1622. return FALSE;
  1623. } // UlDbgResourceUnownedExclusive
  1624. /***************************************************************************++
  1625. Routine Description:
  1626. Initialize an instrumented push lock.
  1627. Arguments:
  1628. pPushLock - Supplies the push lock to initialize.
  1629. pPushLockName - Supplies a display name for the push lock.
  1630. Parameter - Supplies a ULONG_PTR parameter passed into sprintf()
  1631. when creating the push lock name.
  1632. pFileName - Supplies the filename of the caller.
  1633. LineNumber - Supplies the line number of the caller.
  1634. Return Value:
  1635. None
  1636. --***************************************************************************/
  1637. VOID
  1638. UlDbgInitializePushLock(
  1639. IN PUL_PUSH_LOCK pPushLock,
  1640. IN PCSTR pPushLockName,
  1641. IN ULONG_PTR Parameter,
  1642. IN ULONG OwnerTag,
  1643. IN PCSTR pFileName,
  1644. IN USHORT LineNumber
  1645. )
  1646. {
  1647. KIRQL oldIrql;
  1648. UNREFERENCED_PARAMETER(pFileName);
  1649. UNREFERENCED_PARAMETER(LineNumber);
  1650. //
  1651. // Initialize the push lock.
  1652. //
  1653. ExInitializePushLock( &pPushLock->PushLock );
  1654. pPushLock->ExclusiveCount = 0;
  1655. pPushLock->SharedCount = 0;
  1656. pPushLock->ReleaseCount = 0;
  1657. pPushLock->OwnerTag = OwnerTag;
  1658. _snprintf(
  1659. (char*) pPushLock->PushLockName,
  1660. sizeof(pPushLock->PushLockName) - 1,
  1661. pPushLockName,
  1662. Parameter
  1663. );
  1664. pPushLock->PushLockName[sizeof(pPushLock->PushLockName) - 1] = '\0';
  1665. SET_PUSH_LOCK_NOT_OWNED_EXCLUSIVE( pPushLock );
  1666. //
  1667. // Put it on the global list.
  1668. //
  1669. KeAcquireSpinLock( &g_DbgSpinLock, &oldIrql );
  1670. InsertHeadList(
  1671. &g_DbgGlobalPushLockListHead,
  1672. &pPushLock->GlobalPushLockListEntry
  1673. );
  1674. KeReleaseSpinLock( &g_DbgSpinLock, oldIrql );
  1675. } // UlDbgInitializePushLock
  1676. /***************************************************************************++
  1677. Routine Description:
  1678. Deletes an instrumented push lock.
  1679. Arguments:
  1680. pPushLock - Supplies the push lock to delete.
  1681. pFileName - Supplies the filename of the caller.
  1682. LineNumber - Supplies the line number of the caller.
  1683. Return Value:
  1684. None
  1685. --***************************************************************************/
  1686. VOID
  1687. UlDbgDeletePushLock(
  1688. IN PUL_PUSH_LOCK pPushLock,
  1689. IN PCSTR pFileName,
  1690. IN USHORT LineNumber
  1691. )
  1692. {
  1693. KIRQL oldIrql;
  1694. PETHREAD pExclusiveOwner;
  1695. UNREFERENCED_PARAMETER(pFileName);
  1696. UNREFERENCED_PARAMETER(LineNumber);
  1697. //
  1698. // Sanity check.
  1699. //
  1700. ASSERT(pPushLock);
  1701. pExclusiveOwner = pPushLock->pExclusiveOwner;
  1702. if (pExclusiveOwner != NULL)
  1703. {
  1704. DbgPrint(
  1705. "PushLock %p [%s] owned by thread %p\n",
  1706. pPushLock,
  1707. pPushLock->PushLockName,
  1708. pExclusiveOwner
  1709. );
  1710. DbgBreakPoint();
  1711. }
  1712. ASSERT( UlDbgPushLockUnownedExclusive( pPushLock ) );
  1713. //
  1714. // Remove it from the global list.
  1715. //
  1716. if (pPushLock->GlobalPushLockListEntry.Flink != NULL)
  1717. {
  1718. KeAcquireSpinLock( &g_DbgSpinLock, &oldIrql );
  1719. RemoveEntryList( &pPushLock->GlobalPushLockListEntry );
  1720. KeReleaseSpinLock( &g_DbgSpinLock, oldIrql );
  1721. }
  1722. } // UlDbgDeletePushLock
  1723. /***************************************************************************++
  1724. Routine Description:
  1725. Acquires exclusive access to an instrumented push lock.
  1726. Arguments:
  1727. pPushLock - Supplies the push lock to acquire.
  1728. pFileName - Supplies the filename of the caller.
  1729. LineNumber - Supplies the line number of the caller.
  1730. Return Value:
  1731. None
  1732. --***************************************************************************/
  1733. VOID
  1734. UlDbgAcquirePushLockExclusive(
  1735. IN PUL_PUSH_LOCK pPushLock,
  1736. IN PCSTR pFileName,
  1737. IN USHORT LineNumber
  1738. )
  1739. {
  1740. #if ENABLE_THREAD_DBEUG
  1741. PUL_DEBUG_THREAD_DATA pData;
  1742. //
  1743. // Find an existing entry for the current thread.
  1744. //
  1745. pData = ULP_DBG_FIND_THREAD();
  1746. if (pData != NULL)
  1747. {
  1748. //
  1749. // Update the push lock count.
  1750. //
  1751. pData->PushLockCount++;
  1752. ASSERT( pData->PushLockCount > 0 );
  1753. WRITE_REF_TRACE_LOG(
  1754. g_pThreadTraceLog,
  1755. REF_ACTION_ACQUIRE_PUSH_LOCK_EXCLUSIVE,
  1756. pData->PushLockCount,
  1757. pPushLock,
  1758. pFileName,
  1759. LineNumber
  1760. );
  1761. ULP_DBG_DEREFERENCE_THREAD( pData );
  1762. }
  1763. #else
  1764. UNREFERENCED_PARAMETER(pFileName);
  1765. UNREFERENCED_PARAMETER(LineNumber);
  1766. #endif
  1767. //
  1768. // Sanity check.
  1769. //
  1770. ASSERT( pPushLock );
  1771. ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
  1772. //
  1773. // Acquire the push lock.
  1774. //
  1775. KeEnterCriticalRegion();
  1776. ExAcquirePushLockExclusive( &pPushLock->PushLock );
  1777. //
  1778. // Mark it as owned by the current thread.
  1779. //
  1780. ASSERT( UlDbgPushLockUnownedExclusive( pPushLock ) );
  1781. SET_PUSH_LOCK_OWNED_EXCLUSIVE( pPushLock );
  1782. //
  1783. // Update the statistics.
  1784. //
  1785. InterlockedIncrement( &pPushLock->ExclusiveCount );
  1786. } // UlDbgAcquirePushLockExclusive
  1787. /***************************************************************************++
  1788. Routine Description:
  1789. Releases an instrumented push lock that was acquired exclusive.
  1790. Arguments:
  1791. pPushLock - Supplies the push lock to release.
  1792. pFileName - Supplies the filename of the caller.
  1793. LineNumber - Supplies the line number of the caller.
  1794. Return Value:
  1795. None
  1796. --***************************************************************************/
  1797. VOID
  1798. UlDbgReleasePushLockExclusive(
  1799. IN PUL_PUSH_LOCK pPushLock,
  1800. IN PCSTR pFileName,
  1801. IN USHORT LineNumber
  1802. )
  1803. {
  1804. #if ENABLE_THREAD_DBEUG
  1805. PUL_DEBUG_THREAD_DATA pData;
  1806. //
  1807. // Find an existing entry for the current thread.
  1808. //
  1809. pData = ULP_DBG_FIND_THREAD();
  1810. if (pData != NULL)
  1811. {
  1812. //
  1813. // Update the push lock count.
  1814. //
  1815. ASSERT( pData->PushLockCount > 0 );
  1816. pData->PushLockCount--;
  1817. WRITE_REF_TRACE_LOG(
  1818. g_pThreadTraceLog,
  1819. REF_ACTION_RELEASE_PUSH_LOCK,
  1820. pData->PushLockCount,
  1821. pPushLock,
  1822. pFileName,
  1823. LineNumber
  1824. );
  1825. ULP_DBG_DEREFERENCE_THREAD( pData );
  1826. }
  1827. #else
  1828. UNREFERENCED_PARAMETER(pFileName);
  1829. UNREFERENCED_PARAMETER(LineNumber);
  1830. #endif
  1831. //
  1832. // Mark it as unowned.
  1833. //
  1834. ASSERT( UlDbgPushLockOwnedExclusive( pPushLock ) );
  1835. SET_PUSH_LOCK_NOT_OWNED_EXCLUSIVE( pPushLock );
  1836. //
  1837. // Release the push lock.
  1838. //
  1839. ExReleasePushLockExclusive( &pPushLock->PushLock );
  1840. KeLeaveCriticalRegion();
  1841. //
  1842. // Update the statistics.
  1843. //
  1844. InterlockedIncrement( &pPushLock->ReleaseCount );
  1845. } // UlDbgReleasePushLockExclusive
  1846. /***************************************************************************++
  1847. Routine Description:
  1848. Acquires shared access to an instrumented push lock.
  1849. Arguments:
  1850. pPushLock - Supplies the push lock to acquire.
  1851. pFileName - Supplies the filename of the caller.
  1852. LineNumber - Supplies the line number of the caller.
  1853. Return Value:
  1854. None
  1855. --***************************************************************************/
  1856. VOID
  1857. UlDbgAcquirePushLockShared(
  1858. IN PUL_PUSH_LOCK pPushLock,
  1859. IN PCSTR pFileName,
  1860. IN USHORT LineNumber
  1861. )
  1862. {
  1863. #if ENABLE_THREAD_DBEUG
  1864. PUL_DEBUG_THREAD_DATA pData;
  1865. //
  1866. // Find an existing entry for the current thread.
  1867. //
  1868. pData = ULP_DBG_FIND_THREAD();
  1869. if (pData != NULL)
  1870. {
  1871. //
  1872. // Update the push lock count.
  1873. //
  1874. pData->PushLockCount++;
  1875. ASSERT( pData->PushLockCount > 0 );
  1876. WRITE_REF_TRACE_LOG(
  1877. g_pThreadTraceLog,
  1878. REF_ACTION_ACQUIRE_PUSH_LOCK_SHARED,
  1879. pData->PushLockCount,
  1880. pPushLock,
  1881. pFileName,
  1882. LineNumber
  1883. );
  1884. ULP_DBG_DEREFERENCE_THREAD( pData );
  1885. }
  1886. #else
  1887. UNREFERENCED_PARAMETER(pFileName);
  1888. UNREFERENCED_PARAMETER(LineNumber);
  1889. #endif
  1890. //
  1891. // Sanity check.
  1892. //
  1893. ASSERT( pPushLock );
  1894. ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
  1895. //
  1896. // Acquire the push lock.
  1897. //
  1898. KeEnterCriticalRegion();
  1899. ExAcquirePushLockShared( &pPushLock->PushLock );
  1900. //
  1901. // Update the statistics.
  1902. //
  1903. InterlockedIncrement( &pPushLock->SharedCount );
  1904. } // UlDbgAcquirePushLockShared
  1905. /***************************************************************************++
  1906. Routine Description:
  1907. Releases an instrumented push lock that was acquired shared.
  1908. Arguments:
  1909. pPushLock - Supplies the push lock to release.
  1910. pFileName - Supplies the filename of the caller.
  1911. LineNumber - Supplies the line number of the caller.
  1912. Return Value:
  1913. None
  1914. --***************************************************************************/
  1915. VOID
  1916. UlDbgReleasePushLockShared(
  1917. IN PUL_PUSH_LOCK pPushLock,
  1918. IN PCSTR pFileName,
  1919. IN USHORT LineNumber
  1920. )
  1921. {
  1922. #if ENABLE_THREAD_DBEUG
  1923. PUL_DEBUG_THREAD_DATA pData;
  1924. //
  1925. // Find an existing entry for the current thread.
  1926. //
  1927. pData = ULP_DBG_FIND_THREAD();
  1928. if (pData != NULL)
  1929. {
  1930. //
  1931. // Update the push lock count.
  1932. //
  1933. ASSERT( pData->PushLockCount > 0 );
  1934. pData->PushLockCount--;
  1935. WRITE_REF_TRACE_LOG(
  1936. g_pThreadTraceLog,
  1937. REF_ACTION_RELEASE_PUSH_LOCK,
  1938. pData->PushLockCount,
  1939. pPushLock,
  1940. pFileName,
  1941. LineNumber
  1942. );
  1943. ULP_DBG_DEREFERENCE_THREAD( pData );
  1944. }
  1945. #else
  1946. UNREFERENCED_PARAMETER(pFileName);
  1947. UNREFERENCED_PARAMETER(LineNumber);
  1948. #endif
  1949. //
  1950. // Mark it as unowned.
  1951. //
  1952. ASSERT( UlDbgPushLockUnownedExclusive( pPushLock ) );
  1953. SET_PUSH_LOCK_NOT_OWNED_EXCLUSIVE( pPushLock );
  1954. //
  1955. // Release the push lock.
  1956. //
  1957. ExReleasePushLockShared( &pPushLock->PushLock );
  1958. KeLeaveCriticalRegion();
  1959. //
  1960. // Update the statistics.
  1961. //
  1962. InterlockedIncrement( &pPushLock->ReleaseCount );
  1963. } // UlDbgReleasePushLockShared
  1964. /***************************************************************************++
  1965. Routine Description:
  1966. Releases an instrumented push lock.
  1967. Arguments:
  1968. pPushLock - Supplies the push lock to release.
  1969. pFileName - Supplies the filename of the caller.
  1970. LineNumber - Supplies the line number of the caller.
  1971. Return Value:
  1972. None
  1973. --***************************************************************************/
  1974. VOID
  1975. UlDbgReleasePushLock(
  1976. IN PUL_PUSH_LOCK pPushLock,
  1977. IN PCSTR pFileName,
  1978. IN USHORT LineNumber
  1979. )
  1980. {
  1981. #if ENABLE_THREAD_DBEUG
  1982. PUL_DEBUG_THREAD_DATA pData;
  1983. //
  1984. // Find an existing entry for the current thread.
  1985. //
  1986. pData = ULP_DBG_FIND_THREAD();
  1987. if (pData != NULL)
  1988. {
  1989. //
  1990. // Update the push lock count.
  1991. //
  1992. ASSERT( pData->PushLockCount > 0 );
  1993. pData->PushLockCount--;
  1994. WRITE_REF_TRACE_LOG(
  1995. g_pThreadTraceLog,
  1996. REF_ACTION_RELEASE_PUSH_LOCK,
  1997. pData->PushLockCount,
  1998. pPushLock,
  1999. pFileName,
  2000. LineNumber
  2001. );
  2002. ULP_DBG_DEREFERENCE_THREAD( pData );
  2003. }
  2004. #else
  2005. UNREFERENCED_PARAMETER(pFileName);
  2006. UNREFERENCED_PARAMETER(LineNumber);
  2007. #endif
  2008. //
  2009. // Mark it as unowned.
  2010. //
  2011. SET_PUSH_LOCK_NOT_OWNED_EXCLUSIVE( pPushLock );
  2012. //
  2013. // Release the push lock.
  2014. //
  2015. ExReleasePushLock( &pPushLock->PushLock );
  2016. KeLeaveCriticalRegion();
  2017. //
  2018. // Update the statistics.
  2019. //
  2020. InterlockedIncrement( &pPushLock->ReleaseCount );
  2021. } // UlDbgReleasePushLock
  2022. /***************************************************************************++
  2023. Routine Description:
  2024. Determines if the specified push lock is owned exclusively by the
  2025. current thread.
  2026. Arguments:
  2027. pPushLock - Supplies the push lock to test.
  2028. Return Value:
  2029. BOOLEAN - TRUE if the push lock is owned exclusively by the current
  2030. thread, FALSE otherwise.
  2031. --***************************************************************************/
  2032. BOOLEAN
  2033. UlDbgPushLockOwnedExclusive(
  2034. IN PUL_PUSH_LOCK pPushLock
  2035. )
  2036. {
  2037. if (pPushLock->pExclusiveOwner == PsGetCurrentThread())
  2038. {
  2039. return TRUE;
  2040. }
  2041. return FALSE;
  2042. } // UlDbgPushLockOwnedExclusive
  2043. /***************************************************************************++
  2044. Routine Description:
  2045. Determines if the specified push lock is not currently owned exclusively
  2046. by any thread.
  2047. Arguments:
  2048. pPushLock - Supplies the push lock to test.
  2049. Return Value:
  2050. BOOLEAN - TRUE if the push lock is not currently owned exclusively by
  2051. any thread, FALSE otherwise.
  2052. --***************************************************************************/
  2053. BOOLEAN
  2054. UlDbgPushLockUnownedExclusive(
  2055. IN PUL_PUSH_LOCK pPushLock
  2056. )
  2057. {
  2058. if (pPushLock->pExclusiveOwner == NULL)
  2059. {
  2060. return TRUE;
  2061. }
  2062. return FALSE;
  2063. } // UlDbgPushLockUnownedExclusive
  2064. VOID
  2065. UlDbgDumpRequestBuffer(
  2066. IN struct _UL_REQUEST_BUFFER *pBuffer,
  2067. IN PCSTR pName
  2068. )
  2069. {
  2070. DbgPrint(
  2071. "%s @ %p\n"
  2072. " Signature = %08lx\n"
  2073. " ListEntry @ %p%s\n"
  2074. " pConnection = %p\n"
  2075. " WorkItem @ %p\n"
  2076. " UsedBytes = %lu\n"
  2077. " AllocBytes = %lu\n"
  2078. " ParsedBytes = %lu\n"
  2079. " BufferNumber = %lu\n"
  2080. " FromLookaside = %lu\n"
  2081. " pBuffer @ %p\n",
  2082. pName,
  2083. pBuffer,
  2084. pBuffer->Signature,
  2085. &pBuffer->ListEntry,
  2086. IsListEmpty( &pBuffer->ListEntry ) ? " EMPTY" : "",
  2087. pBuffer->pConnection,
  2088. &pBuffer->WorkItem,
  2089. pBuffer->UsedBytes,
  2090. pBuffer->AllocBytes,
  2091. pBuffer->ParsedBytes,
  2092. pBuffer->BufferNumber,
  2093. pBuffer->FromLookaside,
  2094. &pBuffer->pBuffer[0]
  2095. );
  2096. } // UlDbgDumpRequestBuffer
  2097. VOID
  2098. UlDbgDumpHttpConnection(
  2099. IN struct _UL_HTTP_CONNECTION *pConnection,
  2100. IN PCSTR pName
  2101. )
  2102. {
  2103. DbgPrint(
  2104. "%s @ %p\n"
  2105. " Signature = %08lx\n"
  2106. " ConnectionId = %08lx%08lx\n"
  2107. " WorkItem @ %p\n"
  2108. " RefCount = %lu\n"
  2109. " NextRecvNumber = %lu\n"
  2110. " NextBufferNumber = %lu\n"
  2111. " NextBufferToParse = %lu\n"
  2112. " pConnection = %p\n"
  2113. " pRequest = %p\n",
  2114. pName,
  2115. pConnection,
  2116. pConnection->Signature,
  2117. pConnection->ConnectionId,
  2118. &pConnection->WorkItem,
  2119. pConnection->RefCount,
  2120. pConnection->NextRecvNumber,
  2121. pConnection->NextBufferNumber,
  2122. pConnection->NextBufferToParse,
  2123. pConnection->pConnection,
  2124. pConnection->pRequest
  2125. );
  2126. DbgPrint(
  2127. "%s @ %p (cont.)\n"
  2128. " PushLock @ %p\n"
  2129. " BufferHead @ %p%s\n"
  2130. " pCurrentBuffer = %p\n"
  2131. " NeedMoreData = %lu\n"
  2132. #if REFERENCE_DEBUG
  2133. " pTraceLog = %p\n"
  2134. #endif
  2135. ,
  2136. pName,
  2137. pConnection,
  2138. &pConnection->PushLock,
  2139. &pConnection->BufferHead,
  2140. IsListEmpty( &pConnection->BufferHead ) ? " EMPTY" : "",
  2141. pConnection->pCurrentBuffer,
  2142. pConnection->NeedMoreData
  2143. #if REFERENCE_DEBUG
  2144. ,
  2145. pConnection->pConnection->pHttpTraceLog
  2146. #endif
  2147. );
  2148. } // UlDbgDumpHttpConnection
  2149. PIRP
  2150. UlDbgAllocateIrp(
  2151. IN CCHAR StackSize,
  2152. IN BOOLEAN ChargeQuota,
  2153. IN PCSTR pFileName,
  2154. IN USHORT LineNumber
  2155. )
  2156. {
  2157. PIRP pIrp;
  2158. #if !ENABLE_IRP_TRACE
  2159. UNREFERENCED_PARAMETER(pFileName);
  2160. UNREFERENCED_PARAMETER(LineNumber);
  2161. #endif
  2162. pIrp = IoAllocateIrp( StackSize, ChargeQuota );
  2163. if (pIrp != NULL)
  2164. {
  2165. WRITE_IRP_TRACE_LOG(
  2166. g_pIrpTraceLog,
  2167. IRP_ACTION_ALLOCATE_IRP,
  2168. pIrp,
  2169. pFileName,
  2170. LineNumber
  2171. );
  2172. }
  2173. return pIrp;
  2174. } // UlDbgAllocateIrp
  2175. BOOLEAN g_ReallyFreeIrps = TRUE;
  2176. VOID
  2177. UlDbgFreeIrp(
  2178. IN PIRP pIrp,
  2179. IN PCSTR pFileName,
  2180. IN USHORT LineNumber
  2181. )
  2182. {
  2183. #if !ENABLE_IRP_TRACE
  2184. UNREFERENCED_PARAMETER(pFileName);
  2185. UNREFERENCED_PARAMETER(LineNumber);
  2186. #endif
  2187. WRITE_IRP_TRACE_LOG(
  2188. g_pIrpTraceLog,
  2189. IRP_ACTION_FREE_IRP,
  2190. pIrp,
  2191. pFileName,
  2192. LineNumber
  2193. );
  2194. if (g_ReallyFreeIrps)
  2195. {
  2196. IoFreeIrp( pIrp );
  2197. }
  2198. } // UlDbgFreeIrp
  2199. NTSTATUS
  2200. UlDbgCallDriver(
  2201. IN PDEVICE_OBJECT pDeviceObject,
  2202. IN OUT PIRP pIrp,
  2203. IN PCSTR pFileName,
  2204. IN USHORT LineNumber
  2205. )
  2206. {
  2207. #if ENABLE_THREAD_DBEUG
  2208. PUL_DEBUG_THREAD_DATA pData;
  2209. #endif
  2210. NTSTATUS Status;
  2211. #if !ENABLE_IRP_TRACE
  2212. UNREFERENCED_PARAMETER(pFileName);
  2213. UNREFERENCED_PARAMETER(LineNumber);
  2214. #endif
  2215. #if ENABLE_THREAD_DBEUG
  2216. //
  2217. // Record the fact that we are about to call another
  2218. // driver in the thread data. That way if the driver
  2219. // calls our completion routine in-line our debug
  2220. // code won't get confused about it.
  2221. //
  2222. //
  2223. // Find an existing entry for the current thread.
  2224. //
  2225. pData = ULP_DBG_FIND_THREAD();
  2226. if (pData != NULL)
  2227. {
  2228. //
  2229. // Update the external call count.
  2230. //
  2231. pData->ExternalCallCount++;
  2232. ASSERT( pData->ExternalCallCount > 0 );
  2233. }
  2234. #endif
  2235. WRITE_IRP_TRACE_LOG(
  2236. g_pIrpTraceLog,
  2237. IRP_ACTION_CALL_DRIVER,
  2238. pIrp,
  2239. pFileName,
  2240. LineNumber
  2241. );
  2242. //
  2243. // Call the driver.
  2244. //
  2245. Status = IoCallDriver( pDeviceObject, pIrp );
  2246. #if ENABLE_THREAD_DBEUG
  2247. //
  2248. // Update the external call count.
  2249. //
  2250. if (pData != NULL)
  2251. {
  2252. pData->ExternalCallCount--;
  2253. ASSERT( pData->ExternalCallCount >= 0 );
  2254. ULP_DBG_DEREFERENCE_THREAD( pData );
  2255. }
  2256. #endif
  2257. return Status;
  2258. } // UlDbgCallDriver
  2259. VOID
  2260. UlDbgCompleteRequest(
  2261. IN PIRP pIrp,
  2262. IN CCHAR PriorityBoost,
  2263. IN PCSTR pFileName,
  2264. IN USHORT LineNumber
  2265. )
  2266. {
  2267. WRITE_IRP_TRACE_LOG(
  2268. g_pIrpTraceLog,
  2269. IRP_ACTION_COMPLETE_IRP,
  2270. pIrp,
  2271. pFileName,
  2272. LineNumber
  2273. );
  2274. UlTrace(IOCTL,
  2275. ("UlCompleteRequest(%p): status=0x%x, info=%Iu, boost=%d "
  2276. "@ \"%s\", %hu\n",
  2277. pIrp,
  2278. pIrp->IoStatus.Status,
  2279. pIrp->IoStatus.Information,
  2280. (int) PriorityBoost,
  2281. UlDbgFindFilePart( pFileName ),
  2282. LineNumber
  2283. ));
  2284. IF_DEBUG2BOTH(IOCTL, VERBOSE)
  2285. {
  2286. PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( pIrp );
  2287. ULONG BufferLength
  2288. = (ULONG) pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  2289. if (NULL != pIrp->MdlAddress && 0 != BufferLength)
  2290. {
  2291. PUCHAR pOutputBuffer
  2292. = (PUCHAR) MmGetSystemAddressForMdlSafe(
  2293. pIrp->MdlAddress,
  2294. LowPagePriority
  2295. );
  2296. if (NULL != pOutputBuffer)
  2297. {
  2298. UlDbgPrettyPrintBuffer(
  2299. pOutputBuffer,
  2300. MIN(pIrp->IoStatus.Information, BufferLength)
  2301. );
  2302. }
  2303. }
  2304. }
  2305. IoCompleteRequest( pIrp, PriorityBoost );
  2306. } // UlDbgCompleteRequest
  2307. PMDL
  2308. UlDbgAllocateMdl(
  2309. IN PVOID VirtualAddress,
  2310. IN ULONG Length,
  2311. IN BOOLEAN SecondaryBuffer,
  2312. IN BOOLEAN ChargeQuota,
  2313. IN OUT PIRP Irp,
  2314. IN PCSTR pFileName,
  2315. IN USHORT LineNumber
  2316. )
  2317. {
  2318. //
  2319. // Allocate a chunk of memory & store the MDL in it. We'll use this
  2320. // memory to track MDL leaks.
  2321. //
  2322. PMDL mdl;
  2323. #if ENABLE_MDL_TRACKER
  2324. PUL_DEBUG_MDL_TRACKER pMdlTrack;
  2325. pMdlTrack = UL_ALLOCATE_POOL(
  2326. NonPagedPool,
  2327. sizeof(UL_DEBUG_MDL_TRACKER),
  2328. UL_DEBUG_MDL_POOL_TAG
  2329. );
  2330. if(!pMdlTrack)
  2331. {
  2332. return NULL;
  2333. }
  2334. #endif
  2335. mdl = IoAllocateMdl(
  2336. VirtualAddress,
  2337. Length,
  2338. SecondaryBuffer,
  2339. ChargeQuota,
  2340. Irp
  2341. );
  2342. if (mdl != NULL)
  2343. {
  2344. #if ENABLE_MDL_TRACKER
  2345. pMdlTrack->pMdl = mdl;
  2346. pMdlTrack->pFileName = pFileName;
  2347. pMdlTrack->LineNumber = LineNumber;
  2348. ExInterlockedInsertTailList(
  2349. &g_DbgMdlListHead,
  2350. &pMdlTrack->Linkage,
  2351. &g_DbgSpinLock);
  2352. #endif
  2353. WRITE_REF_TRACE_LOG(
  2354. g_pMdlTraceLog,
  2355. REF_ACTION_ALLOCATE_MDL,
  2356. PtrToLong(mdl->Next), // bugbug64
  2357. mdl,
  2358. pFileName,
  2359. LineNumber
  2360. );
  2361. #ifdef SPECIAL_MDL_FLAG
  2362. ASSERT( (mdl->MdlFlags & SPECIAL_MDL_FLAG) == 0 );
  2363. #endif
  2364. }
  2365. else
  2366. {
  2367. #if ENABLE_MDL_TRACKER
  2368. UL_FREE_POOL(pMdlTrack, UL_DEBUG_MDL_POOL_TAG);
  2369. #endif
  2370. }
  2371. return mdl;
  2372. } // UlDbgAllocateMdl
  2373. BOOLEAN g_ReallyFreeMdls = TRUE;
  2374. VOID
  2375. UlDbgFreeMdl(
  2376. IN PMDL Mdl,
  2377. IN PCSTR pFileName,
  2378. IN USHORT LineNumber
  2379. )
  2380. {
  2381. #if ENABLE_MDL_TRACKER
  2382. PUL_DEBUG_MDL_TRACKER pMdlTrack = NULL;
  2383. PLIST_ENTRY pEntry;
  2384. KIRQL oldIrql;
  2385. KeAcquireSpinLock( &g_DbgSpinLock, &oldIrql );
  2386. pEntry = g_DbgMdlListHead.Flink;
  2387. while(pEntry != &g_DbgMdlListHead)
  2388. {
  2389. pMdlTrack = CONTAINING_RECORD(
  2390. pEntry,
  2391. UL_DEBUG_MDL_TRACKER,
  2392. Linkage
  2393. );
  2394. if(pMdlTrack->pMdl == Mdl)
  2395. {
  2396. RemoveEntryList(&pMdlTrack->Linkage);
  2397. UL_FREE_POOL(pMdlTrack, UL_DEBUG_MDL_POOL_TAG);
  2398. break;
  2399. }
  2400. pEntry = pEntry->Flink;
  2401. }
  2402. ASSERT(pMdlTrack != NULL);
  2403. KeReleaseSpinLock(&g_DbgSpinLock, oldIrql);
  2404. #endif
  2405. WRITE_REF_TRACE_LOG(
  2406. g_pMdlTraceLog,
  2407. REF_ACTION_FREE_MDL,
  2408. PtrToLong(Mdl->Next), // bugbug64
  2409. Mdl,
  2410. pFileName,
  2411. LineNumber
  2412. );
  2413. #ifdef SPECIAL_MDL_FLAG
  2414. ASSERT( (Mdl->MdlFlags & SPECIAL_MDL_FLAG) == 0 );
  2415. #endif
  2416. if (g_ReallyFreeMdls)
  2417. {
  2418. IoFreeMdl( Mdl );
  2419. }
  2420. } // UlDbgFreeMdl
  2421. /***************************************************************************++
  2422. Routine Description:
  2423. Locates the file part of a fully qualified path.
  2424. Arguments:
  2425. pPath - Supplies the path to scan.
  2426. Return Value:
  2427. PCSTR - The file part.
  2428. --***************************************************************************/
  2429. PCSTR
  2430. UlDbgFindFilePart(
  2431. IN PCSTR pPath
  2432. )
  2433. {
  2434. PCSTR pFilePart;
  2435. //
  2436. // Strip off the path from the path.
  2437. //
  2438. pFilePart = strrchr( pPath, '\\' );
  2439. if (pFilePart == NULL)
  2440. {
  2441. pFilePart = pPath;
  2442. }
  2443. else
  2444. {
  2445. pFilePart++;
  2446. }
  2447. return pFilePart;
  2448. } // UlDbgFindFilePart
  2449. //
  2450. // Private functions.
  2451. //
  2452. /***************************************************************************++
  2453. Routine Description:
  2454. Updates a pool counter.
  2455. Arguments:
  2456. pAddend - Supplies the counter to update.
  2457. Increment - Supplies the value to add to the counter.
  2458. --***************************************************************************/
  2459. VOID
  2460. UlpDbgUpdatePoolCounter(
  2461. IN OUT PLARGE_INTEGER pAddend,
  2462. IN SIZE_T Increment
  2463. )
  2464. {
  2465. ULONG tmp;
  2466. tmp = (ULONG)Increment;
  2467. ASSERT( (SIZE_T)tmp == Increment );
  2468. ExInterlockedAddLargeStatistic(
  2469. pAddend,
  2470. tmp
  2471. );
  2472. } // UlpDbgUpdatePoolCounter
  2473. #if ENABLE_THREAD_DBEUG
  2474. /***************************************************************************++
  2475. Routine Description:
  2476. Locates and optionally creates per-thread data for the current thread.
  2477. Return Value:
  2478. PUL_DEBUG_THREAD_DATA - The thread data if successful, NULL otherwise.
  2479. --***************************************************************************/
  2480. PUL_DEBUG_THREAD_DATA
  2481. UlpDbgFindThread(
  2482. BOOLEAN OkToCreate,
  2483. PCSTR pFileName,
  2484. USHORT LineNumber
  2485. )
  2486. {
  2487. PUL_DEBUG_THREAD_DATA pData;
  2488. PUL_THREAD_HASH_BUCKET pBucket;
  2489. PETHREAD pThread;
  2490. KIRQL oldIrql;
  2491. PLIST_ENTRY pListEntry;
  2492. ULONG refCount;
  2493. //
  2494. // Get the current thread, find the correct bucket.
  2495. //
  2496. pThread = PsGetCurrentThread();
  2497. pBucket = &g_DbgThreadHashBuckets[HASH_FROM_THREAD(pThread)];
  2498. //
  2499. // Lock the bucket.
  2500. //
  2501. KeAcquireSpinLock( &pBucket->BucketSpinLock, &oldIrql );
  2502. //
  2503. // Try to find an existing entry for the current thread.
  2504. //
  2505. for (pListEntry = pBucket->BucketListHead.Flink ;
  2506. pListEntry != &pBucket->BucketListHead ;
  2507. pListEntry = pListEntry->Flink)
  2508. {
  2509. pData = CONTAINING_RECORD(
  2510. pListEntry,
  2511. UL_DEBUG_THREAD_DATA,
  2512. ThreadDataListEntry
  2513. );
  2514. if (pData->pThread == pThread)
  2515. {
  2516. //
  2517. // Found one. Update the reference count, then return the
  2518. // existing entry.
  2519. //
  2520. pData->ReferenceCount++;
  2521. refCount = pData->ReferenceCount;
  2522. KeReleaseSpinLock( &pBucket->BucketSpinLock, oldIrql );
  2523. //
  2524. // Trace it.
  2525. //
  2526. WRITE_REF_TRACE_LOG(
  2527. g_pThreadTraceLog,
  2528. REF_ACTION_REFERENCE_THREAD,
  2529. refCount,
  2530. pData,
  2531. pFileName,
  2532. LineNumber
  2533. );
  2534. return pData;
  2535. }
  2536. }
  2537. //
  2538. // If we made it this far, then data has not yet been created for
  2539. // the current thread. Create & initialize it now if we're allowed.
  2540. // Basically it's only ok if we're called from UlDbgEnterDriver.
  2541. //
  2542. if (OkToCreate)
  2543. {
  2544. pData = (PUL_DEBUG_THREAD_DATA) UL_ALLOCATE_POOL(
  2545. NonPagedPool,
  2546. sizeof(*pData),
  2547. UL_DEBUG_THREAD_POOL_TAG
  2548. );
  2549. if (pData != NULL)
  2550. {
  2551. RtlZeroMemory( pData, sizeof(*pData) );
  2552. pData->pThread = pThread;
  2553. pData->ReferenceCount = 1;
  2554. pData->ResourceCount = 0;
  2555. pData->PushLockCount = 0;
  2556. InsertHeadList(
  2557. &pBucket->BucketListHead,
  2558. &pData->ThreadDataListEntry
  2559. );
  2560. ++pBucket->Count;
  2561. pBucket->Max = MAX(pBucket->Max, pBucket->Count);
  2562. InterlockedIncrement( &g_DbgThreadCreated );
  2563. }
  2564. }
  2565. else
  2566. {
  2567. pData = NULL;
  2568. }
  2569. KeReleaseSpinLock( &pBucket->BucketSpinLock, oldIrql );
  2570. return pData;
  2571. } // UlpDbgFindThread
  2572. /***************************************************************************++
  2573. Routine Description:
  2574. Dereferences per-thread data.
  2575. Arguments:
  2576. pData - Supplies the thread data to dereference.
  2577. --***************************************************************************/
  2578. VOID
  2579. UlpDbgDereferenceThread(
  2580. IN PUL_DEBUG_THREAD_DATA pData
  2581. REFERENCE_DEBUG_FORMAL_PARAMS
  2582. )
  2583. {
  2584. PUL_THREAD_HASH_BUCKET pBucket;
  2585. KIRQL oldIrql;
  2586. ULONG refCount;
  2587. //
  2588. // Find the correct bucket.
  2589. //
  2590. pBucket = &g_DbgThreadHashBuckets[HASH_FROM_THREAD(pData->pThread)];
  2591. //
  2592. // Update the reference count.
  2593. //
  2594. KeAcquireSpinLock( &pBucket->BucketSpinLock, &oldIrql );
  2595. ASSERT( pData->ReferenceCount > 0 );
  2596. pData->ReferenceCount--;
  2597. refCount = pData->ReferenceCount;
  2598. if (pData->ReferenceCount == 0)
  2599. {
  2600. //
  2601. // It dropped to zero, so remove the thread from the bucket
  2602. // and free the resources.
  2603. //
  2604. RemoveEntryList( &pData->ThreadDataListEntry );
  2605. --pBucket->Count;
  2606. KeReleaseSpinLock( &pBucket->BucketSpinLock, oldIrql );
  2607. UL_FREE_POOL( pData, UL_DEBUG_THREAD_POOL_TAG );
  2608. InterlockedIncrement( &g_DbgThreadDestroyed );
  2609. }
  2610. else
  2611. {
  2612. KeReleaseSpinLock( &pBucket->BucketSpinLock, oldIrql );
  2613. }
  2614. //
  2615. // Trace it.
  2616. //
  2617. WRITE_REF_TRACE_LOG(
  2618. g_pThreadTraceLog,
  2619. REF_ACTION_DEREFERENCE_THREAD,
  2620. refCount,
  2621. pData,
  2622. pFileName,
  2623. LineNumber
  2624. );
  2625. } // UlpDbgDereferenceThread
  2626. #endif
  2627. /***************************************************************************++
  2628. Routine Description:
  2629. Allows us to do fancy things with IRP cancellation (e.g. force a cancel
  2630. while a cancel routine is being set or removed). For now, just default
  2631. to the regular IO manager routine.
  2632. Arguments:
  2633. pIrp - The IRP.
  2634. pCancelRoutine - The cancel routine.
  2635. --***************************************************************************/
  2636. PDRIVER_CANCEL
  2637. UlDbgIoSetCancelRoutine(
  2638. PIRP pIrp,
  2639. PDRIVER_CANCEL pCancelRoutine
  2640. )
  2641. {
  2642. return IoSetCancelRoutine(pIrp, pCancelRoutine);
  2643. }
  2644. #endif // DBG