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.

539 lines
10 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. lookasid.c
  5. Abstract:
  6. This module implements heap lookaside list function.
  7. Author:
  8. David N. Cutler (davec) 19-Feb-1995
  9. Revision History:
  10. --*/
  11. #include "ntrtlp.h"
  12. #include "heap.h"
  13. #include "heappriv.h"
  14. // begin_ntslist
  15. #if !defined(NTSLIST_ASSERT)
  16. #define NTSLIST_ASSERT(x) ASSERT(x)
  17. #endif // !defined(NTSLIST_ASSERT)
  18. #ifdef _NTSLIST_DIRECT_
  19. #define INLINE_SLIST __inline
  20. #define RtlInitializeSListHead _RtlInitializeSListHead
  21. #define _RtlFirstEntrySList FirstEntrySList
  22. PSINGLE_LIST_ENTRY
  23. FirstEntrySList (
  24. const SLIST_HEADER *ListHead
  25. );
  26. #define RtlInterlockedPopEntrySList _RtlInterlockedPopEntrySList
  27. #define RtlInterlockedPushEntrySList _RtlInterlockedPushEntrySList
  28. #define RtlInterlockedFlushSList _RtlInterlockedFlushSList
  29. #define _RtlQueryDepthSList RtlpQueryDepthSList
  30. #else
  31. #define INLINE_SLIST
  32. #endif // _NTSLIST_DIRECT_
  33. // end_ntslist
  34. //
  35. // Define minimum allocation threshold.
  36. //
  37. #define MINIMUM_ALLOCATION_THRESHOLD 25
  38. // begin_ntslist
  39. //
  40. // Define forward referenced function prototypes.
  41. //
  42. VOID
  43. RtlpInitializeSListHead (
  44. IN PSLIST_HEADER ListHead
  45. );
  46. PSINGLE_LIST_ENTRY
  47. FASTCALL
  48. RtlpInterlockedPopEntrySList (
  49. IN PSLIST_HEADER ListHead
  50. );
  51. PSINGLE_LIST_ENTRY
  52. FASTCALL
  53. RtlpInterlockedPushEntrySList (
  54. IN PSLIST_HEADER ListHead,
  55. IN PSINGLE_LIST_ENTRY ListEntry
  56. );
  57. PSINGLE_LIST_ENTRY
  58. FASTCALL
  59. RtlpInterlockedFlushSList (
  60. IN PSLIST_HEADER ListHead
  61. );
  62. USHORT
  63. RtlpQueryDepthSList (
  64. IN PSLIST_HEADER SListHead
  65. );
  66. // end_ntslist
  67. VOID
  68. RtlpInitializeHeapLookaside (
  69. IN PHEAP_LOOKASIDE Lookaside,
  70. IN USHORT Depth
  71. )
  72. /*++
  73. Routine Description:
  74. This function initializes a heap lookaside list structure
  75. Arguments:
  76. Lookaside - Supplies a pointer to a heap lookaside list structure.
  77. Allocate - Supplies a pointer to an allocate function.
  78. Free - Supplies a pointer to a free function.
  79. HeapHandle - Supplies a pointer to the heap that backs this lookaside list
  80. Flags - Supplies a set of heap flags.
  81. Size - Supplies the size for the lookaside list entries.
  82. Depth - Supplies the maximum depth of the lookaside list.
  83. Return Value:
  84. None.
  85. --*/
  86. {
  87. //
  88. // Initialize the lookaside list structure.
  89. //
  90. RtlInitializeSListHead(&Lookaside->ListHead);
  91. Lookaside->Depth = MINIMUM_LOOKASIDE_DEPTH;
  92. Lookaside->MaximumDepth = 256; //Depth;
  93. Lookaside->TotalAllocates = 0;
  94. Lookaside->AllocateMisses = 0;
  95. Lookaside->TotalFrees = 0;
  96. Lookaside->FreeMisses = 0;
  97. Lookaside->LastTotalAllocates = 0;
  98. Lookaside->LastAllocateMisses = 0;
  99. return;
  100. }
  101. VOID
  102. RtlpDeleteHeapLookaside (
  103. IN PHEAP_LOOKASIDE Lookaside
  104. )
  105. /*++
  106. Routine Description:
  107. This function frees any entries specified by the lookaside structure.
  108. Arguments:
  109. Lookaside - Supplies a pointer to a heap lookaside list structure.
  110. Return Value:
  111. None.
  112. --*/
  113. {
  114. PVOID Entry;
  115. return;
  116. }
  117. VOID
  118. RtlpAdjustHeapLookasideDepth (
  119. IN PHEAP_LOOKASIDE Lookaside
  120. )
  121. /*++
  122. Routine Description:
  123. This function is called periodically to adjust the maximum depth of
  124. a single heap lookaside list.
  125. Arguments:
  126. Lookaside - Supplies a pointer to a heap lookaside list structure.
  127. Return Value:
  128. None.
  129. --*/
  130. {
  131. ULONG Allocates;
  132. ULONG Misses;
  133. //
  134. // Compute the total number of allocations and misses for this scan
  135. // period.
  136. //
  137. Allocates = Lookaside->TotalAllocates - Lookaside->LastTotalAllocates;
  138. Lookaside->LastTotalAllocates = Lookaside->TotalAllocates;
  139. Misses = Lookaside->AllocateMisses - Lookaside->LastAllocateMisses;
  140. Lookaside->LastAllocateMisses = Lookaside->AllocateMisses;
  141. //
  142. // Compute target depth of lookaside list.
  143. //
  144. {
  145. ULONG Ratio;
  146. ULONG Target;
  147. //
  148. // If the allocate rate is less than the mimimum threshold, then lower
  149. // the maximum depth of the lookaside list. Otherwise, if the miss rate
  150. // is less than .5%, then lower the maximum depth. Otherwise, raise the
  151. // maximum depth based on the miss rate.
  152. //
  153. if (Misses >= Allocates) {
  154. Misses = Allocates;
  155. }
  156. if (Allocates == 0) {
  157. Allocates = 1;
  158. }
  159. Ratio = (Misses * 1000) / Allocates;
  160. Target = Lookaside->Depth;
  161. if (Allocates < MINIMUM_ALLOCATION_THRESHOLD) {
  162. if (Target > (MINIMUM_LOOKASIDE_DEPTH + 10)) {
  163. Target -= 10;
  164. } else {
  165. Target = MINIMUM_LOOKASIDE_DEPTH;
  166. }
  167. } else if (Ratio < 5) {
  168. if (Target > (MINIMUM_LOOKASIDE_DEPTH + 1)) {
  169. Target -= 1;
  170. } else {
  171. Target = MINIMUM_LOOKASIDE_DEPTH;
  172. }
  173. } else {
  174. Target += ((Ratio * Lookaside->MaximumDepth) / (1000 * 2)) + 5;
  175. if (Target > Lookaside->MaximumDepth) {
  176. Target = Lookaside->MaximumDepth;
  177. }
  178. }
  179. Lookaside->Depth = (USHORT)Target;
  180. }
  181. return;
  182. }
  183. PVOID
  184. RtlpAllocateFromHeapLookaside (
  185. IN PHEAP_LOOKASIDE Lookaside
  186. )
  187. /*++
  188. Routine Description:
  189. This function removes (pops) the first entry from the specified
  190. heap lookaside list.
  191. Arguments:
  192. Lookaside - Supplies a pointer to a paged lookaside list structure.
  193. Return Value:
  194. If an entry is removed from the specified lookaside list, then the
  195. address of the entry is returned as the function value. Otherwise,
  196. NULL is returned.
  197. --*/
  198. {
  199. PVOID Entry;
  200. Lookaside->TotalAllocates += 1;
  201. //
  202. // We need to protect ourselves from a second thread that can cause us
  203. // to fault on the pop. If we do fault then we'll just do a regular pop
  204. // operation
  205. //
  206. __try {
  207. Entry = RtlpInterlockedPopEntrySList(&Lookaside->ListHead);
  208. } __except (EXCEPTION_EXECUTE_HANDLER) {
  209. Entry = NULL;
  210. }
  211. if (Entry != NULL) {
  212. return Entry;
  213. }
  214. Lookaside->AllocateMisses += 1;
  215. return NULL;
  216. }
  217. BOOLEAN
  218. RtlpFreeToHeapLookaside (
  219. IN PHEAP_LOOKASIDE Lookaside,
  220. IN PVOID Entry
  221. )
  222. /*++
  223. Routine Description:
  224. This function inserts (pushes) the specified entry into the specified
  225. paged lookaside list.
  226. Arguments:
  227. Lookaside - Supplies a pointer to a paged lookaside list structure.
  228. Entry - Supples a pointer to the entry that is inserted in the
  229. lookaside list.
  230. Return Value:
  231. BOOLEAN - TRUE if the entry was put on the lookaside list and FALSE
  232. otherwise.
  233. --*/
  234. {
  235. Lookaside->TotalFrees += 1;
  236. if (RtlpQueryDepthSList(&Lookaside->ListHead) < Lookaside->Depth) {
  237. RtlpInterlockedPushEntrySList(&Lookaside->ListHead,
  238. (PSINGLE_LIST_ENTRY)Entry);
  239. return TRUE;
  240. }
  241. Lookaside->FreeMisses += 1;
  242. return FALSE;
  243. }
  244. // begin_ntslist
  245. INLINE_SLIST
  246. VOID
  247. RtlInitializeSListHead (
  248. IN PSLIST_HEADER SListHead
  249. )
  250. /*++
  251. Routine Description:
  252. This function initializes a sequenced singly linked listhead.
  253. Arguments:
  254. SListHead - Supplies a pointer to a sequenced singly linked listhead.
  255. Return Value:
  256. None.
  257. --*/
  258. {
  259. RtlpInitializeSListHead(SListHead);
  260. return;
  261. }
  262. INLINE_SLIST
  263. PSINGLE_LIST_ENTRY
  264. RtlInterlockedPopEntrySList (
  265. IN PSLIST_HEADER ListHead
  266. )
  267. /*++
  268. Routine Description:
  269. This function removes an entry from the front of a sequenced singly
  270. linked list so that access to the list is synchronized in a MP system.
  271. If there are no entries in the list, then a value of NULL is returned.
  272. Otherwise, the address of the entry that is removed is returned as the
  273. function value.
  274. Arguments:
  275. ListHead - Supplies a pointer to the sequenced listhead from which
  276. an entry is to be removed.
  277. Return Value:
  278. The address of the entry removed from the list, or NULL if the list is
  279. empty.
  280. --*/
  281. {
  282. ULONG Count;
  283. //
  284. // It is posible during the pop of the sequenced list that an access
  285. // violation can occur if a stale pointer is dereferenced. This is an
  286. // acceptable result and the operation can be retried.
  287. //
  288. // N.B. The count is used to distinguish the case where the list head
  289. // itself causes the access violation and therefore no progress
  290. // can be made by repeating the operation.
  291. //
  292. Count = 0;
  293. do {
  294. __try {
  295. return RtlpInterlockedPopEntrySList(ListHead);
  296. } __except (Count++ < 20 ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
  297. continue;
  298. }
  299. } while (TRUE);
  300. }
  301. INLINE_SLIST
  302. PSINGLE_LIST_ENTRY
  303. RtlInterlockedPushEntrySList (
  304. IN PSLIST_HEADER ListHead,
  305. IN PSINGLE_LIST_ENTRY ListEntry
  306. )
  307. /*++
  308. Routine Description:
  309. This function inserts an entry at the head of a sequenced singly linked
  310. list so that access to the list is synchronized in an MP system.
  311. Arguments:
  312. ListHead - Supplies a pointer to the sequenced listhead into which
  313. an entry is to be inserted.
  314. ListEntry - Supplies a pointer to the entry to be inserted at the
  315. head of the list.
  316. Return Value:
  317. The address of the previous firt entry in the list. NULL implies list
  318. went from empty to not empty.
  319. --*/
  320. {
  321. NTSLIST_ASSERT(((ULONG_PTR)ListEntry & 0x7) == 0);
  322. return RtlpInterlockedPushEntrySList(ListHead, ListEntry);
  323. }
  324. INLINE_SLIST
  325. PSINGLE_LIST_ENTRY
  326. RtlInterlockedFlushSList (
  327. IN PSLIST_HEADER ListHead
  328. )
  329. /*++
  330. Routine Description:
  331. This function flushes the entire list of entries on a sequenced singly
  332. linked list so that access to the list is synchronized in a MP system.
  333. If there are no entries in the list, then a value of NULL is returned.
  334. Otherwise, the address of the firt entry on the list is returned as the
  335. function value.
  336. Arguments:
  337. ListHead - Supplies a pointer to the sequenced listhead from which
  338. an entry is to be removed.
  339. Return Value:
  340. The address of the entry removed from the list, or NULL if the list is
  341. empty.
  342. --*/
  343. {
  344. return RtlpInterlockedFlushSList(ListHead);
  345. }
  346. // end_ntslist
  347. USHORT
  348. RtlQueryDepthSList (
  349. IN PSLIST_HEADER SListHead
  350. )
  351. /*++
  352. Routine Description:
  353. This function queries the depth of the specified SLIST.
  354. Arguments:
  355. SListHead - Supplies a pointer to a sequenced singly linked listhead.
  356. Return Value:
  357. The current depth of the specified SLIST is returned as the function
  358. value.
  359. --*/
  360. {
  361. return RtlpQueryDepthSList(SListHead);
  362. }