1 /* $Id: ppool.c,v 1.12 2003/07/10 21:05:04 royce Exp $
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/mm/ppool.c
6 * PURPOSE: Implements the paged pool
7 * PROGRAMMER: David Welch (welch@mcmail.com)
12 /* INCLUDES *****************************************************************/
14 #include <ddk/ntddk.h>
15 #include <internal/pool.h>
16 #include <internal/mm.h>
18 #include <internal/debug.h>
20 /* GLOBALS *******************************************************************/
22 typedef struct _MM_PPOOL_FREE_BLOCK_HEADER
25 struct _MM_PPOOL_FREE_BLOCK_HEADER
* NextFree
;
26 } MM_PPOOL_FREE_BLOCK_HEADER
, *PMM_PPOOL_FREE_BLOCK_HEADER
;
28 typedef struct _MM_PPOOL_USED_BLOCK_HEADER
31 } MM_PPOOL_USED_BLOCK_HEADER
, *PMM_PPOOL_USED_BLOCK_HEADER
;
33 PVOID MmPagedPoolBase
;
34 ULONG MmPagedPoolSize
;
35 static FAST_MUTEX MmPagedPoolLock
;
36 static PMM_PPOOL_FREE_BLOCK_HEADER MmPagedPoolFirstFreeBlock
;
38 /* FUNCTIONS *****************************************************************/
40 VOID
MmInitializePagedPool(VOID
)
42 MmPagedPoolFirstFreeBlock
= (PMM_PPOOL_FREE_BLOCK_HEADER
)MmPagedPoolBase
;
44 * We are still at a high IRQL level at this point so explicitly commit
45 * the first page of the paged pool before writing the first block header.
47 MmCommitPagedPoolAddress((PVOID
)MmPagedPoolFirstFreeBlock
);
48 MmPagedPoolFirstFreeBlock
->Size
= MmPagedPoolSize
;
49 MmPagedPoolFirstFreeBlock
->NextFree
= NULL
;
51 ExInitializeFastMutex(&MmPagedPoolLock
);
54 /**********************************************************************
56 * ExAllocatePagedPoolWithTag@12
67 ExAllocatePagedPoolWithTag (IN POOL_TYPE PoolType
,
68 IN ULONG NumberOfBytes
,
71 PMM_PPOOL_FREE_BLOCK_HEADER BestBlock
;
72 PMM_PPOOL_FREE_BLOCK_HEADER CurrentBlock
;
74 PMM_PPOOL_USED_BLOCK_HEADER NewBlock
;
75 PMM_PPOOL_FREE_BLOCK_HEADER NextBlock
;
76 PMM_PPOOL_FREE_BLOCK_HEADER PreviousBlock
;
77 PMM_PPOOL_FREE_BLOCK_HEADER BestPreviousBlock
;
81 * Don't bother allocating anything for a zero-byte block.
83 if (NumberOfBytes
== 0)
89 * Calculate the total number of bytes we will need.
91 BlockSize
= NumberOfBytes
+ sizeof(MM_PPOOL_USED_BLOCK_HEADER
);
92 if (BlockSize
< sizeof(MM_PPOOL_FREE_BLOCK_HEADER
))
94 /* At least we need the size of the free block header. */
95 BlockSize
= sizeof(MM_PPOOL_FREE_BLOCK_HEADER
);
98 ExAcquireFastMutex(&MmPagedPoolLock
);
101 * Find the best fitting block.
103 PreviousBlock
= NULL
;
104 BestPreviousBlock
= BestBlock
= NULL
;
105 CurrentBlock
= MmPagedPoolFirstFreeBlock
;
106 while (CurrentBlock
!= NULL
)
108 if (CurrentBlock
->Size
>= BlockSize
&&
109 (BestBlock
== NULL
||
110 (BestBlock
->Size
- BlockSize
) > (CurrentBlock
->Size
- BlockSize
)))
112 BestPreviousBlock
= PreviousBlock
;
113 BestBlock
= CurrentBlock
;
116 PreviousBlock
= CurrentBlock
;
117 CurrentBlock
= CurrentBlock
->NextFree
;
121 * We didn't find anything suitable at all.
123 if (BestBlock
== NULL
)
125 ExReleaseFastMutex(&MmPagedPoolLock
);
130 * Is there enough space to create a second block from the unused portion.
132 if ((BestBlock
->Size
- BlockSize
) > sizeof(MM_PPOOL_FREE_BLOCK_HEADER
))
134 ULONG NewSize
= BestBlock
->Size
- BlockSize
;
137 * Create the new free block.
139 NextBlock
= (PMM_PPOOL_FREE_BLOCK_HEADER
)((PVOID
)BestBlock
+ BlockSize
);
140 NextBlock
->Size
= NewSize
;
141 NextBlock
->NextFree
= BestBlock
->NextFree
;
144 * Replace the old free block with it.
146 if (BestPreviousBlock
== NULL
)
148 MmPagedPoolFirstFreeBlock
= NextBlock
;
152 BestPreviousBlock
->NextFree
= NextBlock
;
156 * Create the new used block header.
158 NewBlock
= (PMM_PPOOL_USED_BLOCK_HEADER
)BestBlock
;
159 NewBlock
->Size
= BlockSize
;
163 ULONG NewSize
= BestBlock
->Size
;
166 * Remove the selected block from the list of free blocks.
168 if (BestPreviousBlock
== NULL
)
170 MmPagedPoolFirstFreeBlock
= BestBlock
->NextFree
;
174 BestPreviousBlock
->NextFree
= BestBlock
->NextFree
;
178 * Set up the header of the new block
180 NewBlock
= (PMM_PPOOL_USED_BLOCK_HEADER
)BestBlock
;
181 NewBlock
->Size
= NewSize
;
184 ExReleaseFastMutex(&MmPagedPoolLock
);
186 BlockAddress
= (PVOID
)NewBlock
+ sizeof(MM_PPOOL_USED_BLOCK_HEADER
);
188 memset(BlockAddress
, 0, NumberOfBytes
);
190 return(BlockAddress
);
197 ExFreePagedPool(IN PVOID Block
)
199 PMM_PPOOL_FREE_BLOCK_HEADER PreviousBlock
;
200 PMM_PPOOL_USED_BLOCK_HEADER UsedBlock
=
201 (PMM_PPOOL_USED_BLOCK_HEADER
)(Block
- sizeof(MM_PPOOL_USED_BLOCK_HEADER
));
202 ULONG UsedSize
= UsedBlock
->Size
;
203 PMM_PPOOL_FREE_BLOCK_HEADER FreeBlock
=
204 (PMM_PPOOL_FREE_BLOCK_HEADER
)UsedBlock
;
205 PMM_PPOOL_FREE_BLOCK_HEADER NextBlock
;
206 PMM_PPOOL_FREE_BLOCK_HEADER NextNextBlock
;
208 ExAcquireFastMutex(&MmPagedPoolLock
);
211 * Begin setting up the newly freed block's header.
213 FreeBlock
->Size
= UsedSize
;
216 * Find the blocks immediately before and after the newly freed block on the free list.
218 PreviousBlock
= NULL
;
219 NextBlock
= MmPagedPoolFirstFreeBlock
;
220 while (NextBlock
!= NULL
&& NextBlock
< FreeBlock
)
222 PreviousBlock
= NextBlock
;
223 NextBlock
= NextBlock
->NextFree
;
227 * Insert the freed block on the free list.
229 if (PreviousBlock
== NULL
)
231 FreeBlock
->NextFree
= MmPagedPoolFirstFreeBlock
;
232 MmPagedPoolFirstFreeBlock
= FreeBlock
;
236 PreviousBlock
->NextFree
= FreeBlock
;
237 FreeBlock
->NextFree
= NextBlock
;
241 * If the next block is immediately adjacent to the newly freed one then
244 if (NextBlock
!= NULL
&&
245 ((PVOID
)FreeBlock
+ FreeBlock
->Size
) == (PVOID
)NextBlock
)
247 FreeBlock
->Size
= FreeBlock
->Size
+ NextBlock
->Size
;
248 FreeBlock
->NextFree
= NextBlock
->NextFree
;
249 NextNextBlock
= NextBlock
->NextFree
;
253 NextNextBlock
= NextBlock
;
257 * If the previous block is adjacent to the newly freed one then
260 if (PreviousBlock
!= NULL
&&
261 ((PVOID
)PreviousBlock
+ PreviousBlock
->Size
) == (PVOID
)FreeBlock
)
263 PreviousBlock
->Size
= PreviousBlock
->Size
+ FreeBlock
->Size
;
264 PreviousBlock
->NextFree
= NextNextBlock
;
267 ExReleaseFastMutex(&MmPagedPoolLock
);