Sync with trunk r63786.
[reactos.git] / drivers / sac / driver / memory.c
1 /*
2 * PROJECT: ReactOS Drivers
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: drivers/sac/driver/memory.c
5 * PURPOSE: Driver for the Server Administration Console (SAC) for EMS
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include "sacdrv.h"
12
13 /* GLOBALS ********************************************************************/
14
15 LONG TotalFrees, TotalBytesFreed, TotalAllocations, TotalBytesAllocated;
16 KSPIN_LOCK MemoryLock;
17 PSAC_MEMORY_LIST GlobalMemoryList;
18
19 /* FUNCTIONS ******************************************************************/
20
21 BOOLEAN
22 NTAPI
23 InitializeMemoryManagement(VOID)
24 {
25 PSAC_MEMORY_ENTRY Entry;
26 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n");
27
28 /* Allocate a nonpaged heap for us to use */
29 GlobalMemoryList = ExAllocatePoolWithTagPriority(NonPagedPool,
30 SAC_MEMORY_LIST_SIZE,
31 INITIAL_BLOCK_TAG,
32 HighPoolPriority);
33 if (GlobalMemoryList)
34 {
35 /* Initialize a lock for it */
36 KeInitializeSpinLock(&MemoryLock);
37
38 /* Initialize the head of the list */
39 GlobalMemoryList->Signature = GLOBAL_MEMORY_SIGNATURE;
40 GlobalMemoryList->LocalDescriptor = (PSAC_MEMORY_ENTRY)(GlobalMemoryList + 1);
41 GlobalMemoryList->Size = SAC_MEMORY_LIST_SIZE - sizeof(SAC_MEMORY_LIST);
42 GlobalMemoryList->Next = NULL;
43
44 /* Initialize the first free entry */
45 Entry = GlobalMemoryList->LocalDescriptor;
46 Entry->Signature = LOCAL_MEMORY_SIGNATURE;
47 Entry->Tag = FREE_POOL_TAG;
48 Entry->Size = GlobalMemoryList->Size - sizeof(SAC_MEMORY_ENTRY);
49
50 /* All done */
51 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting with TRUE.\n");
52 return TRUE;
53 }
54
55 /* No pool available to manage our heap */
56 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting with FALSE. No pool.\n");
57 return FALSE;
58 }
59
60 VOID
61 NTAPI
62 FreeMemoryManagement(VOID)
63 {
64 PSAC_MEMORY_LIST Next;
65 KIRQL OldIrql;
66 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n");
67
68 /* Acquire the memory lock while freeing the list(s) */
69 KeAcquireSpinLock(&MemoryLock, &OldIrql);
70 while (GlobalMemoryList)
71 {
72 ASSERT(GlobalMemoryList->Signature == GLOBAL_MEMORY_SIGNATURE);
73
74 /* While outisde of the lock, save the next list and free this one */
75 KeReleaseSpinLock(&MemoryLock, OldIrql);
76 Next = GlobalMemoryList->Next;
77 ExFreePoolWithTag(GlobalMemoryList, 0);
78
79 /* Reacquire the lock and see if there was another list to free */
80 KeAcquireSpinLock(&MemoryLock, &OldIrql);
81 GlobalMemoryList = Next;
82 }
83
84 /* All done */
85 KeReleaseSpinLock(&MemoryLock, OldIrql);
86 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting\n");
87 }
88
89 PVOID
90 NTAPI
91 MyAllocatePool(IN SIZE_T PoolSize,
92 IN ULONG Tag,
93 IN PCHAR File,
94 IN ULONG Line)
95 {
96 PVOID p;
97 p = ExAllocatePoolWithTag(NonPagedPool, PoolSize, 'HACK');
98 RtlZeroMemory(p, PoolSize);
99 SAC_DBG(SAC_DBG_MM, "Returning block 0x%X.\n", p);
100 return p;
101 #if 0
102 KIRQL OldIrql;
103 PSAC_MEMORY_LIST GlobalDescriptor, NewDescriptor;
104 PSAC_MEMORY_ENTRY LocalDescriptor, NextDescriptor;
105 ULONG GlobalSize, ActualSize;
106 PVOID Buffer;
107
108 ASSERT(Tag != FREE_POOL_TAG);
109 SAC_DBG(SAC_DBG_MM, "Entering.\n");
110
111 /* Acquire the memory allocation lock and align the size request */
112 KeAcquireSpinLock(&MemoryLock, &OldIrql);
113 PoolSize = ALIGN_UP(PoolSize, ULONGLONG);
114
115 #if _USE_SAC_HEAP_ALLOCATOR_
116 GlobalDescriptor = GlobalMemoryList;
117 KeAcquireSpinLock(&MemoryLock, &OldIrql);
118 while (GlobalDescriptor)
119 {
120 ASSERT(GlobalMemoryList->Signature == GLOBAL_MEMORY_SIGNATURE);
121
122 LocalDescriptor = GlobalDescriptor->LocalDescriptor;
123
124 GlobalSize = GlobalDescriptor->Size;
125 while (GlobalSize)
126 {
127 ASSERT(LocalDescriptor->Signature == LOCAL_MEMORY_SIGNATURE);
128
129 if ((LocalDescriptor->Tag == FREE_POOL_TAG) &&
130 (LocalDescriptor->Size >= PoolSize))
131 {
132 break;
133 }
134
135 GlobalSize -= (LocalDescriptor->Size + sizeof(SAC_MEMORY_ENTRY));
136
137 LocalDescriptor =
138 (PSAC_MEMORY_ENTRY)((ULONG_PTR)LocalDescriptor +
139 LocalDescriptor->Size +
140 sizeof(SAC_MEMORY_ENTRY));
141 }
142
143 GlobalDescriptor = GlobalDescriptor->Next;
144 }
145
146 if (!GlobalDescriptor)
147 {
148 KeReleaseSpinLock(&MemoryLock, OldIrql);
149
150 ActualSize = min(
151 PAGE_SIZE,
152 PoolSize + sizeof(SAC_MEMORY_ENTRY) + sizeof(SAC_MEMORY_LIST));
153
154 SAC_DBG(SAC_DBG_MM, "Allocating new space.\n");
155
156 NewDescriptor = ExAllocatePoolWithTagPriority(NonPagedPool,
157 ActualSize,
158 ALLOC_BLOCK_TAG,
159 HighPoolPriority);
160 if (!NewDescriptor)
161 {
162 SAC_DBG(SAC_DBG_MM, "No more memory, returning NULL.\n");
163 return NULL;
164 }
165
166 KeAcquireSpinLock(&MemoryLock, &OldIrql);
167
168 NewDescriptor->Signature = GLOBAL_MEMORY_SIGNATURE;
169 NewDescriptor->LocalDescriptor = (PSAC_MEMORY_ENTRY)(NewDescriptor + 1);
170 NewDescriptor->Size = ActualSize - 16;
171 NewDescriptor->Next = GlobalMemoryList;
172
173 GlobalMemoryList = NewDescriptor;
174
175 LocalDescriptor = NewDescriptor->LocalDescriptor;
176 LocalDescriptor->Signature = LOCAL_MEMORY_SIGNATURE;
177 LocalDescriptor->Tag = FREE_POOL_TAG;
178 LocalDescriptor->Size =
179 GlobalMemoryList->Size - sizeof(SAC_MEMORY_ENTRY);
180 }
181
182 SAC_DBG(SAC_DBG_MM, "Found a good sized block.\n");
183 ASSERT(LocalDescriptor->Tag == FREE_POOL_TAG);
184 ASSERT(LocalDescriptor->Signature == LOCAL_MEMORY_SIGNATURE);
185
186 if (LocalDescriptor->Size > (PoolSize + sizeof(SAC_MEMORY_ENTRY)))
187 {
188 NextDescriptor =
189 (PSAC_MEMORY_ENTRY)((ULONG_PTR)LocalDescriptor +
190 PoolSize +
191 sizeof(SAC_MEMORY_ENTRY));
192 if (NextDescriptor->Tag == FREE_POOL_TAG)
193 {
194 NextDescriptor->Tag = FREE_POOL_TAG;
195 NextDescriptor->Signature = LOCAL_MEMORY_SIGNATURE;
196 NextDescriptor->Size =
197 (LocalDescriptor->Size - PoolSize - sizeof(SAC_MEMORY_ENTRY));
198
199 LocalDescriptor->Size = PoolSize;
200 }
201 }
202 #else
203 /* Shut the compiler up */
204 NewDescriptor = GlobalDescriptor = NULL;
205 GlobalSize = (ULONG)NewDescriptor;
206 ActualSize = GlobalSize;
207 NextDescriptor = (PVOID)ActualSize;
208 NewDescriptor = (PVOID)NextDescriptor;
209
210 /* Use the NT pool allocator */
211 LocalDescriptor = ExAllocatePoolWithTag(NonPagedPool,
212 PoolSize + sizeof(*LocalDescriptor),
213 Tag);
214 LocalDescriptor->Size = PoolSize;
215 #endif
216 /* Set the tag, and release the lock */
217 LocalDescriptor->Tag = Tag;
218 KeReleaseSpinLock(&MemoryLock, OldIrql);
219
220 /* Update our performance counters */
221 InterlockedIncrement(&TotalAllocations);
222 InterlockedExchangeAdd(&TotalBytesAllocated, LocalDescriptor->Size);
223
224 /* Return the buffer and zero it */
225 SAC_DBG(SAC_DBG_MM, "Returning block 0x%X.\n", LocalDescriptor);
226 Buffer = LocalDescriptor + 1;
227 RtlZeroMemory(Buffer, PoolSize);
228 return Buffer;
229 #endif
230 }
231
232 VOID
233 NTAPI
234 MyFreePool(IN PVOID *Block)
235 {
236 #if 0
237 PSAC_MEMORY_ENTRY NextDescriptor;
238 PSAC_MEMORY_ENTRY ThisDescriptor, FoundDescriptor;
239 PSAC_MEMORY_ENTRY LocalDescriptor = (PVOID)((ULONG_PTR)(*Block) - sizeof(SAC_MEMORY_ENTRY));
240 ULONG GlobalSize, LocalSize;
241 PSAC_MEMORY_LIST GlobalDescriptor;
242 KIRQL OldIrql;
243 SAC_DBG(SAC_DBG_MM, "Entering with block 0x%X.\n", LocalDescriptor);
244
245 /* Make sure this was a valid entry */
246 ASSERT(LocalDescriptor->Size > 0);
247 ASSERT(LocalDescriptor->Signature == LOCAL_MEMORY_SIGNATURE);
248
249 /* Update performance counters */
250 InterlockedIncrement(&TotalFrees);
251 InterlockedExchangeAdd(&TotalBytesFreed, LocalDescriptor->Size);
252
253 /* Acquire the memory alliocation lock */
254 GlobalDescriptor = GlobalMemoryList;
255 KeAcquireSpinLock(&MemoryLock, &OldIrql);
256
257 #if _USE_SAC_HEAP_ALLOCATOR_
258 while (GlobalDescriptor)
259 {
260 ASSERT(GlobalMemoryList->Signature == GLOBAL_MEMORY_SIGNATURE);
261
262 FoundDescriptor = NULL;
263
264 ThisDescriptor = GlobalDescriptor->LocalDescriptor;
265
266 GlobalSize = GlobalDescriptor->Size;
267 while (GlobalSize)
268 {
269 ASSERT(ThisDescriptor->Signature == LOCAL_MEMORY_SIGNATURE);
270
271 if (ThisDescriptor == LocalDescriptor) break;
272
273 GlobalSize -= (ThisDescriptor->Size + sizeof(SAC_MEMORY_ENTRY));
274
275 ThisDescriptor =
276 (PSAC_MEMORY_ENTRY)((ULONG_PTR)ThisDescriptor +
277 ThisDescriptor->Size +
278 sizeof(SAC_MEMORY_ENTRY));
279 }
280
281 if (ThisDescriptor == LocalDescriptor) break;
282
283 GlobalDescriptor = GlobalDescriptor->Next;
284 }
285
286 if (!GlobalDescriptor)
287 {
288 KeReleaseSpinLock(&MemoryLock, OldIrql);
289 SAC_DBG(SAC_DBG_MM, "Could not find block.\n");
290 return;
291 }
292
293 ASSERT(ThisDescriptor->Signature == LOCAL_MEMORY_SIGNATURE);
294
295 if (LocalDescriptor->Tag == FREE_POOL_TAG)
296 {
297 KeReleaseSpinLock(&MemoryLock, OldIrql);
298 SAC_DBG(SAC_DBG_MM, "Attempted to free something twice.\n");
299 return;
300 }
301
302 LocalSize = LocalDescriptor->Size;
303 LocalDescriptor->Tag = FREE_POOL_TAG;
304
305 if (GlobalSize > (LocalSize + sizeof(SAC_MEMORY_ENTRY)))
306 {
307 NextDescriptor =
308 (PSAC_MEMORY_ENTRY)((ULONG_PTR)LocalDescriptor +
309 LocalSize +
310 sizeof(SAC_MEMORY_ENTRY));
311 if (NextDescriptor->Tag == FREE_POOL_TAG)
312 {
313 NextDescriptor->Tag = 0;
314 NextDescriptor->Signature = 0;
315
316 LocalDescriptor->Size +=
317 (NextDescriptor->Size + sizeof(SAC_MEMORY_ENTRY));
318 }
319 }
320
321 if ((FoundDescriptor) && (FoundDescriptor->Tag == FREE_POOL_TAG))
322 {
323 LocalDescriptor->Signature = 0;
324 LocalDescriptor->Tag = 0;
325
326 FoundDescriptor->Size +=
327 (LocalDescriptor->Size + sizeof(SAC_MEMORY_ENTRY));
328 }
329 #else
330 /* Shut the compiler up */
331 LocalSize = GlobalSize = 0;
332 ThisDescriptor = (PVOID)LocalSize;
333 NextDescriptor = (PVOID)GlobalSize;
334 GlobalDescriptor = (PVOID)ThisDescriptor;
335 FoundDescriptor = (PVOID)GlobalDescriptor;
336 GlobalDescriptor = (PVOID)NextDescriptor;
337 NextDescriptor = (PVOID)FoundDescriptor;
338
339 /* Use the NT pool allocator*/
340 ExFreePool(LocalDescriptor);
341 #endif
342
343 /* Release the lock, delete the address, and return */
344 KeReleaseSpinLock(&MemoryLock, OldIrql);
345 #endif
346 SAC_DBG(SAC_DBG_MM, "exiting: 0x%p.\n", *Block);
347 ExFreePoolWithTag(*Block, 'HACK');
348 *Block = NULL;
349 }