xref: /reactos/drivers/sac/driver/memory.c (revision 1734f297)
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 outside 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 allocation 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 }
350