Sync with trunk head (r49139)
[reactos.git] / dll / win32 / kernel32 / mem / local.c
1 /*
2 * PROJECT: ReactOS Win32 Base API
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/win32/kernel32/mem/local.c
5 * PURPOSE: Local Memory APIs (sits on top of Heap*)
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <k32.h>
12
13 #define NDEBUG
14 #include <debug.h>
15
16 /* TYPES *********************************************************************/
17
18 extern SYSTEM_BASIC_INFORMATION BaseCachedSysInfo;
19
20 /* FUNCTIONS ***************************************************************/
21
22 /*
23 * @implemented
24 */
25 HLOCAL
26 NTAPI
27 LocalAlloc(UINT uFlags,
28 SIZE_T dwBytes)
29 {
30 ULONG Flags = 0;
31 PVOID Ptr = NULL;
32 HANDLE hMemory;
33 PBASE_HEAP_HANDLE_ENTRY HandleEntry;
34 BASE_TRACE_ALLOC(dwBytes, uFlags);
35 ASSERT(hProcessHeap);
36
37 /* Make sure the flags are valid */
38 if (uFlags & ~LMEM_VALID_FLAGS)
39 {
40 /* They aren't, fail */
41 BASE_TRACE_FAILURE();
42 SetLastError(ERROR_INVALID_PARAMETER);
43 return NULL;
44 }
45
46 /* Convert ZEROINIT */
47 if (uFlags & LMEM_ZEROINIT) Flags |= HEAP_ZERO_MEMORY;
48
49 /* Check if we're not movable, which means pointer-based heap */
50 if (!(uFlags & LMEM_MOVEABLE))
51 {
52 /* Allocate heap for it */
53 Ptr = RtlAllocateHeap(hProcessHeap, Flags, dwBytes);
54 BASE_TRACE_ALLOC2(Ptr);
55 return Ptr;
56 }
57
58 /* This is heap based, so lock it in first */
59 RtlLockHeap(hProcessHeap);
60
61 /*
62 * Disable locking, enable custom flags, and write the
63 * movable flag (deprecated)
64 */
65 Flags |= HEAP_NO_SERIALIZE |
66 HEAP_SETTABLE_USER_VALUE |
67 BASE_HEAP_FLAG_MOVABLE;
68
69 /* Allocate the handle */
70 HandleEntry = BaseHeapAllocEntry();
71 if (!HandleEntry)
72 {
73 /* Fail */
74 hMemory = NULL;
75 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
76 BASE_TRACE_FAILURE();
77 goto Quickie;
78 }
79
80 /* Get the object and make sure we have size */
81 hMemory = &HandleEntry->Object;
82 if (dwBytes)
83 {
84 /* Allocate the actual memory for it */
85 Ptr = RtlAllocateHeap(hProcessHeap, Flags, dwBytes);
86 BASE_TRACE_PTR(HandleEntry, Ptr);
87 if (!Ptr)
88 {
89 /* We failed, manually set the allocate flag and free the handle */
90 HandleEntry->Flags = RTL_HANDLE_VALID;
91 BaseHeapFreeEntry(HandleEntry);
92
93 /* For the cleanup case */
94 HandleEntry = NULL;
95 }
96 else
97 {
98 /* All worked well, save our heap entry */
99 RtlSetUserValueHeap(hProcessHeap, HEAP_NO_SERIALIZE, Ptr, hMemory);
100 }
101 }
102
103 Quickie:
104 /* Cleanup! First unlock the heap */
105 RtlUnlockHeap(hProcessHeap);
106
107 /* Check if a handle was allocated */
108 if (HandleEntry)
109 {
110 /* Set the pointer and allocated flag */
111 HandleEntry->Object = Ptr;
112 HandleEntry->Flags = RTL_HANDLE_VALID;
113 if (!Ptr)
114 {
115 /* We don't have a valid pointer, but so reuse this handle */
116 HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSE;
117 }
118
119 /* Check if the handle is discardable */
120 if (uFlags & GMEM_DISCARDABLE)
121 {
122 /* Save it in the handle entry */
123 HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSABLE;
124 }
125
126 /* Check if the handle is moveable */
127 if (uFlags & GMEM_MOVEABLE)
128 {
129 /* Save it in the handle entry */
130 HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_MOVABLE;
131 }
132
133 /* Set the pointer */
134 Ptr = hMemory;
135 }
136
137 /* Return the pointer */
138 return Ptr;
139 }
140
141 /*
142 * @implemented
143 */
144 SIZE_T
145 NTAPI
146 LocalCompact(UINT dwMinFree)
147 {
148 /* Call the RTL Heap Manager */
149 return RtlCompactHeap(hProcessHeap, 0);
150 }
151
152 /*
153 * @implemented
154 */
155 UINT
156 NTAPI
157 LocalFlags(HLOCAL hMem)
158 {
159 PBASE_HEAP_HANDLE_ENTRY HandleEntry;
160 HANDLE Handle = NULL;
161 ULONG Flags = 0;
162 UINT uFlags = LMEM_INVALID_HANDLE;
163
164 /* Start by locking the heap */
165 RtlLockHeap(hProcessHeap);
166
167 /* Check if this is a simple RTL Heap Managed block */
168 if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY))
169 {
170 /* Then we'll query RTL Heap */
171 RtlGetUserInfoHeap(hProcessHeap, Flags, hMem, &Handle, &Flags);
172 BASE_TRACE_PTR(Handle, hMem);
173
174 /*
175 * Check if RTL Heap didn't find a handle associated with us or
176 * said that this heap isn't movable, which means something we're
177 * really not a handle-based heap.
178 */
179 if (!(Handle) || !(Flags & BASE_HEAP_FLAG_MOVABLE))
180 {
181 /* Then set the flags to 0 */
182 uFlags = 0;
183 }
184 else
185 {
186 /* Otherwise we're handle-based, so get the internal handle */
187 hMem = Handle;
188 }
189 }
190
191 /* Check if the handle is actually an entry in our table */
192 if ((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY)
193 {
194 /* Then get the entry */
195 HandleEntry = BaseHeapGetEntry(hMem);
196 BASE_TRACE_HANDLE(HandleEntry, hMem);
197
198 /* Make sure it's a valid handle */
199 if (BaseHeapValidateEntry(HandleEntry))
200 {
201 /* Get the lock count first */
202 uFlags = HandleEntry->LockCount & LMEM_LOCKCOUNT;
203
204 /* Now check if it's discardable */
205 if (HandleEntry->Flags & BASE_HEAP_ENTRY_FLAG_REUSABLE)
206 {
207 /* Set the Win32 Flag */
208 uFlags |= LMEM_DISCARDABLE;
209 }
210
211 /* Now check if it's discarded */
212 if (HandleEntry->Flags & BASE_HEAP_ENTRY_FLAG_REUSE)
213 /* Set the Win32 Flag */
214 uFlags |= LMEM_DISCARDED;
215 }
216 }
217
218 /* Check if by now, we still haven't gotten any useful flags */
219 if (uFlags == LMEM_INVALID_HANDLE) SetLastError(ERROR_INVALID_HANDLE);
220
221 /* All done! Unlock heap and return Win32 Flags */
222 RtlUnlockHeap(hProcessHeap);
223 return uFlags;
224 }
225
226 /*
227 * @implemented
228 */
229 HLOCAL
230 NTAPI
231 LocalFree(HLOCAL hMem)
232 {
233 /* This is identical to a Global Free */
234 return GlobalFree(hMem);
235 }
236
237 /*
238 * @implemented
239 */
240 HLOCAL
241 NTAPI
242 LocalHandle(LPCVOID pMem)
243 {
244 /* This is identical to a Global Handle */
245 return GlobalHandle(pMem);
246 }
247
248 /*
249 * @implemented
250 */
251 LPVOID
252 NTAPI
253 LocalLock(HLOCAL hMem)
254 {
255 /* This is the same as a GlobalLock, assuming these never change */
256 C_ASSERT(LMEM_LOCKCOUNT == GMEM_LOCKCOUNT);
257 return GlobalLock(hMem);
258 }
259
260 HLOCAL
261 NTAPI
262 LocalReAlloc(HLOCAL hMem,
263 SIZE_T dwBytes,
264 UINT uFlags)
265 {
266 PBASE_HEAP_HANDLE_ENTRY HandleEntry;
267 LPVOID Ptr;
268 ULONG Flags = 0;
269
270 /* Convert ZEROINIT */
271 if (uFlags & LMEM_ZEROINIT) Flags |= HEAP_ZERO_MEMORY;
272
273 /* If this wasn't a movable heap, then we MUST re-alloc in place */
274 if (!(uFlags & LMEM_MOVEABLE)) Flags |= HEAP_REALLOC_IN_PLACE_ONLY;
275
276 /* Lock the heap and disable built-in locking in the RTL Heap funcitons */
277 RtlLockHeap(hProcessHeap);
278 Flags |= HEAP_NO_SERIALIZE;
279
280 /* Check if this is a simple handle-based block */
281 if (((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY))
282 {
283 /* Get the entry */
284 HandleEntry = BaseHeapGetEntry(hMem);
285 BASE_TRACE_HANDLE(HandleEntry, hMem);
286
287 /* Make sure the handle is valid */
288 if (!BaseHeapValidateEntry(HandleEntry))
289 {
290 /* Fail */
291 BASE_TRACE_FAILURE();
292 SetLastError(ERROR_INVALID_HANDLE);
293 hMem = NULL;
294 }
295 else if (uFlags & LMEM_MODIFY)
296 {
297 /* User is changing flags... check if the memory was discardable */
298 if (uFlags & LMEM_DISCARDABLE)
299 {
300 /* Then set the flag */
301 HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSABLE;
302 }
303 else
304 {
305 /* Otherwise, remove the flag */
306 HandleEntry->Flags &= BASE_HEAP_ENTRY_FLAG_REUSABLE;
307 }
308 }
309 else
310 {
311 /* Otherwise, get the object and check if we have no size */
312 Ptr = HandleEntry->Object;
313 if (!dwBytes)
314 {
315 /* Clear the handle and check for a pointer */
316 hMem = NULL;
317 if (Ptr)
318 {
319 /* Make sure the handle isn't locked */
320 if ((uFlags & LMEM_MOVEABLE) && !(HandleEntry->LockCount))
321 {
322 /* Free the current heap */
323 RtlFreeHeap(hProcessHeap, Flags, Ptr);
324
325 /* Free the handle */
326 HandleEntry->Object = NULL;
327 HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSE;
328
329 /* Get the object pointer */
330 hMem = &HandleEntry->Object;
331 }
332 }
333 else
334 {
335 /* Otherwise just return the object pointer */
336 hMem = &HandleEntry->Object;
337 }
338 }
339 else
340 {
341 /* Otherwise, we're allocating, so set the new flags needed */
342 Flags |= HEAP_SETTABLE_USER_VALUE | BASE_HEAP_FLAG_MOVABLE;
343 if (!Ptr)
344 {
345 /* We don't have a base, so allocate one */
346 Ptr = RtlAllocateHeap(hProcessHeap, Flags, dwBytes);
347 BASE_TRACE_ALLOC2(Ptr);
348 if (Ptr)
349 {
350 /* Allocation succeeded, so save our entry */
351 RtlSetUserValueHeap(hProcessHeap,
352 HEAP_NO_SERIALIZE,
353 Ptr,
354 hMem);
355 }
356 }
357 else
358 {
359 /*
360 * If it's not movable or currently locked, we MUST allocate
361 * in-place!
362 */
363 if (!(uFlags & LMEM_MOVEABLE) && (HandleEntry->LockCount))
364 {
365 /* Set the flag */
366 Flags |= HEAP_REALLOC_IN_PLACE_ONLY;
367 }
368 else
369 {
370 /* Otherwise clear the flag if we set it previously */
371 Flags &= ~HEAP_REALLOC_IN_PLACE_ONLY;
372 }
373
374 /* And do the re-allocation */
375 Ptr = RtlReAllocateHeap(hProcessHeap, Flags, Ptr, dwBytes);
376 }
377
378 /* Make sure we have a pointer by now */
379 if (Ptr)
380 {
381 /* Write it in the handle entry and mark it in use */
382 HandleEntry->Object = Ptr;
383 HandleEntry->Flags &= ~BASE_HEAP_ENTRY_FLAG_REUSE;
384 }
385 else
386 {
387 /* Otherwise we failed */
388 hMem = NULL;
389 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
390 }
391 }
392 }
393 }
394 else if (!(uFlags & LMEM_MODIFY))
395 {
396 /* Otherwise, this is a simple RTL Managed Heap, so just call it */
397 hMem = RtlReAllocateHeap(hProcessHeap,
398 Flags | HEAP_NO_SERIALIZE,
399 hMem,
400 dwBytes);
401 if (!hMem)
402 {
403 /* Fail */
404 BASE_TRACE_FAILURE();
405 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
406 }
407 }
408
409 /* All done, unlock the heap and return the pointer */
410 RtlUnlockHeap(hProcessHeap);
411 return hMem;
412 }
413
414 /*
415 * @implemented
416 */
417 SIZE_T
418 WINAPI
419 LocalShrink(HLOCAL hMem,
420 UINT cbNewSize)
421 {
422 /* Call RTL */
423 return RtlCompactHeap(hProcessHeap, 0);
424 }
425
426 /*
427 * @implemented
428 */
429 SIZE_T
430 NTAPI
431 LocalSize(HLOCAL hMem)
432 {
433 /* This is the same as a Global Size */
434 return GlobalSize(hMem);
435 }
436
437 /*
438 * @implemented
439 */
440 BOOL
441 NTAPI
442 LocalUnlock(HLOCAL hMem)
443 {
444 /* This is the same as a Global Unlock */
445 return GlobalUnlock(hMem);
446 }
447
448 /* EOF */