1 /* $Id: ppool.c,v 1.14 2003/07/29 18:51:11 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 inline static void* block_to_address (
41 MM_PPOOL_USED_BLOCK_HEADER
* blk
)
43 * FUNCTION: Translate a block header address to the corresponding block
47 return ( (void *) ((char*)blk
+ sizeof(MM_PPOOL_USED_BLOCK_HEADER
)) );
50 inline static MM_PPOOL_USED_BLOCK_HEADER
* address_to_block(void* addr
)
52 return (MM_PPOOL_USED_BLOCK_HEADER
*)
53 ( ((char*)addr
) - sizeof(MM_PPOOL_USED_BLOCK_HEADER
) );
56 VOID
MmInitializePagedPool(VOID
)
58 MmPagedPoolFirstFreeBlock
= (PMM_PPOOL_FREE_BLOCK_HEADER
)MmPagedPoolBase
;
60 * We are still at a high IRQL level at this point so explicitly commit
61 * the first page of the paged pool before writing the first block header.
63 MmCommitPagedPoolAddress((PVOID
)MmPagedPoolFirstFreeBlock
);
64 MmPagedPoolFirstFreeBlock
->Size
= MmPagedPoolSize
;
65 MmPagedPoolFirstFreeBlock
->NextFree
= NULL
;
67 ExInitializeFastMutex(&MmPagedPoolLock
);
70 /**********************************************************************
72 * ExAllocatePagedPoolWithTag@12
81 ExAllocatePagedPoolWithTag (IN POOL_TYPE PoolType
,
82 IN ULONG NumberOfBytes
,
85 PMM_PPOOL_FREE_BLOCK_HEADER BestBlock
;
86 PMM_PPOOL_FREE_BLOCK_HEADER CurrentBlock
;
88 PMM_PPOOL_USED_BLOCK_HEADER NewBlock
;
89 PMM_PPOOL_FREE_BLOCK_HEADER NextBlock
;
90 PMM_PPOOL_FREE_BLOCK_HEADER PreviousBlock
;
91 PMM_PPOOL_FREE_BLOCK_HEADER BestPreviousBlock
;
95 * Don't bother allocating anything for a zero-byte block.
97 if (NumberOfBytes
== 0)
103 * Calculate the total number of bytes we will need.
105 BlockSize
= NumberOfBytes
+ sizeof(MM_PPOOL_USED_BLOCK_HEADER
);
106 if (BlockSize
< sizeof(MM_PPOOL_FREE_BLOCK_HEADER
))
108 /* At least we need the size of the free block header. */
109 BlockSize
= sizeof(MM_PPOOL_FREE_BLOCK_HEADER
);
112 ExAcquireFastMutex(&MmPagedPoolLock
);
115 * Find the best fitting block.
117 PreviousBlock
= NULL
;
118 BestPreviousBlock
= BestBlock
= NULL
;
119 CurrentBlock
= MmPagedPoolFirstFreeBlock
;
120 while (CurrentBlock
!= NULL
)
122 if (CurrentBlock
->Size
>= BlockSize
&&
123 (BestBlock
== NULL
||
124 (BestBlock
->Size
- BlockSize
) > (CurrentBlock
->Size
- BlockSize
)))
126 BestPreviousBlock
= PreviousBlock
;
127 BestBlock
= CurrentBlock
;
130 PreviousBlock
= CurrentBlock
;
131 CurrentBlock
= CurrentBlock
->NextFree
;
135 * We didn't find anything suitable at all.
137 if (BestBlock
== NULL
)
139 ExReleaseFastMutex(&MmPagedPoolLock
);
144 * Is there enough space to create a second block from the unused portion.
146 if ((BestBlock
->Size
- BlockSize
) > sizeof(MM_PPOOL_FREE_BLOCK_HEADER
))
148 ULONG NewSize
= BestBlock
->Size
- BlockSize
;
151 * Create the new free block.
153 NextBlock
= (PMM_PPOOL_FREE_BLOCK_HEADER
)((char*)BestBlock
+ BlockSize
);
154 NextBlock
->Size
= NewSize
;
155 NextBlock
->NextFree
= BestBlock
->NextFree
;
158 * Replace the old free block with it.
160 if (BestPreviousBlock
== NULL
)
162 MmPagedPoolFirstFreeBlock
= NextBlock
;
166 BestPreviousBlock
->NextFree
= NextBlock
;
170 * Create the new used block header.
172 NewBlock
= (PMM_PPOOL_USED_BLOCK_HEADER
)BestBlock
;
173 NewBlock
->Size
= BlockSize
;
177 ULONG NewSize
= BestBlock
->Size
;
180 * Remove the selected block from the list of free blocks.
182 if (BestPreviousBlock
== NULL
)
184 MmPagedPoolFirstFreeBlock
= BestBlock
->NextFree
;
188 BestPreviousBlock
->NextFree
= BestBlock
->NextFree
;
192 * Set up the header of the new block
194 NewBlock
= (PMM_PPOOL_USED_BLOCK_HEADER
)BestBlock
;
195 NewBlock
->Size
= NewSize
;
198 ExReleaseFastMutex(&MmPagedPoolLock
);
200 BlockAddress
= block_to_address ( NewBlock
);
202 memset(BlockAddress
, 0, NumberOfBytes
);
204 return(BlockAddress
);
208 ExFreePagedPool(IN PVOID Block
)
210 PMM_PPOOL_FREE_BLOCK_HEADER PreviousBlock
;
211 PMM_PPOOL_USED_BLOCK_HEADER UsedBlock
= address_to_block(Block
);
212 ULONG UsedSize
= UsedBlock
->Size
;
213 PMM_PPOOL_FREE_BLOCK_HEADER FreeBlock
=
214 (PMM_PPOOL_FREE_BLOCK_HEADER
)UsedBlock
;
215 PMM_PPOOL_FREE_BLOCK_HEADER NextBlock
;
216 PMM_PPOOL_FREE_BLOCK_HEADER NextNextBlock
;
218 ExAcquireFastMutex(&MmPagedPoolLock
);
221 * Begin setting up the newly freed block's header.
223 FreeBlock
->Size
= UsedSize
;
226 * Find the blocks immediately before and after the newly freed block on the free list.
228 PreviousBlock
= NULL
;
229 NextBlock
= MmPagedPoolFirstFreeBlock
;
230 while (NextBlock
!= NULL
&& NextBlock
< FreeBlock
)
232 PreviousBlock
= NextBlock
;
233 NextBlock
= NextBlock
->NextFree
;
237 * Insert the freed block on the free list.
239 if (PreviousBlock
== NULL
)
241 FreeBlock
->NextFree
= MmPagedPoolFirstFreeBlock
;
242 MmPagedPoolFirstFreeBlock
= FreeBlock
;
246 PreviousBlock
->NextFree
= FreeBlock
;
247 FreeBlock
->NextFree
= NextBlock
;
251 * If the next block is immediately adjacent to the newly freed one then
254 if (NextBlock
!= NULL
&&
255 ((char*)FreeBlock
+ FreeBlock
->Size
) == (char*)NextBlock
)
257 FreeBlock
->Size
= FreeBlock
->Size
+ NextBlock
->Size
;
258 FreeBlock
->NextFree
= NextBlock
->NextFree
;
259 NextNextBlock
= NextBlock
->NextFree
;
263 NextNextBlock
= NextBlock
;
267 * If the previous block is adjacent to the newly freed one then
270 if (PreviousBlock
!= NULL
&&
271 ((char*)PreviousBlock
+ PreviousBlock
->Size
) == (char*)FreeBlock
)
273 PreviousBlock
->Size
= PreviousBlock
->Size
+ FreeBlock
->Size
;
274 PreviousBlock
->NextFree
= NextNextBlock
;
277 ExReleaseFastMutex(&MmPagedPoolLock
);