Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1534 lines
33 KiB

  1. /*
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. atkmem.c
  5. Abstract:
  6. This module contains the routines which allocates and free memory. Only
  7. the non-paged pool is used.
  8. !!! For profiling, we use spinlock acquire/release for CurAllocCount/CurAllocSize
  9. Author:
  10. Nikhil Kamkolkar (NikhilK@microsoft.com)
  11. Jameel Hyder (JameelH@microsoft.com)
  12. Revision History:
  13. 25 Apr 1992 Initial Version (JameelH)
  14. --*/
  15. #include <atalk.h>
  16. #pragma hdrstop
  17. #define FILENUM ATKMEM
  18. #ifdef ALLOC_PRAGMA
  19. #pragma alloc_text(INIT, AtalkInitMemorySystem)
  20. #pragma alloc_text(PAGE, AtalkDeInitMemorySystem)
  21. #endif
  22. VOID
  23. AtalkInitMemorySystem(
  24. VOID
  25. )
  26. {
  27. LONG i;
  28. for (i = 0; i < NUM_BLKIDS; i++)
  29. INITIALIZE_SPIN_LOCK(&atalkBPLock[i]);
  30. AtalkTimerInitialize(&atalkBPTimer,
  31. atalkBPAgePool,
  32. BLOCK_POOL_TIMER);
  33. AtalkTimerScheduleEvent(&atalkBPTimer);
  34. }
  35. VOID
  36. AtalkDeInitMemorySystem(
  37. VOID
  38. )
  39. {
  40. LONG i, j, NumBlksPerChunk;
  41. PBLK_CHUNK pChunk, pFree;
  42. for (i = 0; i < NUM_BLKIDS; i++)
  43. {
  44. NumBlksPerChunk = atalkNumBlks[i];
  45. for (pChunk = atalkBPHead[i];
  46. pChunk != NULL;
  47. NOTHING)
  48. {
  49. DBGPRINT(DBG_COMP_RESOURCES, DBG_LEVEL_INFO,
  50. ("AtalkDeInitMemorySystem: Freeing %lx\n", pChunk));
  51. if ((pChunk->bc_NumFree != NumBlksPerChunk) ||
  52. (pChunk->bc_NumAlloc != 0))
  53. {
  54. DBGPRINT(DBG_COMP_RESOURCES, DBG_LEVEL_ERR,
  55. ("AtalkDeInitMemorySystem: Unfreed blocks from blockid %d, Chunk %lx\n",
  56. i, pChunk));
  57. ASSERT(0);
  58. }
  59. if (pChunk->bc_BlkId >= BLKID_NEED_NDIS_INT)
  60. {
  61. PBLK_HDR pBlkHdr;
  62. // We need to free the Ndis stuff for these guys
  63. for (j = 0, pBlkHdr = pChunk->bc_FreeHead;
  64. j < NumBlksPerChunk;
  65. j++, pBlkHdr = pBlkHdr->bh_Next)
  66. {
  67. PBUFFER_HDR pBufHdr;
  68. pBufHdr = (PBUFFER_HDR)((PBYTE)pBlkHdr + sizeof(BLK_HDR));
  69. ASSERT(pBufHdr->bh_NdisPkt == NULL);
  70. AtalkNdisFreeBuffer(pBufHdr->bh_NdisBuffer);
  71. }
  72. }
  73. pFree = pChunk;
  74. pChunk = pChunk->bc_Next;
  75. AtalkFreeMemory(pFree);
  76. }
  77. atalkBPHead[i] = NULL;
  78. }
  79. }
  80. PVOID FASTCALL
  81. AtalkAllocMem(
  82. #ifdef TRACK_MEMORY_USAGE
  83. IN ULONG Size,
  84. IN ULONG FileLine
  85. #else
  86. IN ULONG Size
  87. #endif // TRACK_MEMORY_USAGE
  88. )
  89. /*++
  90. Routine Description:
  91. Allocate a block of non-paged memory. This is just a wrapper over ExAllocPool.
  92. Allocation failures are error-logged. We always allocate a ULONG more than
  93. the specified size to accomodate the size. This is used by AtalkFreeMemory
  94. to update the statistics.
  95. Arguments:
  96. Return Value:
  97. --*/
  98. {
  99. PBYTE pBuf;
  100. BOOLEAN zeroed;
  101. #ifdef PROFILING
  102. TIME TimeS, TimeE, TimeD;
  103. #endif
  104. // round up the size so that we can put a signature at the end
  105. // that is on a ULONG boundary
  106. zeroed = ((Size & ZEROED_MEMORY_TAG) == ZEROED_MEMORY_TAG);
  107. Size = DWORDSIZEBLOCK(Size & ~ZEROED_MEMORY_TAG) +
  108. #if DBG
  109. sizeof(DWORD) + // For the signature
  110. #endif
  111. sizeof(ULONG_PTR);
  112. #ifdef PROFILING
  113. TimeS = KeQueryPerformanceCounter(NULL);
  114. #endif
  115. // Do the actual memory allocation. Allocate four extra bytes so
  116. // that we can store the size of the allocation for the free routine.
  117. if ((pBuf = ExAllocatePoolWithTag(NonPagedPool, Size, ATALK_TAG)) == NULL)
  118. {
  119. LOG_ERROR(EVENT_ATALK_MEMORYRESOURCES, STATUS_INSUFFICIENT_RESOURCES, NULL, 0);
  120. DBGPRINT(DBG_COMP_RESOURCES, DBG_LEVEL_FATAL,
  121. ("AtalkAllocMemory: failed - size %lx\n", Size));
  122. return NULL;
  123. }
  124. #ifdef PROFILING
  125. INTERLOCKED_INCREMENT_LONG(&AtalkStatistics.stat_CurAllocCount,
  126. &AtalkStatsLock.SpinLock);
  127. INTERLOCKED_INCREMENT_LONG(&AtalkStatistics.stat_ExAllocPoolCount,
  128. &AtalkStatsLock.SpinLock);
  129. TimeE = KeQueryPerformanceCounter(NULL);
  130. TimeD.QuadPart = TimeE.QuadPart - TimeS.QuadPart;
  131. INTERLOCKED_ADD_LARGE_INTGR(&AtalkStatistics.stat_ExAllocPoolTime,
  132. TimeD,
  133. &AtalkStatsLock.SpinLock);
  134. #endif
  135. INTERLOCKED_ADD_ULONG(&AtalkStatistics.stat_CurAllocSize,
  136. Size,
  137. &AtalkStatsLock.SpinLock);
  138. ASSERTMSG("AtalkAllocMemory: Allocation has exceeded Limit !!!\n",
  139. AtalkStatistics.stat_CurAllocSize < (ULONG)AtalkMemLimit);
  140. // Save the size of this block in the four extra bytes we allocated.
  141. *((PULONG)pBuf) = Size;
  142. #if DBG
  143. *((PULONG)(pBuf+Size-sizeof(ULONG))) = ATALK_MEMORY_SIGNATURE;
  144. DBGPRINT(DBG_COMP_RESOURCES, DBG_LEVEL_INFO,
  145. ("AtalkAllocMemory: Allocated %lx bytes @%lx\n", Size, pBuf));
  146. #endif
  147. AtalkTrackMemoryUsage((PVOID)pBuf, Size, TRUE, FileLine);
  148. #if DBG
  149. Size -= sizeof(ULONG);
  150. #endif
  151. pBuf += sizeof(ULONG_PTR);
  152. if (zeroed)
  153. {
  154. RtlZeroMemory(pBuf, Size - sizeof(ULONG_PTR));
  155. }
  156. // Return a pointer to the memory after the size longword.
  157. return (pBuf);
  158. }
  159. VOID FASTCALL
  160. AtalkFreeMemory(
  161. IN PVOID pBuf
  162. )
  163. /*++
  164. Routine Description:
  165. Free the block of memory allocated via AtalkAllocMemory. This is
  166. a wrapper around ExFreePool.
  167. Arguments:
  168. Return Value:
  169. --*/
  170. {
  171. PULONG pRealBuffer;
  172. ULONG Size;
  173. #ifdef PROFILING
  174. TIME TimeS, TimeE, TimeD;
  175. #endif
  176. // Get a pointer to the block allocated by ExAllocatePool.
  177. pRealBuffer = (PULONG)((PCHAR)pBuf - sizeof(ULONG_PTR));
  178. Size = *pRealBuffer;
  179. AtalkTrackMemoryUsage(pRealBuffer, Size, FALSE, 0);
  180. #if DBG
  181. *pRealBuffer = 0;
  182. // Check the signature at the end
  183. if (*(PULONG)((PCHAR)pRealBuffer + Size - sizeof(ULONG))
  184. != ATALK_MEMORY_SIGNATURE)
  185. {
  186. DBGPRINT(DBG_COMP_RESOURCES, DBG_LEVEL_FATAL,
  187. ("AtalkFreeMemory: Memory overrun on block %lx\n", pRealBuffer));
  188. ASSERT(0);
  189. }
  190. *(PULONG)((PCHAR)pRealBuffer + Size - sizeof(ULONG)) = 0;
  191. #endif
  192. INTERLOCKED_ADD_ULONG(&AtalkStatistics.stat_CurAllocSize,
  193. -(LONG)Size,
  194. &AtalkStatsLock.SpinLock);
  195. #ifdef PROFILING
  196. INTERLOCKED_DECREMENT_LONG(&AtalkStatistics.stat_CurAllocCount,
  197. &AtalkStatsLock);
  198. INTERLOCKED_INCREMENT_LONG(&AtalkStatistics.stat_ExFreePoolCount,
  199. &AtalkStatsLock);
  200. TimeS = KeQueryPerformanceCounter(NULL);
  201. #endif
  202. // Free the pool and return.
  203. ExFreePool(pRealBuffer);
  204. #ifdef PROFILING
  205. TimeE = KeQueryPerformanceCounter(NULL);
  206. TimeD.QuadPart = TimeE.QuadPart - TimeS.QuadPart;
  207. INTERLOCKED_ADD_LARGE_INTGR(&AtalkStatistics.stat_ExFreePoolTime,
  208. TimeD,
  209. &AtalkStatsLock.SpinLock);
  210. #endif
  211. }
  212. PBUFFER_DESC
  213. AtalkDescribeBufferDesc(
  214. IN PVOID DataPtr,
  215. IN PVOID FreePtr,
  216. IN USHORT Length,
  217. #ifdef TRACK_BUFFDESC_USAGE
  218. IN USHORT Flags,
  219. IN ULONG FileLine
  220. #else
  221. IN USHORT Flags
  222. #endif
  223. )
  224. /*++
  225. Routine Description:
  226. Arguments:
  227. Return Value:
  228. --*/
  229. {
  230. PBUFFER_DESC pBuffDesc;
  231. if ((pBuffDesc = AtalkAllocBufferDesc(DataPtr,
  232. Length,
  233. #ifdef TRACK_BUFFDESC_USAGE
  234. Flags,
  235. FileLine
  236. #else
  237. Flags
  238. #endif
  239. )) != NULL)
  240. {
  241. pBuffDesc->bd_FreeBuffer = FreePtr;
  242. }
  243. return pBuffDesc;
  244. }
  245. PBUFFER_DESC
  246. AtalkAllocBufferDesc(
  247. IN PVOID Ptr OPTIONAL,
  248. IN USHORT Length,
  249. #ifdef TRACK_BUFFDESC_USAGE
  250. IN USHORT Flags,
  251. IN ULONG FileLine
  252. #else
  253. IN USHORT Flags
  254. #endif
  255. )
  256. /*++
  257. Routine Description:
  258. Arguments:
  259. Return Value:
  260. --*/
  261. {
  262. PBUFFER_DESC pBuffDesc = NULL;
  263. DBGPRINT(DBG_COMP_RESOURCES, DBG_LEVEL_INFO,
  264. ("AtalkAllocBuffDesc: Ptr %lx, Length %x, Flags %x\n",
  265. Ptr, Length, Flags));
  266. pBuffDesc = AtalkBPAllocBlock(BLKID_BUFFDESC);
  267. if (pBuffDesc != NULL)
  268. {
  269. #if DBG
  270. pBuffDesc->bd_Signature = BD_SIGNATURE;
  271. #endif
  272. pBuffDesc->bd_Length = Length;
  273. pBuffDesc->bd_Flags = Flags;
  274. pBuffDesc->bd_Next = NULL;
  275. // Depending on whether a char buffer or a PAMDL is being
  276. // passed in...
  277. if (Flags & BD_CHAR_BUFFER)
  278. {
  279. if ((Ptr == NULL) &&
  280. ((Ptr = AtalkAllocMemory(Length)) == NULL))
  281. {
  282. pBuffDesc->bd_Flags = 0;
  283. pBuffDesc->bd_CharBuffer = NULL;
  284. AtalkFreeBuffDesc(pBuffDesc);
  285. pBuffDesc = NULL;
  286. }
  287. else
  288. {
  289. pBuffDesc->bd_CharBuffer = pBuffDesc->bd_FreeBuffer = Ptr;
  290. AtalkTrackBuffDescUsage(pBuffDesc, TRUE, FileLine);
  291. }
  292. }
  293. else
  294. {
  295. pBuffDesc->bd_OpaqueBuffer = (PAMDL)Ptr;
  296. }
  297. }
  298. return pBuffDesc;
  299. }
  300. VOID FASTCALL
  301. AtalkFreeBuffDesc(
  302. IN PBUFFER_DESC pBuffDesc
  303. )
  304. /*++
  305. Routine Description:
  306. Arguments:
  307. Return Value:
  308. --*/
  309. {
  310. ASSERT(VALID_BUFFDESC(pBuffDesc));
  311. if ((pBuffDesc->bd_Flags & (BD_FREE_BUFFER | BD_CHAR_BUFFER)) ==
  312. (BD_FREE_BUFFER | BD_CHAR_BUFFER))
  313. AtalkFreeMemory(pBuffDesc->bd_FreeBuffer);
  314. AtalkTrackBuffDescUsage(pBuffDesc, FALSE, 0);
  315. AtalkBPFreeBlock(pBuffDesc);
  316. }
  317. VOID
  318. AtalkCopyBuffDescToBuffer(
  319. IN PBUFFER_DESC pBuffDesc,
  320. IN LONG SrcOff,
  321. IN LONG BytesToCopy,
  322. IN PBYTE DstBuf
  323. )
  324. /*++
  325. Routine Description:
  326. Arguments:
  327. Return Value:
  328. --*/
  329. {
  330. NTSTATUS Status;
  331. ULONG BytesCopied;
  332. LONG Index = 0;
  333. ASSERT(VALID_BUFFDESC(pBuffDesc));
  334. while ((pBuffDesc != NULL) &&
  335. (SrcOff > (LONG)pBuffDesc->bd_Length))
  336. {
  337. SrcOff -= pBuffDesc->bd_Length;
  338. pBuffDesc = pBuffDesc->bd_Next;
  339. }
  340. do
  341. {
  342. LONG ThisCopy;
  343. if (pBuffDesc == NULL)
  344. break;
  345. ThisCopy = BytesToCopy;
  346. if (ThisCopy > ((LONG)pBuffDesc->bd_Length - SrcOff))
  347. ThisCopy = ((LONG)pBuffDesc->bd_Length - SrcOff);
  348. BytesToCopy -= ThisCopy;
  349. if (pBuffDesc->bd_Flags & BD_CHAR_BUFFER)
  350. {
  351. RtlCopyMemory(DstBuf + Index,
  352. pBuffDesc->bd_CharBuffer + SrcOff,
  353. ThisCopy);
  354. }
  355. else
  356. {
  357. Status = TdiCopyMdlToBuffer(pBuffDesc->bd_OpaqueBuffer,
  358. SrcOff,
  359. DstBuf + Index,
  360. 0,
  361. ThisCopy,
  362. &BytesCopied);
  363. ASSERT(NT_SUCCESS(Status) && (BytesCopied == (ULONG)ThisCopy));
  364. }
  365. Index += ThisCopy;
  366. SrcOff -= (pBuffDesc->bd_Length - ThisCopy);
  367. pBuffDesc = pBuffDesc->bd_Next;
  368. } while (BytesToCopy > 0);
  369. }
  370. VOID
  371. AtalkCopyBufferToBuffDesc(
  372. IN PBYTE SrcBuf,
  373. IN LONG BytesToCopy,
  374. IN PBUFFER_DESC pBuffDesc,
  375. IN LONG DstOff
  376. )
  377. /*++
  378. Routine Description:
  379. Arguments:
  380. Return Value:
  381. --*/
  382. {
  383. NTSTATUS Status;
  384. LONG Index = 0;
  385. ASSERT(VALID_BUFFDESC(pBuffDesc));
  386. while ((DstOff > (LONG)pBuffDesc->bd_Length) &&
  387. (pBuffDesc != NULL))
  388. {
  389. DstOff -= pBuffDesc->bd_Length;
  390. pBuffDesc = pBuffDesc->bd_Next;
  391. }
  392. do
  393. {
  394. LONG ThisCopy;
  395. if (pBuffDesc == NULL)
  396. break;
  397. ThisCopy = BytesToCopy;
  398. if (ThisCopy > ((LONG)pBuffDesc->bd_Length - DstOff))
  399. ThisCopy = ((LONG)pBuffDesc->bd_Length - DstOff);
  400. BytesToCopy -= ThisCopy;
  401. if (pBuffDesc->bd_Flags & BD_CHAR_BUFFER)
  402. {
  403. RtlCopyMemory(pBuffDesc->bd_CharBuffer + DstOff,
  404. SrcBuf + Index,
  405. ThisCopy);
  406. }
  407. else
  408. {
  409. Status = TdiCopyBufferToMdl(SrcBuf,
  410. Index,
  411. ThisCopy,
  412. pBuffDesc->bd_OpaqueBuffer,
  413. DstOff,
  414. (PULONG)&ThisCopy);
  415. ASSERT(NT_SUCCESS(Status) && (ThisCopy == BytesToCopy));
  416. }
  417. Index += ThisCopy;
  418. DstOff -= (pBuffDesc->bd_Length - ThisCopy);
  419. pBuffDesc = pBuffDesc->bd_Next;
  420. } while (BytesToCopy > 0);
  421. }
  422. LONG FASTCALL
  423. AtalkSizeBuffDesc(
  424. IN PBUFFER_DESC pBuffDesc
  425. )
  426. /*++
  427. Routine Description:
  428. Arguments:
  429. Return Value:
  430. --*/
  431. {
  432. LONG Size;
  433. ASSERT(VALID_BUFFDESC(pBuffDesc));
  434. for (Size = 0; pBuffDesc != NULL; pBuffDesc = pBuffDesc->bd_Next)
  435. Size += (LONG)pBuffDesc->bd_Length;
  436. return(Size);
  437. }
  438. PAMDL
  439. AtalkSubsetAmdl(
  440. IN PAMDL pStartingMdl,
  441. IN ULONG TotalOffset,
  442. IN ULONG DesiredLength
  443. )
  444. /*++
  445. Routine Description:
  446. This routine is called to build an Mdl chain from a source Mdl chain and
  447. offset into it. We assume we don't know the length of the source Mdl chain,
  448. and we must allocate and build the Mdls for the destination chain, which
  449. we do from non-paged pool. Note that this routine, unlike the IO subsystem
  450. routines, sets the SystemVaMapped bit in the generated Mdls to the same
  451. value as that in the source Mdls.
  452. IT WOULD BE BAD TO USE MmMapLockedPages OR MmProbeAndLockPages ON THE
  453. DESTINATION MDLS UNLESS YOU TAKE RESPONSIBILITY FOR UNMAPPING THEM!
  454. The MDLs that are returned are mapped and locked. (Actually, the pages in
  455. them are in the same state as those in the source MDLs.)
  456. If the system runs out of memory while we are building the destination
  457. MDL chain, we completely clean up the built chain and return with
  458. NewCurrentMdl and NewByteOffset set to the current values of CurrentMdl
  459. and TotalOffset. TRUELength is set to 0.
  460. Environment:
  461. Kernel Mode, Source Mdls locked. It is recommended, although not required,
  462. that the source Mdls be mapped and locked prior to calling this routine.
  463. Arguments:
  464. pStartingMdl - the source appletalk mdl ( == nt mdl)
  465. TotalOffset - Offset within this MDL to start the packet at.
  466. DesiredLength - The number of bytes to insert into the packet.
  467. Return Value:
  468. pointer to build mdl, NULL if out of resources, or lengths inconsistent.
  469. --*/
  470. {
  471. PMDL Destination=NULL;
  472. PBYTE BaseVa;
  473. ULONG NewMdlLength;
  474. PMDL NewMdl;
  475. PMDL pMdl;
  476. PMDL CurrentMdl = (PMDL)pStartingMdl;
  477. ULONG CurrentOffset = TotalOffset;
  478. ULONG BytesToDescribe = DesiredLength;
  479. //
  480. // first make sure that we have enough bytes!
  481. //
  482. if (DesiredLength > (ULONG)AtalkSizeMdlChain(pStartingMdl))
  483. {
  484. DBGPRINT(DBG_COMP_UTILS, DBG_LEVEL_ERR,
  485. ("AtalkSubsetMdl: req len (%ld) exceeds avl len (%ld) for mdl %lx\n",
  486. DesiredLength, AtalkSizeMdlChain(pStartingMdl),pStartingMdl));
  487. ASSERT(0);
  488. return(NULL);
  489. }
  490. //
  491. // first, get to the right Mdl (in most cases, the same as pStartingMdl)
  492. //
  493. while (CurrentMdl && (CurrentOffset >= MmGetMdlByteCount (CurrentMdl)))
  494. {
  495. CurrentOffset -= MmGetMdlByteCount (CurrentMdl);
  496. CurrentMdl = CurrentMdl->Next;
  497. ASSERT(CurrentMdl != NULL);
  498. }
  499. while (BytesToDescribe)
  500. {
  501. ASSERT(CurrentMdl != NULL);
  502. BaseVa = (PBYTE)MmGetMdlVirtualAddress(CurrentMdl) + CurrentOffset;
  503. NewMdlLength = MmGetMdlByteCount (CurrentMdl) - CurrentOffset;
  504. // if Mdl has more bytes than what's needed, set available to what's needed
  505. if (NewMdlLength > BytesToDescribe)
  506. {
  507. NewMdlLength = BytesToDescribe;
  508. }
  509. pMdl = IoAllocateMdl(BaseVa,
  510. NewMdlLength,
  511. FALSE,
  512. FALSE,
  513. NULL);
  514. // store the first mdl for return
  515. if (!Destination)
  516. {
  517. Destination = pMdl;
  518. // subsequent Mdl's must start with offset 0!!
  519. CurrentOffset = 0;
  520. }
  521. else
  522. {
  523. // link-in to the earlier mdl
  524. NewMdl->Next = pMdl;
  525. }
  526. NewMdl = pMdl;
  527. if (pMdl != NULL)
  528. {
  529. ATALK_DBG_INC_COUNT(AtalkDbgMdlsAlloced);
  530. #ifdef PROFILING
  531. INTERLOCKED_INCREMENT_LONG(
  532. &AtalkStatistics.stat_CurMdlCount,
  533. &AtalkStatsLock.SpinLock);
  534. #endif
  535. IoBuildPartialMdl(CurrentMdl,
  536. pMdl,
  537. BaseVa,
  538. NewMdlLength);
  539. }
  540. else
  541. {
  542. // free up whatever was allocated so far
  543. while (Destination)
  544. {
  545. pMdl = Destination->Next;
  546. IoFreeMdl(Destination);
  547. ATALK_DBG_DEC_COUNT(AtalkDbgMdlsAlloced);
  548. Destination = pMdl;
  549. }
  550. }
  551. BytesToDescribe -= NewMdlLength;
  552. CurrentMdl = CurrentMdl->Next;
  553. }
  554. return(Destination);
  555. }
  556. PAMDL
  557. AtalkAllocAMdl(
  558. IN PBYTE pBuffer OPTIONAL,
  559. IN LONG Size
  560. )
  561. /*++
  562. Routine Description:
  563. Arguments:
  564. Return Value:
  565. --*/
  566. {
  567. PMDL pMdl = NULL;
  568. if (pBuffer == NULL)
  569. {
  570. pBuffer = AtalkAllocMemory(Size);
  571. }
  572. if ((pBuffer == NULL) ||
  573. ((pMdl = IoAllocateMdl(pBuffer, Size, FALSE, FALSE, NULL)) == NULL))
  574. {
  575. LOG_ERROR(EVENT_ATALK_RESOURCES, STATUS_INSUFFICIENT_RESOURCES, NULL, 0);
  576. }
  577. #ifdef PROFILING
  578. else
  579. {
  580. INTERLOCKED_INCREMENT_LONG(
  581. &AtalkStatistics.stat_CurMdlCount,
  582. &AtalkStatsLock.SpinLock);
  583. }
  584. #endif
  585. if (pMdl != NULL)
  586. {
  587. ATALK_DBG_INC_COUNT(AtalkDbgMdlsAlloced);
  588. MmBuildMdlForNonPagedPool(pMdl);
  589. }
  590. return(pMdl);
  591. }
  592. LONG FASTCALL
  593. AtalkSizeMdlChain(
  594. IN PAMDL pAMdlChain
  595. )
  596. /*++
  597. Routine Description:
  598. Arguments:
  599. Return Value:
  600. --*/
  601. {
  602. LONG Size;
  603. for (Size = 0; pAMdlChain != NULL; pAMdlChain = pAMdlChain->Next)
  604. {
  605. Size += MmGetMdlByteCount(pAMdlChain);
  606. }
  607. return(Size);
  608. }
  609. /*** AtalkBPAllocBlock
  610. *
  611. * Alloc a block of memory from the block pool package. This is written to speed up
  612. * operations where a lot of small fixed size allocations/frees happen. Going to
  613. * ExAllocPool() in these cases is expensive.
  614. *
  615. * It is important to keep the list of blocks in such a way that all completely free
  616. * blocks are at the tail end of the list.
  617. */
  618. PVOID FASTCALL
  619. AtalkBPAllocBlock(
  620. IN BLKID BlockId
  621. )
  622. {
  623. PBLK_HDR pBlk = NULL;
  624. PBLK_CHUNK pChunk, *ppChunkHead;
  625. KIRQL OldIrql;
  626. USHORT BlkSize;
  627. ATALK_SPIN_LOCK * pLock;
  628. NDIS_STATUS ndisStatus;
  629. #ifdef PROFILING
  630. TIME TimeS, TimeE, TimeD;
  631. TimeS = KeQueryPerformanceCounter(NULL);
  632. #endif
  633. ASSERT (BlockId < NUM_BLKIDS);
  634. BlkSize = atalkBlkSize[BlockId];
  635. ppChunkHead = &atalkBPHead[BlockId];
  636. pLock = &atalkBPLock[BlockId];
  637. ACQUIRE_SPIN_LOCK(pLock, &OldIrql);
  638. if ((pChunk = *ppChunkHead) != NULL)
  639. {
  640. ASSERT(VALID_BC(pChunk));
  641. ASSERT(pChunk->bc_BlkId == BlockId);
  642. ASSERT((pChunk->bc_NumFree + pChunk->bc_NumAlloc) == atalkNumBlks[BlockId]);
  643. if (pChunk->bc_NumFree > 0)
  644. {
  645. // This is where we take it off from
  646. DBGPRINT(DBG_COMP_SYSTEM, DBG_LEVEL_INFO,
  647. ("AtalkBPAllocBlock: Found space in Chunk %lx\n", pChunk));
  648. #ifdef PROFILING
  649. INTERLOCKED_INCREMENT_LONG( &AtalkStatistics.stat_NumBPHits,
  650. &AtalkStatsLock.SpinLock);
  651. #endif
  652. }
  653. if (pChunk->bc_NumFree == 0)
  654. {
  655. // We do not have space on any of the chunks on this list
  656. ASSERT(pChunk->bc_NumAlloc == atalkNumBlks[BlockId]);
  657. pChunk = NULL;
  658. }
  659. }
  660. if (pChunk == NULL)
  661. {
  662. DBGPRINT(DBG_COMP_SYSTEM, DBG_LEVEL_INFO,
  663. ("AtalkBPAllocBlock: Allocating a new chunk for Id %d\n", BlockId));
  664. #ifdef PROFILING
  665. INTERLOCKED_INCREMENT_LONG( &AtalkStatistics.stat_NumBPMisses,
  666. &AtalkStatsLock.SpinLock);
  667. #endif
  668. pChunk = AtalkAllocMemory(atalkChunkSize[BlockId]);
  669. if (pChunk != NULL)
  670. {
  671. LONG i, j;
  672. PBLK_HDR pBlkHdr;
  673. PBUFFER_HDR pBufHdr;
  674. USHORT NumBlksPerChunk;
  675. #if DBG
  676. pChunk->bc_Signature = BC_SIGNATURE;
  677. pChunk->bc_NumAlloc = 0;
  678. #endif
  679. NumBlksPerChunk = atalkNumBlks[BlockId];
  680. ASSERT (NumBlksPerChunk <= 0xFF);
  681. pChunk->bc_NumFree = (BYTE)NumBlksPerChunk;
  682. pChunk->bc_BlkId = BlockId;
  683. pChunk->bc_FreeHead = (PBLK_HDR)((PBYTE)pChunk + sizeof(BLK_CHUNK));
  684. DBGPRINT(DBG_COMP_SYSTEM, DBG_LEVEL_INFO,
  685. ("AtalkBPAllocBlock: Initializing chunk %lx, BlkId=%d\n", pChunk,BlockId));
  686. // Initialize the blocks in the chunk
  687. for (i = 0, pBlkHdr = pChunk->bc_FreeHead;
  688. i < NumBlksPerChunk;
  689. i++, pBlkHdr = pBlkHdr->bh_Next)
  690. {
  691. LONG Size;
  692. #if DBG
  693. pBlkHdr->bh_Signature = BH_SIGNATURE;
  694. #endif
  695. pBlkHdr->bh_Next = (i == (NumBlksPerChunk-1)) ?
  696. NULL :
  697. (PBLK_HDR)((PBYTE)pBlkHdr + BlkSize);
  698. if (BlockId >= BLKID_NEED_NDIS_INT)
  699. {
  700. PCHAR pStartOfBuf;
  701. // We need to initialize the Ndis stuff for these guys
  702. pBufHdr = (PBUFFER_HDR)((PBYTE)pBlkHdr + sizeof(BLK_HDR));
  703. pBufHdr->bh_NdisPkt = NULL;
  704. if (BlockId == BLKID_SENDBUF)
  705. {
  706. Size = sizeof(BUFFER_HDR) + sizeof(BUFFER_DESC);
  707. pStartOfBuf = (PCHAR)pBufHdr + Size;
  708. }
  709. else if ((BlockId == BLKID_MNP_SMSENDBUF) ||
  710. (BlockId == BLKID_MNP_LGSENDBUF) )
  711. {
  712. // NOTE: the 1 byte of Buffer[1], combined with aligning
  713. // effect screws up Size (it's 3 more than what we think!)
  714. Size = sizeof(MNPSENDBUF);
  715. pStartOfBuf = &(((PMNPSENDBUF)pBufHdr)->Buffer[0]);
  716. }
  717. else
  718. {
  719. Size = sizeof(BUFFER_HDR);
  720. pStartOfBuf = (PCHAR)pBufHdr + Size;
  721. }
  722. // Make a NDIS buffer descriptor for this data
  723. NdisAllocateBuffer(&ndisStatus,
  724. &pBufHdr->bh_NdisBuffer,
  725. AtalkNdisBufferPoolHandle,
  726. pStartOfBuf,
  727. (UINT)(BlkSize - sizeof(BLK_HDR) - Size));
  728. if (ndisStatus != NDIS_STATUS_SUCCESS)
  729. {
  730. LOG_ERROR(EVENT_ATALK_NDISRESOURCES, ndisStatus, NULL, 0);
  731. DBGPRINT(DBG_COMP_SYSTEM, DBG_LEVEL_ERR,
  732. ("NdisAllocateBuffer: Ndis Out-of-Resource condition hit\n"));
  733. ASSERT(0);
  734. break;
  735. }
  736. ATALK_DBG_INC_COUNT(AtalkDbgMdlsAlloced);
  737. // More processing for send buffers
  738. if ((BlockId == BLKID_SENDBUF) ||
  739. (BlockId == BLKID_MNP_SMSENDBUF) ||
  740. (BlockId == BLKID_MNP_LGSENDBUF))
  741. {
  742. PSENDBUF pSendBuf;
  743. PBUFFER_DESC pBuffDesc;
  744. PMNPSENDBUF pMnpSendBuf;
  745. if (BlockId == BLKID_SENDBUF)
  746. {
  747. pSendBuf = (PSENDBUF)pBufHdr;
  748. pBuffDesc = &pSendBuf->sb_BuffDesc;
  749. pBuffDesc->bd_Length = MAX_SENDBUF_LEN;
  750. pBuffDesc->bd_CharBuffer= pSendBuf->sb_Space;
  751. }
  752. else if (BlockId == BLKID_MNP_SMSENDBUF)
  753. {
  754. pMnpSendBuf = (PMNPSENDBUF)pBufHdr;
  755. pMnpSendBuf->DataSize = 0;
  756. pMnpSendBuf->FreeBuffer = &pMnpSendBuf->Buffer[0];
  757. pBuffDesc = &pMnpSendBuf->sb_BuffDesc;
  758. pBuffDesc->bd_Length = MNP_MINSEND_LEN;
  759. pBuffDesc->bd_CharBuffer= &pMnpSendBuf->Buffer[0];
  760. }
  761. else // if (BlockId == BLKID_MNP_LGSENDBUF)
  762. {
  763. pMnpSendBuf = (PMNPSENDBUF)pBufHdr;
  764. pMnpSendBuf->DataSize = 0;
  765. pMnpSendBuf->FreeBuffer = &pMnpSendBuf->Buffer[0];
  766. pBuffDesc = &pMnpSendBuf->sb_BuffDesc;
  767. pBuffDesc->bd_Length = MNP_MAXSEND_LEN;
  768. pBuffDesc->bd_CharBuffer= &pMnpSendBuf->Buffer[0];
  769. }
  770. #if DBG
  771. pBuffDesc->bd_Signature = BD_SIGNATURE;
  772. #endif
  773. pBuffDesc->bd_Flags = BD_CHAR_BUFFER;
  774. pBuffDesc->bd_Next = NULL;
  775. pBuffDesc->bd_FreeBuffer= NULL;
  776. }
  777. }
  778. }
  779. if (i != NumBlksPerChunk)
  780. {
  781. // This has to be a failure from Ndis !!!
  782. // Undo a bunch of stuff
  783. ASSERT (BlockId >= BLKID_NEED_NDIS_INT);
  784. DBGPRINT(DBG_COMP_SYSTEM, DBG_LEVEL_ERR,
  785. ("AtalkBPAllocBlock: Freeing new chunk (Ndis failure) Id %d\n",
  786. BlockId));
  787. pBlkHdr = pChunk->bc_FreeHead;
  788. for (j = 0, pBlkHdr = pChunk->bc_FreeHead;
  789. j < i; j++, pBlkHdr = pBlkHdr->bh_Next)
  790. {
  791. PBUFFER_HDR pBufHdr;
  792. pBufHdr = (PBUFFER_HDR)((PBYTE)pBlkHdr + sizeof(BLK_HDR));
  793. AtalkNdisFreeBuffer(pBufHdr->bh_NdisBuffer);
  794. }
  795. AtalkFreeMemory(pChunk);
  796. pChunk = NULL;
  797. }
  798. else
  799. {
  800. // Successfully initialized the chunk, link it in
  801. AtalkLinkDoubleAtHead(*ppChunkHead, pChunk, bc_Next, bc_Prev);
  802. #if DBG
  803. atalkNumChunksForId[BlockId] ++;
  804. #endif
  805. }
  806. }
  807. }
  808. if (pChunk != NULL)
  809. {
  810. PBLK_CHUNK pTmp;
  811. ASSERT(VALID_BC(pChunk));
  812. ASSERT(pChunk->bc_BlkId == BlockId);
  813. DBGPRINT(DBG_COMP_RESOURCES, DBG_LEVEL_INFO,
  814. ("AtalkBPAllocBlock: Allocating a block out of chunk %lx(%d,%d) for Id %d\n",
  815. pChunk, pChunk->bc_NumFree, pChunk->bc_NumAlloc, BlockId));
  816. pBlk = pChunk->bc_FreeHead;
  817. ASSERT(VALID_BH(pBlk));
  818. pChunk->bc_FreeHead = pBlk->bh_Next;
  819. pBlk->bh_pChunk = pChunk;
  820. pChunk->bc_Age = 0; // Reset age
  821. pChunk->bc_NumFree --;
  822. #if DBG
  823. pChunk->bc_NumAlloc ++;
  824. #endif
  825. // If the block is now empty, unlink it from here and move it
  826. // to the first empty slot. We know that all blocks 'earlier' than
  827. // this are non-empty.
  828. if ((pChunk->bc_NumFree == 0) &&
  829. ((pTmp = pChunk->bc_Next) != NULL) &&
  830. (pTmp->bc_NumFree > 0))
  831. {
  832. ASSERT(pChunk->bc_NumAlloc == atalkNumBlks[BlockId]);
  833. AtalkUnlinkDouble(pChunk, bc_Next, bc_Prev);
  834. for (; pTmp != NULL; pTmp = pTmp->bc_Next)
  835. {
  836. ASSERT(VALID_BC(pTmp));
  837. if (pTmp->bc_NumFree == 0)
  838. {
  839. ASSERT(pTmp->bc_NumAlloc == atalkNumBlks[BlockId]);
  840. // Found a free one. Park it right here.
  841. AtalkInsertDoubleBefore(pChunk, pTmp, bc_Next, bc_Prev);
  842. break;
  843. }
  844. else if (pTmp->bc_Next == NULL) // We reached the end
  845. {
  846. AtalkLinkDoubleAtEnd(pChunk, pTmp, bc_Next, bc_Prev);
  847. break;
  848. }
  849. }
  850. }
  851. }
  852. if (pBlk != NULL)
  853. {
  854. //
  855. // we allocate Ndis Packets for ARAP guys later, when we really need
  856. //
  857. if ((BlockId >= BLKID_NEED_NDIS_INT) &&
  858. (BlockId != BLKID_MNP_SMSENDBUF) &&
  859. (BlockId != BLKID_MNP_LGSENDBUF))
  860. {
  861. PBUFFER_HDR pBufHdr;
  862. // We need to initialize the Ndis stuff for these guys
  863. pBufHdr = (PBUFFER_HDR)((PBYTE)pBlk + sizeof(BLK_HDR));
  864. pBufHdr->bh_NdisPkt = NULL;
  865. // Allocate an NDIS packet descriptor from the global packet pool
  866. NdisDprAllocatePacket(&ndisStatus,
  867. &pBufHdr->bh_NdisPkt,
  868. AtalkNdisPacketPoolHandle);
  869. if (ndisStatus != NDIS_STATUS_SUCCESS)
  870. {
  871. LOG_ERROR(EVENT_ATALK_NDISRESOURCES, ndisStatus, NULL, 0);
  872. DBGPRINT(DBG_COMP_SYSTEM, DBG_LEVEL_ERR,
  873. ("NdisDprAllocatePacket: Ndis Out-of-Resource condition hit\n"));
  874. ASSERT(0);
  875. RELEASE_SPIN_LOCK(pLock, OldIrql);
  876. AtalkBPFreeBlock(pBufHdr);
  877. return(NULL);
  878. }
  879. // Link the buffer descriptor into the packet descriptor
  880. RtlZeroMemory(pBufHdr->bh_NdisPkt->ProtocolReserved, sizeof(PROTOCOL_RESD));
  881. NdisChainBufferAtBack(pBufHdr->bh_NdisPkt,
  882. pBufHdr->bh_NdisBuffer);
  883. ((PPROTOCOL_RESD)(pBufHdr->bh_NdisPkt->ProtocolReserved))->Receive.pr_BufHdr = pBufHdr;
  884. }
  885. ++pBlk;
  886. #if DBG
  887. atalkBlksForId[BlockId] ++;
  888. #endif
  889. }
  890. RELEASE_SPIN_LOCK(pLock, OldIrql);
  891. #ifdef PROFILING
  892. INTERLOCKED_INCREMENT_LONG(&AtalkStatistics.stat_BPAllocCount,
  893. &AtalkStatsLock.SpinLock);
  894. TimeE = KeQueryPerformanceCounter(NULL);
  895. TimeD.QuadPart = TimeE.QuadPart - TimeS.QuadPart;
  896. INTERLOCKED_ADD_LARGE_INTGR(&AtalkStatistics.stat_BPAllocTime,
  897. TimeD,
  898. &AtalkStatsLock.SpinLock);
  899. #endif
  900. return pBlk;
  901. }
  902. /*** atalkBPFreeBlock
  903. *
  904. * Return a block to its owning chunk.
  905. */
  906. VOID FASTCALL
  907. AtalkBPFreeBlock(
  908. IN PVOID pBlock
  909. )
  910. {
  911. PBLK_CHUNK pChunk;
  912. PBLK_HDR pBlkHdr;
  913. BLKID BlockId;
  914. KIRQL OldIrql;
  915. ATALK_SPIN_LOCK * pLock;
  916. #ifdef PROFILING
  917. TIME TimeS, TimeE, TimeD;
  918. TimeS = KeQueryPerformanceCounter(NULL);
  919. #endif
  920. pBlkHdr = (PBLK_HDR)((PCHAR)pBlock - sizeof(BLK_HDR));
  921. ASSERT(VALID_BH(pBlkHdr));
  922. pChunk = pBlkHdr->bh_pChunk;
  923. ASSERT(VALID_BC(pChunk));
  924. BlockId = pChunk->bc_BlkId;
  925. pLock = &atalkBPLock[BlockId];
  926. ACQUIRE_SPIN_LOCK(pLock, &OldIrql);
  927. if (BlockId >= BLKID_NEED_NDIS_INT)
  928. {
  929. PBUFFER_HDR pBufHdr;
  930. // We need to free the ndis packet here - if present
  931. pBufHdr = (PBUFFER_HDR)pBlock;
  932. if (pBufHdr->bh_NdisPkt != NULL)
  933. {
  934. NdisDprFreePacket(pBufHdr->bh_NdisPkt);
  935. pBufHdr->bh_NdisPkt = NULL;
  936. }
  937. }
  938. DBGPRINT(DBG_COMP_SYSTEM, DBG_LEVEL_INFO,
  939. ("AtalkBPFreeBlock: Returning Block %lx to chunk %lx for Id %d\n",
  940. pBlkHdr, pChunk, BlockId));
  941. ASSERT (pChunk->bc_NumFree < atalkNumBlks[BlockId]);
  942. #if DBG
  943. atalkBlksForId[BlockId] --;
  944. pChunk->bc_NumAlloc --;
  945. #endif
  946. pChunk->bc_NumFree ++;
  947. ASSERT((pChunk->bc_NumFree + pChunk->bc_NumAlloc) == atalkNumBlks[BlockId]);
  948. pBlkHdr->bh_Next = pChunk->bc_FreeHead;
  949. pChunk->bc_FreeHead = pBlkHdr;
  950. // If this block's status is changing from a 'none available' to 'available'
  951. // move him to the head of the list
  952. if (pChunk->bc_NumFree == 1)
  953. {
  954. AtalkUnlinkDouble(pChunk, bc_Next, bc_Prev);
  955. AtalkLinkDoubleAtHead(atalkBPHead[BlockId],
  956. pChunk,
  957. bc_Next,
  958. bc_Prev);
  959. }
  960. #ifdef PROFILING
  961. INTERLOCKED_INCREMENT_LONG(&AtalkStatistics.stat_BPFreeCount,
  962. &AtalkStatsLock.SpinLock);
  963. TimeE = KeQueryPerformanceCounter(NULL);
  964. TimeD.QuadPart = TimeE.QuadPart - TimeS.QuadPart;
  965. INTERLOCKED_ADD_LARGE_INTGR_DPC(&AtalkStatistics.stat_BPFreeTime,
  966. TimeD,
  967. &AtalkStatsLock.SpinLock);
  968. #endif
  969. RELEASE_SPIN_LOCK(pLock, OldIrql);
  970. }
  971. /*** atalkBPAgePool
  972. *
  973. * Age out the block pool of unused blocks
  974. */
  975. LOCAL LONG FASTCALL
  976. atalkBPAgePool(
  977. IN PTIMERLIST Context,
  978. IN BOOLEAN TimerShuttingDown
  979. )
  980. {
  981. PBLK_CHUNK pChunk;
  982. LONG i, j, NumBlksPerChunk;
  983. if (TimerShuttingDown)
  984. {
  985. return ATALK_TIMER_NO_REQUEUE;
  986. }
  987. for (i = 0; i < NUM_BLKIDS; i++)
  988. {
  989. NumBlksPerChunk = atalkNumBlks[i];
  990. ACQUIRE_SPIN_LOCK_DPC(&atalkBPLock[i]);
  991. for (pChunk = atalkBPHead[i];
  992. pChunk != NULL; )
  993. {
  994. PBLK_CHUNK pFree;
  995. ASSERT(VALID_BC(pChunk));
  996. pFree = pChunk;
  997. pChunk = pChunk->bc_Next;
  998. // Since all blocks which are completely used up are at the tail end of
  999. // the list, if we encounter one, we are done.
  1000. if (pFree->bc_NumFree == 0)
  1001. break;
  1002. if (pFree->bc_NumFree == NumBlksPerChunk)
  1003. {
  1004. DBGPRINT(DBG_COMP_SYSTEM, DBG_LEVEL_WARN,
  1005. ("atalkBPAgePool: Aging Chunk %lx, Id %d NumFree %d\n",
  1006. pFree, pFree->bc_BlkId,pFree->bc_NumFree));
  1007. if (++(pFree->bc_Age) >= MAX_BLOCK_POOL_AGE)
  1008. {
  1009. DBGPRINT(DBG_COMP_SYSTEM, DBG_LEVEL_WARN,
  1010. ("atalkBPAgePool: freeing Chunk %lx, Id %d\n",
  1011. pFree, pFree->bc_BlkId));
  1012. AtalkUnlinkDouble(pFree, bc_Next, bc_Prev);
  1013. #ifdef PROFILING
  1014. INTERLOCKED_INCREMENT_LONG( &AtalkStatistics.stat_NumBPAge,
  1015. &AtalkStatsLock.SpinLock);
  1016. #endif
  1017. if (pFree->bc_BlkId >= BLKID_NEED_NDIS_INT)
  1018. {
  1019. PBLK_HDR pBlkHdr;
  1020. // We need to free Ndis stuff for these guys
  1021. pBlkHdr = pFree->bc_FreeHead;
  1022. for (j = 0, pBlkHdr = pFree->bc_FreeHead;
  1023. j < NumBlksPerChunk;
  1024. j++, pBlkHdr = pBlkHdr->bh_Next)
  1025. {
  1026. PBUFFER_HDR pBufHdr;
  1027. pBufHdr = (PBUFFER_HDR)((PBYTE)pBlkHdr + sizeof(BLK_HDR));
  1028. ASSERT(pBufHdr->bh_NdisPkt == NULL);
  1029. AtalkNdisFreeBuffer(pBufHdr->bh_NdisBuffer);
  1030. }
  1031. }
  1032. AtalkFreeMemory(pFree);
  1033. #if DBG
  1034. atalkNumChunksForId[i] --;
  1035. #endif
  1036. }
  1037. }
  1038. }
  1039. RELEASE_SPIN_LOCK_DPC(&atalkBPLock[i]);
  1040. }
  1041. return ATALK_TIMER_REQUEUE;
  1042. }
  1043. #ifdef TRACK_MEMORY_USAGE
  1044. #define MAX_PTR_COUNT 4*1024
  1045. #define MAX_MEM_USERS 512
  1046. LOCAL ATALK_SPIN_LOCK atalkMemTrackLock = {0};
  1047. LOCAL struct
  1048. {
  1049. PVOID mem_Ptr;
  1050. ULONG mem_FileLine;
  1051. } atalkMemPtrs[MAX_PTR_COUNT] = {0};
  1052. LOCAL struct
  1053. {
  1054. ULONG mem_FL;
  1055. ULONG mem_Count;
  1056. } atalkMemUsage[MAX_MEM_USERS] = {0};
  1057. BOOLEAN NeverBeenFull=TRUE;
  1058. VOID
  1059. AtalkTrackMemoryUsage(
  1060. IN PVOID pMem,
  1061. IN ULONG Size,
  1062. IN BOOLEAN Alloc,
  1063. IN ULONG FileLine
  1064. )
  1065. /*++
  1066. Routine Description:
  1067. Keep track of memory usage by storing and clearing away pointers as and
  1068. when they are allocated or freed. This helps in keeping track of memory
  1069. leaks.
  1070. Arguments:
  1071. Return Value:
  1072. --*/
  1073. {
  1074. static int i = 0;
  1075. int j, k;
  1076. KIRQL OldIrql;
  1077. ACQUIRE_SPIN_LOCK(&atalkMemTrackLock, &OldIrql);
  1078. if (Alloc)
  1079. {
  1080. for (j = 0; j < MAX_PTR_COUNT; i++, j++)
  1081. {
  1082. i = i & (MAX_PTR_COUNT-1);
  1083. if (atalkMemPtrs[i].mem_Ptr == NULL)
  1084. {
  1085. atalkMemPtrs[i].mem_Ptr = pMem;
  1086. atalkMemPtrs[i++].mem_FileLine = FileLine;
  1087. break;
  1088. }
  1089. }
  1090. for (k = 0; k < MAX_MEM_USERS; k++)
  1091. {
  1092. if (atalkMemUsage[k].mem_FL == FileLine)
  1093. {
  1094. atalkMemUsage[k].mem_Count += Size;
  1095. break;
  1096. }
  1097. }
  1098. if (k == MAX_MEM_USERS)
  1099. {
  1100. for (k = 0; k < MAX_MEM_USERS; k++)
  1101. {
  1102. if (atalkMemUsage[k].mem_FL == 0)
  1103. {
  1104. atalkMemUsage[k].mem_FL = FileLine;
  1105. atalkMemUsage[k].mem_Count = Size;
  1106. break;
  1107. }
  1108. }
  1109. if (k == MAX_MEM_USERS)
  1110. {
  1111. DBGPRINT(DBG_COMP_RESOURCES, DBG_LEVEL_ERR,
  1112. ("AtalkTrackMemoryUsage: Out of space on atalkMemUsage !!!\n"));
  1113. }
  1114. }
  1115. }
  1116. else
  1117. {
  1118. for (j = 0, k = i; j < MAX_PTR_COUNT; j++, k--)
  1119. {
  1120. k = k & (MAX_PTR_COUNT-1);
  1121. if (atalkMemPtrs[k].mem_Ptr == pMem)
  1122. {
  1123. atalkMemPtrs[k].mem_Ptr = 0;
  1124. atalkMemPtrs[k].mem_FileLine = 0;
  1125. break;
  1126. }
  1127. }
  1128. for (k = 0; k < MAX_MEM_USERS; k++)
  1129. {
  1130. if (atalkMemUsage[k].mem_FL == FileLine)
  1131. {
  1132. if (atalkMemUsage[k].mem_Count >= Size)
  1133. {
  1134. atalkMemUsage[k].mem_Count -= Size;
  1135. }
  1136. break;
  1137. }
  1138. }
  1139. }
  1140. RELEASE_SPIN_LOCK(&atalkMemTrackLock, OldIrql);
  1141. if (j == MAX_PTR_COUNT)
  1142. {
  1143. if (NeverBeenFull)
  1144. {
  1145. NeverBeenFull = FALSE;
  1146. DBGPRINT(DBG_COMP_RESOURCES, DBG_LEVEL_ERR,
  1147. ("AtalkTrackMemoryUsage: %s\n", Alloc ? "Table Full" : "Can't find"));
  1148. }
  1149. }
  1150. }
  1151. #endif // TRACK_MEMORY_USAGE
  1152. #ifdef TRACK_BUFFDESC_USAGE
  1153. #define MAX_BD_COUNT 1024*2
  1154. LOCAL ATALK_SPIN_LOCK atalkBdTrackLock = {0};
  1155. LOCAL struct
  1156. {
  1157. PVOID bdesc_Ptr;
  1158. ULONG bdesc_FileLine;
  1159. } atalkBuffDescPtrs[MAX_BD_COUNT] = {0};
  1160. VOID
  1161. AtalkTrackBuffDescUsage(
  1162. IN PVOID pBuffDesc,
  1163. IN BOOLEAN Alloc,
  1164. IN ULONG FileLine
  1165. )
  1166. /*++
  1167. Routine Description:
  1168. Keep track of buffer-desc usage by storing and clearing away pointers as and
  1169. when they are allocated or freed. This helps in keeping track of memory
  1170. leaks.
  1171. Arguments:
  1172. Return Value:
  1173. --*/
  1174. {
  1175. static int i = 0;
  1176. int j, k;
  1177. KIRQL OldIrql;
  1178. ACQUIRE_SPIN_LOCK(&atalkBdTrackLock, &OldIrql);
  1179. if (Alloc)
  1180. {
  1181. for (j = 0; j < MAX_BD_COUNT; i++, j++)
  1182. {
  1183. i = i & (MAX_BD_COUNT-1);
  1184. if (atalkBuffDescPtrs[i].bdesc_Ptr == NULL)
  1185. {
  1186. atalkBuffDescPtrs[i].bdesc_Ptr = pBuffDesc;
  1187. atalkBuffDescPtrs[i++].bdesc_FileLine = FileLine;
  1188. break;
  1189. }
  1190. }
  1191. }
  1192. else
  1193. {
  1194. for (j = 0, k = i; j < MAX_BD_COUNT; j++, k--)
  1195. {
  1196. k = k & (MAX_BD_COUNT-1);
  1197. if (atalkBuffDescPtrs[k].bdesc_Ptr == pBuffDesc)
  1198. {
  1199. atalkBuffDescPtrs[k].bdesc_Ptr = 0;
  1200. atalkBuffDescPtrs[k].bdesc_FileLine = 0;
  1201. break;
  1202. }
  1203. }
  1204. }
  1205. RELEASE_SPIN_LOCK(&atalkBdTrackLock, OldIrql);
  1206. if (j == MAX_BD_COUNT)
  1207. {
  1208. DBGPRINT(DBG_COMP_RESOURCES, DBG_LEVEL_INFO,
  1209. ("AtalkTrackBuffDescUsage: %s\n", Alloc ? "Table Full" : "Can't find"));
  1210. ASSERT(0);
  1211. }
  1212. }
  1213. #endif // TRACK_BUFFDESC_USAGE