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.

599 lines
13 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. ipinip\ppool.h
  5. Abstract:
  6. Code for managing NDIS_PACKET pools. This is merely a reformatted version
  7. of SteveC's l2tp\ppool.c
  8. Revision History:
  9. --*/
  10. #define __FILE_SIG__ PPOOL_SIG
  11. #include "inc.h"
  12. //-----------------------------------------------------------------------------
  13. // Local prototypes (alphabetically)
  14. //-----------------------------------------------------------------------------
  15. PPACKET_HEAD
  16. AddPacketBlockToPool(
  17. IN PPACKET_POOL pPool
  18. );
  19. VOID
  20. FreeUnusedPacketPoolBlocks(
  21. IN PPACKET_POOL pPool
  22. );
  23. //-----------------------------------------------------------------------------
  24. // Interface routines
  25. //-----------------------------------------------------------------------------
  26. VOID
  27. InitPacketPool(
  28. OUT PPACKET_POOL pPool,
  29. IN ULONG ulProtocolReservedLength,
  30. IN ULONG ulMaxPackets,
  31. IN ULONG ulPacketsPerBlock,
  32. IN ULONG ulFreesPerCollection,
  33. IN ULONG ulTag
  34. )
  35. /*++
  36. Routine Description
  37. Initialize caller's packet pool control block 'pPool'
  38. Locks
  39. Caller's 'pPool' packet must be protected from multiple access during
  40. this call.
  41. Arguments
  42. ulProtocolReservedLength size in bytes of the 'ProtocolReserved'
  43. array of each individual packet.
  44. ulMaxPackets maximum number of packets allowed in the
  45. entire pool, or 0 for unlimited.
  46. ulPacketsPerBlock number of packets to include in each block
  47. of packets.
  48. ulFreesPerCollection number of FreePacketToPool calls until the
  49. next garbage collect scan, or 0 for default.
  50. ulTag pool tag to use when allocating blocks
  51. Return Value
  52. None
  53. --*/
  54. {
  55. pPool->ulProtocolReservedLength = ulProtocolReservedLength;
  56. pPool->ulPacketsPerBlock = ulPacketsPerBlock;
  57. pPool->ulMaxPackets = ulMaxPackets;
  58. pPool->ulFreesSinceCollection = 0;
  59. pPool->ulTag = ulTag;
  60. if(ulFreesPerCollection)
  61. {
  62. pPool->ulFreesPerCollection = ulFreesPerCollection;
  63. }
  64. else
  65. {
  66. //
  67. // Calculate default garbage collection trigger. Don't want to be too
  68. // aggressive here.
  69. //
  70. pPool->ulFreesPerCollection = 50 * pPool->ulPacketsPerBlock;
  71. }
  72. InitializeListHead(&(pPool->leBlockHead));
  73. InitializeListHead(&(pPool->leFreePktHead));
  74. RtInitializeSpinLock(&(pPool->rlLock));
  75. }
  76. BOOLEAN
  77. FreePacketPool(
  78. IN PPACKET_POOL pPool
  79. )
  80. /*++
  81. Routine Description
  82. Free up all resources allocated in packet pool 'pPool'. This is the
  83. inverse of InitPacketPool.
  84. Locks
  85. Arguments
  86. Return Value
  87. TRUE if successful
  88. FALSE if any of the pool could not be freed due to outstanding packets
  89. --*/
  90. {
  91. BOOLEAN fSuccess;
  92. KIRQL irql;
  93. RtAcquireSpinLock(&(pPool->rlLock),
  94. &irql);
  95. FreeUnusedPacketPoolBlocks(pPool);
  96. fSuccess = (pPool->ulCurPackets is 0);
  97. RtReleaseSpinLock(&(pPool->rlLock),
  98. irql);
  99. return fSuccess;
  100. }
  101. PNDIS_PACKET
  102. GetPacketFromPool(
  103. IN PPACKET_POOL pPool,
  104. OUT PACKET_HEAD **ppHead
  105. )
  106. /*++
  107. Routine Description
  108. Returns the address of the NDIS_PACKET descriptor allocated from the
  109. pool. The pool is expanded, if necessary, but caller should
  110. still check for NULL return since the pool may have been at maximum
  111. size.
  112. Locks
  113. Arguments
  114. pPool Pool to get packet from
  115. ppHead Pointer the "cookie" that is used to return the packet to
  116. the pool (see FreePacketToPool). Caller would normally stash this
  117. value in the appropriate 'reserved' areas of the packet for
  118. retrieval later.
  119. Return Value
  120. Pointer to NDIS_PACKET or NULL
  121. --*/
  122. {
  123. PLIST_ENTRY pleNode;
  124. PPACKET_HEAD pHead;
  125. PNDIS_PACKET pPacket;
  126. KIRQL irql;
  127. RtAcquireSpinLock(&(pPool->rlLock),
  128. &irql);
  129. if(IsListEmpty(&pPool->leFreePktHead))
  130. {
  131. pleNode = NULL;
  132. }
  133. else
  134. {
  135. pleNode = RemoveHeadList(&(pPool->leFreePktHead));
  136. pHead = CONTAINING_RECORD(pleNode, PACKET_HEAD, leFreePktLink);
  137. pHead->pBlock->ulFreePackets--;
  138. }
  139. RtReleaseSpinLock(&(pPool->rlLock),
  140. irql);
  141. if(!pleNode)
  142. {
  143. //
  144. // The free list was empty. Try to expand the pool.
  145. //
  146. pHead = AddPacketBlockToPool(pPool);
  147. if(!pHead)
  148. {
  149. return NULL;
  150. }
  151. }
  152. *ppHead = pHead;
  153. return pHead->pNdisPacket;
  154. }
  155. VOID
  156. FreePacketToPool(
  157. IN PPACKET_POOL pPool,
  158. IN PPACKET_HEAD pHead,
  159. IN BOOLEAN fGarbageCollection
  160. )
  161. /*++
  162. Routine Description
  163. Returns a packet to the pool of unused packet. The packet must have
  164. been previously allocate with GetaPacketFromPool.
  165. Locks
  166. Arguments
  167. pPool Pool to which the packet is to be returned
  168. pHead The "cookie" that was given when the packet was allocated
  169. fGarbageCollection is set when the free should be considered for
  170. purposes of garbage collection. This is used by the AddPacketToPool
  171. routine to avoid counting the initial "add" frees. Normal callers
  172. should set this flag.
  173. Return Value
  174. NO_ERROR
  175. --*/
  176. {
  177. KIRQL irql;
  178. RtAcquireSpinLock(&(pPool->rlLock),
  179. &irql);
  180. InsertHeadList(&(pPool->leFreePktHead),
  181. &(pHead->leFreePktLink));
  182. pHead->pBlock->ulFreePackets++;
  183. if(fGarbageCollection)
  184. {
  185. pPool->ulFreesSinceCollection++;
  186. if(pPool->ulFreesSinceCollection >= pPool->ulFreesPerCollection)
  187. {
  188. //
  189. // Time to collect garbage, i.e. free any blocks in the pool
  190. // not in use.
  191. //
  192. FreeUnusedPacketPoolBlocks(pPool);
  193. pPool->ulFreesSinceCollection = 0;
  194. }
  195. }
  196. RtReleaseSpinLock(&(pPool->rlLock),
  197. irql);
  198. }
  199. //-----------------------------------------------------------------------------
  200. // Utility routines (alphabetically)
  201. //-----------------------------------------------------------------------------
  202. PPACKET_HEAD
  203. AddPacketBlockToPool(
  204. IN PPACKET_POOL pPool
  205. )
  206. /*++
  207. Routine Description
  208. Allocate a new packet block and add it to the packet pool
  209. Locks
  210. Arguments
  211. Return Value
  212. NO_ERROR
  213. --*/
  214. {
  215. NDIS_STATUS status;
  216. PPACKET_BLOCK pNew;
  217. ULONG ulSize;
  218. ULONG ulCount;
  219. BOOLEAN fOk;
  220. PPACKET_HEAD pReturn;
  221. KIRQL irql;
  222. fOk = FALSE;
  223. pNew = NULL;
  224. RtAcquireSpinLock(&(pPool->rlLock),
  225. &irql);
  226. do
  227. {
  228. if((pPool->ulMaxPackets) and
  229. (pPool->ulCurPackets >= pPool->ulMaxPackets))
  230. {
  231. //
  232. // No can do. The pool was initialized with a max size and that
  233. // has been reached.
  234. //
  235. break;
  236. }
  237. //
  238. // Calculate the contiguous block's size and the number of packets
  239. // it will hold.
  240. //
  241. ulCount = pPool->ulPacketsPerBlock;
  242. if(pPool->ulMaxPackets)
  243. {
  244. if(ulCount > (pPool->ulMaxPackets - pPool->ulCurPackets))
  245. {
  246. //
  247. // If a max was specified, respect that
  248. //
  249. ulCount = pPool->ulMaxPackets - pPool->ulCurPackets;
  250. }
  251. }
  252. //
  253. // We allocate a PACKET_BLOCK to account for this block of packets
  254. // and one PACKET_HEAD per packet
  255. //
  256. ulSize = sizeof(PACKET_BLOCK) + (ulCount * sizeof(PACKET_HEAD));
  257. //
  258. // Allocate the contiguous memory block for the PACKETBLOCK header
  259. // and the individual PACKET_HEADs.
  260. //
  261. pNew = RtAllocate(NonPagedPool,
  262. ulSize,
  263. pPool->ulTag);
  264. if(!pNew)
  265. {
  266. Trace(UTIL, ERROR,
  267. ("AddPacketBlockToPool: Unable to allocate %d bytes\n",
  268. ulSize));
  269. break;
  270. }
  271. //
  272. // Zero only the block header portion.
  273. //
  274. NdisZeroMemory(pNew, sizeof(PACKET_BLOCK));
  275. //
  276. // Allocate a pool of NDIS_PACKET descriptors.
  277. //
  278. NdisAllocatePacketPool(&status,
  279. &pNew->nhNdisPool,
  280. ulCount,
  281. pPool->ulProtocolReservedLength);
  282. if(status isnot NDIS_STATUS_SUCCESS)
  283. {
  284. Trace(UTIL, ERROR,
  285. ("AddPacketBlockToPool: Unable to allocate packet pool for %d packets\n",
  286. ulCount));
  287. break;
  288. }
  289. //
  290. // Fill in the back pointer to the pool.
  291. //
  292. pNew->pPool = pPool;
  293. //
  294. // Link the new block. At this point, all the packets are
  295. // effectively "in use". They are made available in the loop
  296. // below.
  297. //
  298. pNew->ulPackets = ulCount;
  299. pPool->ulCurPackets += ulCount;
  300. InsertHeadList(&(pPool->leBlockHead),
  301. &(pNew->leBlockLink));
  302. fOk = TRUE;
  303. }while(FALSE);
  304. RtReleaseSpinLock(&pPool->rlLock,
  305. irql);
  306. if(!fOk)
  307. {
  308. //
  309. // Bailing, undo whatever succeeded.
  310. //
  311. if(pNew)
  312. {
  313. RtFree(pNew);
  314. if(pNew->nhNdisPool)
  315. {
  316. NdisFreePacketPool(pNew->nhNdisPool);
  317. }
  318. }
  319. return NULL;
  320. }
  321. //
  322. // Initialize each individual packet header and add it to the list of free
  323. // packets.
  324. //
  325. {
  326. ULONG i;
  327. PPACKET_HEAD pHead;
  328. pReturn = NULL;
  329. //
  330. // For each PACKET_HEAD of the block...
  331. //
  332. for(i = 0, pHead = (PPACKET_HEAD)(pNew + 1);
  333. i < ulCount;
  334. i++, pHead++)
  335. {
  336. InitializeListHead(&pHead->leFreePktLink);
  337. pHead->pBlock = pNew;
  338. pHead->pNdisPacket = NULL;
  339. //
  340. // Associate an NDIS_PACKET descriptor from the pool we
  341. // allocated above.
  342. //
  343. NdisAllocatePacket(&status,
  344. &pHead->pNdisPacket,
  345. pNew->nhNdisPool);
  346. if(status isnot NDIS_STATUS_SUCCESS)
  347. {
  348. continue;
  349. }
  350. if(pReturn)
  351. {
  352. //
  353. // Add the constructed packet to the list of free packets.
  354. // The 'FALSE' tells the garbage collection algorithm the
  355. // operation is an "add" rather than a "release" and should be
  356. // ignored.
  357. //
  358. FreePacketToPool(pPool,
  359. pHead,
  360. FALSE);
  361. }
  362. else
  363. {
  364. //
  365. // The first successfully constructed packet is returned by
  366. // this routine.
  367. //
  368. pReturn = pHead;
  369. }
  370. }
  371. }
  372. return pReturn;
  373. }
  374. VOID
  375. FreeUnusedPacketPoolBlocks(
  376. IN PPACKET_POOL pPool
  377. )
  378. /*++
  379. Routine Description
  380. Check if any of the blocks in pool are not in use, and if so, free them.
  381. Locks
  382. Caller must hold the pool lock
  383. NOTE: The MSDN doc says that no locks may be held while calling
  384. NdisFreePacketXxx, but according to JameelH that is incorrect.
  385. Arguments
  386. pPool Pointer to pool
  387. Return Value
  388. None
  389. --*/
  390. {
  391. PLIST_ENTRY pleNode;
  392. //
  393. // For each block in the pool...
  394. //
  395. pleNode = pPool->leBlockHead.Flink;
  396. while(pleNode isnot &(pPool->leBlockHead))
  397. {
  398. PLIST_ENTRY pleNextNode;
  399. PPACKET_BLOCK pBlock;
  400. pleNextNode = pleNode->Flink;
  401. pBlock = CONTAINING_RECORD(pleNode, PACKET_BLOCK, leBlockLink);
  402. if(pBlock->ulFreePackets >= pBlock->ulPackets)
  403. {
  404. ULONG i;
  405. PPACKET_HEAD pHead;
  406. //
  407. // Found a block with no packets in use. Walk the packet block
  408. // removing each packet from the pool's free list and freeing any
  409. // associated NDIS_PACKET descriptor.
  410. //
  411. for(i = 0, pHead = (PPACKET_HEAD)(pBlock + 1);
  412. i < pBlock->ulPackets;
  413. i++, pHead++)
  414. {
  415. RemoveEntryList(&(pHead->leFreePktLink));
  416. if(pHead->pNdisPacket)
  417. {
  418. NdisFreePacket(pHead->pNdisPacket);
  419. }
  420. }
  421. //
  422. // Remove and release the unused block.
  423. //
  424. RemoveEntryList(pleNode);
  425. pPool->ulCurPackets -= pBlock->ulPackets;
  426. if(pBlock->nhNdisPool)
  427. {
  428. NdisFreePacketPool(pBlock->nhNdisPool);
  429. }
  430. RtFree(pBlock);
  431. }
  432. pleNode = pleNextNode;
  433. }
  434. }