Author: ion
Date: Sat Jun 24 22:11:57 2006
New Revision: 22579
URL:
http://svn.reactos.org/svn/reactos?rev=22579&view=rev
Log:
- Rewrote Base Heap implementation nearly from scratch, currently only for Global Heap
(Local Heap is as broken as before, since it still calls the Global Heap APIs). For
detailed implementation notes, see baseheap.h
- Main changes include using the RtlHandle package instead of duplicating an internal
implementation, as well as using the RtlHeap* APIs that allow for setting User
Flags/Values for associating Base Heap Flags/Handles with the actual RTL-managed block.
- Regression-tested with WINE tests and basic ROS apps.
Added:
trunk/reactos/dll/win32/kernel32/include/baseheap.h
Modified:
trunk/reactos/dll/win32/kernel32/include/kernel32.h
trunk/reactos/dll/win32/kernel32/mem/global.c
trunk/reactos/dll/win32/kernel32/misc/dllmain.c
Added: trunk/reactos/dll/win32/kernel32/include/baseheap.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/kernel32/include…
==============================================================================
--- trunk/reactos/dll/win32/kernel32/include/baseheap.h (added)
+++ trunk/reactos/dll/win32/kernel32/include/baseheap.h Sat Jun 24 22:11:57 2006
@@ -1,0 +1,121 @@
+/*
+ * PROJECT: ReactOS Win32 Base API
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: dll/win32/kernel32/include/baseheap.h
+ * PURPOSE: Base Heap Structures
+ * PROGRAMMERS: Alex Ionescu (alex.ionescu(a)reactos.org)
+ */
+
+//
+// Some important implementation notes.
+//
+// Firstly, the Global* APIs in Win32 are largely similar to the Local* APIs,
+// but there are a number of small differences (for example, there is no such
+// thing as DDE/Shared Local memory, and the re-allocation semantics are also
+// simpler, because you cannot force a move).
+//
+// Note something VERY IMPORTANT: This implementation *depends* on the fact
+// that all heap pointers are, at the very least, 8 byte aligned, and that heap
+// handles are actually pointers inside our HandleEntry->Object, which happens
+// to be at offset 0x4, which means testing with bit 3 tells us if the handle
+// is a pointer or a real "handle". On 64-bit, heap pointers should be 16-byte
+// aligned, and our offset should be 0x8, so the trick works anyways, but using
+// the 4th bit.
+//
+// Apart from MSDN, a wonderful source of information about how this works is
+// available on Raymond's blog, in a 4-parter series starting at:
+//
http://blogs.msdn.com/oldnewthing/archive/2004/11/04/252258.aspx.
+//
+// Finally, as Raymond points out, be aware that some applications depend on
+// the way this implementation was done, since global memory handles are a
+// straight-forward overlay on top of the RTL Handle implementation, and rogue
+// applications can easily do the conversion manually without calling the right
+// API for it (such as GlobalLock).
+//
+
+//
+// The Handle Table
+//
+extern RTL_HANDLE_TABLE BaseGlobalHandleTable;
+
+//
+// Tracing Support
+// Define _BASE_HANDLE_TRACE for Traces
+//
+#ifdef _BASE_HANDLE_TRACE_
+#define BH_PRINT DbgPrint
+#else
+#define BH_PRINT DPRINT
+#endif
+#define BASE_TRACE_ALLOC(x, y) \
+ BH_PRINT("[BASE_HEAP] %s : Allocating %lx bytes with flags: %lx\n", \
+ __FUNCTION__, x, y)
+#define BASE_TRACE_ALLOC2(x) \
+ BH_PRINT("[BASE_HEAP] %s : Allocated %p\n", \
+ __FUNCTION__, x)
+#define BASE_TRACE_PTR(x, y) \
+ BH_PRINT("[BASE_HEAP] %s : Using handle: %lx for pointer: %p\n", \
+ __FUNCTION__, x, y)
+#define BASE_TRACE_HANDLE(x, y) \
+ BH_PRINT("[BASE_HEAP] %s : Using handle: %lx for block: %p\n", \
+ __FUNCTION__, x, y)
+#define BASE_TRACE_DEALLOC(x) \
+ BH_PRINT("[BASE_HEAP] %s : Freeing %p\n", \
+ __FUNCTION__, x)
+
+//
+// The handle structure for global heap handles.
+// Notice that it nicely overlays with RTL_HANDLE_ENTRY.
+// KEEP IT THAT WAY! ;-)
+//
+typedef struct _GLOBAL_HEAP_HANDLE_ENTRY
+{
+ USHORT Flags;
+ USHORT LockCount;
+ union
+ {
+ PVOID Object;
+ ULONG OldSize;
+ };
+} GLOBAL_HEAP_HANDLE_ENTRY, *PGLOBAL_HEAP_HANDLE_ENTRY;
+
+//
+// Handle entry flags
+// Note that 0x0001 is the shared/generic RTL_HANDLE_VALID
+//
+#define GLOBAL_HEAP_ENTRY_FLAG_MOVABLE 0x0002
+#define GLOBAL_HEAP_ENTRY_FLAG_REUSABLE 0x0004
+#define GLOBAL_HEAP_ENTRY_FLAG_REUSE 0x0008
+#define GLOBAL_HEAP_ENTRY_FLAG_DDESHARE 0x0010
+
+//
+// Easy way to check if the global handle is actually an entry in our table
+//
+#define GLOBAL_HEAP_IS_HANDLE_ENTRY \
+ (ULONG_PTR)FIELD_OFFSET(GLOBAL_HEAP_HANDLE_ENTRY, Object)
+
+//
+// Tags for the entire heap allocation for this global memory.
+// They are set part of the User Flags of the RTL Heap.
+//
+#define GLOBAL_HEAP_FLAG_MOVABLE HEAP_SETTABLE_USER_FLAG1
+#define GLOBAL_HEAP_FLAG_DDESHARE HEAP_SETTABLE_USER_FLAG2
+
+//
+// Internal Handle Functions
+//
+#define GlobalAllocEntry() \
+ (PGLOBAL_HEAP_HANDLE_ENTRY)RtlAllocateHandle(&BaseGlobalHandleTable, NULL)
+
+#define GlobalGetEntry(h) \
+ (PGLOBAL_HEAP_HANDLE_ENTRY) \
+ CONTAINING_RECORD(h, \
+ GLOBAL_HEAP_HANDLE_ENTRY, \
+ Object);
+
+#define GlobalValidateEntry(he) \
+ RtlIsValidHandle(&BaseGlobalHandleTable, (PRTL_HANDLE_TABLE_ENTRY)he)
+
+#define GlobalFreeEntry(he) \
+ RtlFreeHandle(&BaseGlobalHandleTable, (PRTL_HANDLE_TABLE_ENTRY)he);
+
Modified: trunk/reactos/dll/win32/kernel32/include/kernel32.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/kernel32/include…
==============================================================================
--- trunk/reactos/dll/win32/kernel32/include/kernel32.h (original)
+++ trunk/reactos/dll/win32/kernel32/include/kernel32.h Sat Jun 24 22:11:57 2006
@@ -1,5 +1,7 @@
#ifndef _KERNEL32_INCLUDE_KERNEL32_H
#define _KERNEL32_INCLUDE_KERNEL32_H
+
+#include "baseheap.h"
#define BINARY_UNKNOWN (0)
#define BINARY_PE_EXE32 (1)
Modified: trunk/reactos/dll/win32/kernel32/mem/global.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/kernel32/mem/glo…
==============================================================================
--- trunk/reactos/dll/win32/kernel32/mem/global.c (original)
+++ trunk/reactos/dll/win32/kernel32/mem/global.c Sat Jun 24 22:11:57 2006
@@ -1,740 +1,931 @@
-/* $Id$
- *
- * Win32 Global/Local heap functions (GlobalXXX, LocalXXX).
- * These functions included in Win32 for compatibility with 16 bit Windows
- * Especially the moveable blocks and handles are oldish.
- * But the ability to directly allocate memory with GPTR and LPTR is widely
- * used.
- *
- * Updated to support movable memory with algorithms taken from wine.
- */
+/*
+ * PROJECT: ReactOS Win32 Base API
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: dll/win32/kernel32/mem/global.c
+ * PURPOSE: Global Memory APIs (sits on top of Heap*)
+ * PROGRAMMERS: Alex Ionescu (alex.ionescu(a)reactos.org)
+ */
+
+/* INCLUDES ******************************************************************/
#include <k32.h>
#define NDEBUG
-#include "../include/debug.h"
-
-#ifdef _GNUC_
-#define STRUCT_PACK __attribute__((packed))
-#else
-#define STRUCT_PACK
-#endif
-
-#define MAGIC_GLOBAL_USED 0x5342BEEF
-#define GLOBAL_LOCK_MAX 0xFF
-
-/*Wine found that some applications complain if memory isn't 8 byte aligned.
-* We make use of that experience here.
-*/
-#define HANDLE_SIZE 8 /*sizeof(HANDLE) *2 */
-
-
-typedef struct __GLOBAL_LOCAL_HANDLE
-{
- DWORD Magic;
- LPVOID Pointer; STRUCT_PACK
- BYTE Flags;
- BYTE LockCount;
-} GLOBAL_HANDLE, LOCAL_HANDLE, *PGLOBAL_HANDLE, *PLOCAL_HANDLE;
-
-#define HANDLE_TO_INTERN(h) ((PGLOBAL_HANDLE)(((char *)(h))-4))
-#define INTERN_TO_HANDLE(i) ((HGLOBAL) &((i)->Pointer))
-#define POINTER_TO_HANDLE(p) (*(PHANDLE)((ULONG_PTR)p - HANDLE_SIZE))
-#define ISHANDLE(h) ((((ULONG)(h)) & 0x4)!=0)
-#define ISPOINTER(h) ((((ULONG)(h)) & 0x4)==0)
-
-
-static void DbgPrintStruct(PGLOBAL_HANDLE h)
-{
- DPRINT("Magic: 0x%X\n", h->Magic);
- DPRINT("Pointer: 0x%X\n", h->Pointer);
- DPRINT("Flags: 0x%X\n", h->Flags);
- DPRINT("LockCount: 0x%X\n", h->LockCount);
-}
-
-
+#include "debug.h"
+
+#define BASE_TRACE_FAILURE() \
+ DbgPrint("[BASE_HEAP] %s : Failing %d\n", \
+ __FUNCTION__, __LINE__)
+
+/* TYPES *********************************************************************/
+
+extern SYSTEM_BASIC_INFORMATION BaseCachedSysInfo;
+RTL_HANDLE_TABLE BaseGlobalHandleTable;
/* FUNCTIONS ***************************************************************/
/*
* @implemented
*/
-HGLOBAL STDCALL
+HGLOBAL
+NTAPI
GlobalAlloc(UINT uFlags,
DWORD dwBytes)
{
-
- PGLOBAL_HANDLE phandle = 0;
- PVOID palloc = 0;
- UINT heap_flags = 0;
-
- if (uFlags & GMEM_ZEROINIT)
- {
- heap_flags = HEAP_ZERO_MEMORY;
- }
-
- DPRINT("GlobalAlloc( 0x%X, 0x%lX )\n", uFlags, dwBytes);
-
- //Changed hProcessHeap to GetProcessHeap()
- if ((uFlags & GMEM_MOVEABLE)==0) /* POINTER */
- {
- palloc = RtlAllocateHeap(GetProcessHeap(), heap_flags, dwBytes);
- if (! ISPOINTER(palloc))
- {
- DPRINT1("GlobalAlloced pointer which is not 8-byte aligned\n");
- RtlFreeHeap(GetProcessHeap(), 0, palloc);
+ ULONG Flags = 0;
+ PVOID Ptr = NULL;
+ HANDLE hMemory;
+ PGLOBAL_HEAP_HANDLE_ENTRY HandleEntry;
+ BASE_TRACE_ALLOC(dwBytes, uFlags);
+ ASSERT(hProcessHeap);
+
+ /* Make sure the flags are valid */
+ if (uFlags & ~GMEM_VALID_FLAGS)
+ {
+ /* They aren't, fail */
+ BASE_TRACE_FAILURE();
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return NULL;
+ }
+
+ /* Convert ZEROINIT */
+ if (uFlags & GMEM_ZEROINIT) Flags |= HEAP_ZERO_MEMORY;
+
+ /* Check if we're not movable, which means pointer-based heap */
+ if (!(uFlags & GMEM_MOVEABLE))
+ {
+ /* Check if this is DDESHARE (deprecated) */
+ if (uFlags & GMEM_DDESHARE) Flags |= GLOBAL_HEAP_ENTRY_FLAG_DDESHARE;
+
+ /* Allocate heap for it */
+ Ptr = RtlAllocateHeap(hProcessHeap, Flags, dwBytes);
+ BASE_TRACE_ALLOC2(Ptr);
+ return Ptr;
+ }
+
+ /* This is heap based, so lock it in first */
+ RtlLockHeap(hProcessHeap);
+
+ /*
+ * Disable locking, enable custom flags, and write the
+ * movable flag (deprecated)
+ */
+ Flags |= HEAP_NO_SERIALIZE |
+ HEAP_SETTABLE_USER_VALUE |
+ GLOBAL_HEAP_FLAG_MOVABLE;
+
+ /* Allocate the handle */
+ HandleEntry = GlobalAllocEntry();
+ if (!HandleEntry)
+ {
+ /* Fail */
+ hMemory = NULL;
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ BASE_TRACE_FAILURE();
+ goto Quickie;
+ }
+
+ /* Get the object and make sure we have size */
+ hMemory = &HandleEntry->Object;
+ if (dwBytes)
+ {
+ /* Allocate the actual memory for it */
+ Ptr = RtlAllocateHeap(hProcessHeap, Flags, dwBytes);
+ BASE_TRACE_PTR(HandleEntry, Ptr);
+ if (!Ptr)
+ {
+ /* We failed, manually set the allocate flag and free the handle */
+ HandleEntry->Flags = RTL_HANDLE_VALID;
+ GlobalFreeEntry(HandleEntry);
+
+ /* For the cleanup case */
+ HandleEntry = NULL;
+ }
+ else
+ {
+ /* All worked well, save our heap entry */
+ RtlSetUserValueHeap(hProcessHeap, HEAP_NO_SERIALIZE, Ptr, hMemory);
+ }
+ }
+
+Quickie:
+ /* Cleanup! First unlock the heap */
+ RtlUnlockHeap(hProcessHeap);
+
+ /* Check if a handle was allocated */
+ if (HandleEntry)
+ {
+ /* Set the pointer and allocated flag */
+ HandleEntry->Object = Ptr;
+ HandleEntry->Flags = RTL_HANDLE_VALID;
+ if (!Ptr)
+ {
+ /* We don't have a valid pointer, but so reuse this handle */
+ HandleEntry->Flags = GLOBAL_HEAP_ENTRY_FLAG_REUSE;
+ }
+
+ /* Check if the handle is discardable */
+ if (uFlags & GMEM_DISCARDABLE)
+ {
+ /* Save it in the handle entry */
+ HandleEntry->Flags |= GLOBAL_HEAP_ENTRY_FLAG_REUSABLE;
+ }
+
+ /* Check if the handle is moveable */
+ if (uFlags & GMEM_MOVEABLE)
+ {
+ /* Save it in the handle entry */
+ HandleEntry->Flags |= GLOBAL_HEAP_ENTRY_FLAG_MOVABLE;
+ }
+
+ /* Check if the handle is DDE Shared */
+ if (uFlags & GMEM_DDESHARE)
+ {
+ /* Save it in the handle entry */
+ HandleEntry->Flags |= GLOBAL_HEAP_ENTRY_FLAG_DDESHARE;
+ }
+
+ /* Set the pointer */
+ Ptr = hMemory;
+ }
+
+ /* Return the pointer */
+ return Ptr;
+}
+
+/*
+ * @implemented
+ */
+SIZE_T
+NTAPI
+GlobalCompact(DWORD dwMinFree)
+{
+ /* Call the RTL Heap Manager */
+ return RtlCompactHeap(hProcessHeap, 0);
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+GlobalFix(HGLOBAL hMem)
+{
+ /* Lock the memory if it the handle is valid */
+ if (INVALID_HANDLE_VALUE != hMem) GlobalLock(hMem);
+}
+
+/*
+ * @implemented
+ */
+UINT
+NTAPI
+GlobalFlags(HGLOBAL hMem)
+{
+ PGLOBAL_HEAP_HANDLE_ENTRY HandleEntry;
+ HANDLE Handle = NULL;
+ ULONG Flags = 0;
+ UINT uFlags = GMEM_INVALID_HANDLE;
+
+ /* Start by locking the heap */
+ RtlLockHeap(hProcessHeap);
+
+ /* Check if this is a simple RTL Heap Managed block */
+ if (!((ULONG_PTR)hMem & GLOBAL_HEAP_IS_HANDLE_ENTRY))
+ {
+ /* Then we'll query RTL Heap */
+ RtlGetUserInfoHeap(hProcessHeap, Flags, hMem, &Handle, &Flags);
+ BASE_TRACE_PTR(Handle, hMem);
+
+ /*
+ * Check if RTL Heap didn't find a handle associated with us or
+ * said that this heap isn't movable, which means something we're
+ * really not a handle-based heap.
+ */
+ if (!(Handle) || !(Flags & GLOBAL_HEAP_FLAG_MOVABLE))
+ {
+ /* Then set the flags to 0 */
+ uFlags = 0;
+ }
+ else
+ {
+ /* Otherwise we're handle-based, so get the internal handle */
+ hMem = Handle;
+ }
+ }
+
+ /* Check if the handle is actually an entry in our table */
+ if ((ULONG_PTR)hMem & GLOBAL_HEAP_IS_HANDLE_ENTRY)
+ {
+ /* Then get the entry */
+ HandleEntry = GlobalGetEntry(hMem);
+ BASE_TRACE_HANDLE(HandleEntry, hMem);
+
+ /* Make sure it's a valid handle */
+ if (GlobalValidateEntry(HandleEntry))
+ {
+ /* Get the lock count first */
+ uFlags = HandleEntry->LockCount & GMEM_LOCKCOUNT;
+
+ /* Now check if it's discarded */
+ if (HandleEntry->Flags & GLOBAL_HEAP_ENTRY_FLAG_REUSABLE)
+ {
+ /* Set the Win32 Flag */
+ uFlags |= GMEM_DISCARDED;
+ }
+
+ /* Check if it's movable */
+ if (HandleEntry->Flags & GLOBAL_HEAP_ENTRY_FLAG_MOVABLE)
+ {
+ /* Set the Win32 Flag */
+ uFlags |= GMEM_MOVEABLE;
+ }
+
+ /* Check if it's DDE Shared */
+ if (HandleEntry->Flags & GLOBAL_HEAP_ENTRY_FLAG_DDESHARE)
+ {
+ /* Set the Win32 Flag */
+ uFlags |= GMEM_DDESHARE;
+ }
+ }
+ }
+
+ /* Check if by now, we still haven't gotten any useful flags */
+ if (uFlags == GMEM_INVALID_HANDLE) SetLastError(ERROR_INVALID_HANDLE);
+
+ /* All done! Unlock heap and return Win32 Flags */
+ RtlUnlockHeap(hProcessHeap);
+ return uFlags;
+}
+
+/*
+ * @implemented
+ */
+HGLOBAL
+NTAPI
+GlobalFree(HGLOBAL hMem)
+{
+ PGLOBAL_HEAP_HANDLE_ENTRY HandleEntry;
+ LPVOID Ptr;
+ BASE_TRACE_DEALLOC(hMem);
+
+ /* Check if this was a simple allocated heap entry */
+ if (!((ULONG_PTR)hMem & GLOBAL_HEAP_IS_HANDLE_ENTRY))
+ {
+ /* Free it with the RTL Heap Manager */
+ if (RtlFreeHeap(hProcessHeap, 0, hMem))
+ {
+ /* Return NULL since there's no handle */
return NULL;
}
- return (HGLOBAL) palloc;
- }
- else /* HANDLE */
- {
- HeapLock(hProcessHeap);
-
- phandle = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(GLOBAL_HANDLE));
- if (phandle)
- {
- phandle->Magic = MAGIC_GLOBAL_USED;
- phandle->Flags = uFlags >> 8;
- phandle->LockCount = 0;
- phandle->Pointer = 0;
-
- if (dwBytes)
+ else
+ {
+ /* Otherwise fail */
+ BASE_TRACE_FAILURE();
+ SetLastError(ERROR_INVALID_HANDLE);
+ return hMem;
+ }
+ }
+
+ /* It's a handle probably, so lock the heap */
+ RtlLockHeap(hProcessHeap);
+
+ /* Make sure that this is an entry in our handle database */
+ if ((ULONG_PTR)hMem & GLOBAL_HEAP_IS_HANDLE_ENTRY)
+ {
+ /* Get the entry */
+ HandleEntry = GlobalGetEntry(hMem);
+ BASE_TRACE_HANDLE(HandleEntry, hMem);
+
+ /* Make sure the handle is valid */
+ if (!GlobalValidateEntry(HandleEntry))
+ {
+ /* It's not, fail */
+ SetLastError(ERROR_INVALID_HANDLE);
+ Ptr = NULL;
+ }
+ else
+ {
+ /* It's valid, so get the pointer */
+ Ptr = HandleEntry->Object;
+
+ /* Free this handle */
+ GlobalFreeEntry(HandleEntry);
+
+ /* If the pointer is 0, then we don't have a handle either */
+ if (!Ptr) hMem = NULL;
+ }
+ }
+ else
+ {
+ /* Otherwise, reuse the handle as a pointer */
+ BASE_TRACE_FAILURE();
+ Ptr = hMem;
+ }
+
+ /* Check if we got here with a valid heap pointer */
+ if (Ptr)
+ {
+ /* Free it */
+ RtlFreeHeap(hProcessHeap, HEAP_NO_SERIALIZE, Ptr);
+ hMem = NULL;
+ }
+
+ /* We're done, so unlock the heap and return the handle */
+ RtlUnlockHeap(hProcessHeap);
+ return hMem;
+}
+
+/*
+ * @implemented
+ */
+HGLOBAL
+NTAPI
+GlobalHandle(LPCVOID pMem)
+{
+ HANDLE Handle = NULL;
+ ULONG Flags;
+
+ /* Lock the heap */
+ RtlLockHeap(hProcessHeap);
+
+ /* Query RTL Heap */
+ RtlGetUserInfoHeap(hProcessHeap,
+ HEAP_NO_SERIALIZE,
+ (PVOID)pMem,
+ &Handle,
+ &Flags);
+ BASE_TRACE_PTR(Handle, pMem);
+
+ /*
+ * Check if RTL Heap didn't find a handle for us or said that
+ * this heap isn't movable.
+ */
+ if (!(Handle) || !(Flags & GLOBAL_HEAP_FLAG_MOVABLE))
+ {
+ /* We're actually handle-based, so the pointer is a handle */
+ Handle = (HANDLE)pMem;
+ }
+
+ /* All done, unlock the heap and return the handle */
+ RtlUnlockHeap(hProcessHeap);
+ return Handle;
+}
+
+/*
+ * @implemented
+ */
+LPVOID
+NTAPI
+GlobalLock(HGLOBAL hMem)
+{
+ PGLOBAL_HEAP_HANDLE_ENTRY HandleEntry;
+ LPVOID Ptr;
+
+ /* Check if this was a simple allocated heap entry */
+ if (!((ULONG_PTR)hMem & GLOBAL_HEAP_IS_HANDLE_ENTRY))
+ {
+ /* Then simply return the pointer */
+ return hMem;
+ }
+
+ /* Otherwise, lock the heap */
+ RtlLockHeap(hProcessHeap);
+
+ /* Get the handle entry */
+ HandleEntry = GlobalGetEntry(hMem);
+ BASE_TRACE_HANDLE(HandleEntry, hMem);
+
+ /* Make sure it's valid */
+ if (!GlobalValidateEntry(HandleEntry))
+ {
+ /* It's not, fail */
+ BASE_TRACE_FAILURE();
+ SetLastError(ERROR_INVALID_HANDLE);
+ Ptr = NULL;
+ }
+ else
+ {
+ /* Otherwise, get the pointer */
+ Ptr = HandleEntry->Object;
+ if (Ptr)
+ {
+ /* Increase the lock count, unless we've went too far */
+ if (HandleEntry->LockCount++ == GMEM_LOCKCOUNT)
{
- palloc = RtlAllocateHeap(GetProcessHeap(), heap_flags, dwBytes +
HANDLE_SIZE);
- if (palloc)
+ /* In which case we simply unlock once */
+ HandleEntry->LockCount--;
+ }
+ }
+ else
+ {
+ /* The handle is still there but the memory was already freed */
+ SetLastError(ERROR_DISCARDED);
+ }
+ }
+
+ /* All done. Unlock the heap and return the pointer */
+ RtlUnlockHeap(hProcessHeap);
+ return Ptr;
+}
+
+HGLOBAL
+NTAPI
+GlobalReAlloc(HGLOBAL hMem,
+ DWORD dwBytes,
+ UINT uFlags)
+{
+ PGLOBAL_HEAP_HANDLE_ENTRY HandleEntry;
+ HANDLE Handle;
+ LPVOID Ptr;
+ ULONG Flags = 0;
+
+ /* Convert ZEROINIT */
+ if (uFlags & GMEM_ZEROINIT) Flags |= HEAP_ZERO_MEMORY;
+
+ /* If this wasn't a movable heap, then we MUST re-alloc in place */
+ if (!(uFlags & GMEM_MOVEABLE)) Flags |= HEAP_REALLOC_IN_PLACE_ONLY;
+
+ /* Lock the heap and disable built-in locking in the RTL Heap funcitons */
+ RtlLockHeap(hProcessHeap);
+ Flags |= HEAP_NO_SERIALIZE;
+ DPRINT1("hmem: %p Flags: %lx\n", hMem, uFlags);
+
+ /* Check if this is a simple handle-based block */
+ if (((ULONG_PTR)hMem & GLOBAL_HEAP_IS_HANDLE_ENTRY))
+ {
+ /* Get the entry */
+ HandleEntry = GlobalGetEntry(hMem);
+ BASE_TRACE_HANDLE(HandleEntry, hMem);
+
+ /* Make sure the handle is valid */
+ if (!GlobalValidateEntry(HandleEntry))
+ {
+ /* Fail */
+ BASE_TRACE_FAILURE();
+ SetLastError(ERROR_INVALID_HANDLE);
+ hMem = NULL;
+ }
+ else if (uFlags & GMEM_MODIFY)
+ {
+ /* User is changing flags... check if the memory was discardable */
+ if (uFlags & GMEM_DISCARDABLE)
+ {
+ /* Then set the flag */
+ HandleEntry->Flags |= GLOBAL_HEAP_ENTRY_FLAG_REUSABLE;
+ }
+ else
+ {
+ /* Otherwise, remove the flag */
+ HandleEntry->Flags &= GLOBAL_HEAP_ENTRY_FLAG_REUSABLE;
+ }
+ }
+ else
+ {
+ /* Otherwise, get the object and check if we have no size */
+ Ptr = HandleEntry->Object;
+ if (!dwBytes)
+ {
+ /* Clear the handle and check for a pointer */
+ hMem = NULL;
+ if (Ptr)
{
- *(PHANDLE)palloc = INTERN_TO_HANDLE(phandle);
- phandle->Pointer = (PVOID)((ULONG_PTR)palloc + HANDLE_SIZE);
+ /* Make sure the handle isn't locked */
+ if ((uFlags & GMEM_MOVEABLE) & !(HandleEntry->LockCount))
+ {
+ /* Free the current heap */
+ RtlFreeHeap(hProcessHeap, Flags, Ptr);
+
+ /* Free the handle */
+ HandleEntry->Object = NULL;
+ HandleEntry->Flags |= GLOBAL_HEAP_ENTRY_FLAG_REUSE;
+
+ /* Get the object pointer */
+ hMem = &HandleEntry->Object;
+ }
}
- else /*failed to allocate the memory block*/
+ else
{
- RtlFreeHeap(GetProcessHeap(), 0, phandle);
- phandle = 0;
+ /* Otherwise just return the object pointer */
+ hMem = &HandleEntry->Object;
}
}
else
{
- DPRINT("Allocated a 0 size movable block.\n");
- DbgPrintStruct(phandle);
- DPRINT("Address of the struct: 0x%X\n", phandle);
- DPRINT("Address of pointer: 0x%X\n",
&(phandle->Pointer));
- }
- }
- HeapUnlock(hProcessHeap);
-
- if (phandle)
- {
- if (ISPOINTER(INTERN_TO_HANDLE(phandle)))
- {
- DPRINT1("GlobalAlloced handle which is 8-byte aligned but
shouldn't be\n");
- RtlFreeHeap(GetProcessHeap(), 0, palloc);
- RtlFreeHeap(GetProcessHeap(), 0, phandle);
- return NULL;
- }
- return INTERN_TO_HANDLE(phandle);
- }
- else
- return (HGLOBAL)0;
- }
-}
-
-
-/*
- * @implemented
- */
-SIZE_T STDCALL
-GlobalCompact(DWORD dwMinFree)
-{
- return RtlCompactHeap(hProcessHeap, 0);
-}
-
-
-/*
- * @implemented
- */
-VOID STDCALL
-GlobalFix(HGLOBAL hMem)
-{
- if (INVALID_HANDLE_VALUE != hMem)
- GlobalLock(hMem);
-}
-
-/*
- * @implemented
- */
-UINT STDCALL
-GlobalFlags(HGLOBAL hMem)
-{
- DWORD retval;
- PGLOBAL_HANDLE phandle;
-
- DPRINT("GlobalFlags( 0x%lX )\n", (ULONG)hMem);
-
- if(!ISHANDLE(hMem))
- {
- DPRINT("GlobalFlags: Fixed memory.\n");
- retval = 0;
- }
- else
- {
- HeapLock(GetProcessHeap());
-
- phandle = HANDLE_TO_INTERN(hMem);
-
- /*DbgPrintStruct(phandle);*/
-
- if (MAGIC_GLOBAL_USED == phandle->Magic)
- {
- /*DbgPrint("GlobalFlags: Magic number ok\n");
- **DbgPrint("GlobalFlags: pointer is 0x%X\n", phandle->Pointer);
- */
- retval = phandle->LockCount + (phandle->Flags << 8);
- if (0 == phandle->Pointer)
- {
- retval = retval | GMEM_DISCARDED;
- }
- }
- else
- {
- DPRINT1("GlobalSize: invalid handle\n");
- retval = 0;
- }
- HeapUnlock(GetProcessHeap());
- }
- return retval;
-}
-
-
-/*
- * @implemented
- */
-HGLOBAL STDCALL
-GlobalFree(HGLOBAL hMem)
-{
- PGLOBAL_HANDLE phandle;
- HGLOBAL hreturned;
-
- DPRINT("GlobalFree( 0x%lX )\n", (ULONG)hMem);
-
- hreturned = 0;
- if (ISPOINTER(hMem)) /* POINTER */
- {
- if(!RtlFreeHeap(GetProcessHeap(), 0, (PVOID)hMem))
- hMem = 0;
- }
- else /* HANDLE */
- {
- HeapLock(GetProcessHeap());
-
- phandle = HANDLE_TO_INTERN(hMem);
-
- if(MAGIC_GLOBAL_USED == phandle->Magic)
- {
- /* WIN98 does not make this test. That is you can free a */
- /* block you have not unlocked. Go figure!! */
- if(phandle->LockCount!=0)
- {
- DPRINT1("Warning! GlobalFree(0x%X) Freeing a handle to a locked
object.\n", hMem);
- SetLastError(ERROR_INVALID_HANDLE);
- }
-
- if(phandle->Pointer)
- if (!RtlFreeHeap(GetProcessHeap(), 0,
(PVOID)((ULONG_PTR)phandle->Pointer - HANDLE_SIZE)))
- hreturned = hMem;
-
- if (!RtlFreeHeap(GetProcessHeap(), 0, phandle))
- hreturned = hMem;
- }
- HeapUnlock(GetProcessHeap());
-
- hMem = 0;
- }
- return hreturned;
-}
-
-
-/*
- * @implemented
- */
-HGLOBAL STDCALL
-GlobalHandle(LPCVOID pMem)
-{
- HGLOBAL handle = 0;
- PGLOBAL_HANDLE test = 0;
- LPCVOID pointer_test = 0;
-
- DPRINT("GlobalHandle( 0x%lX )\n", (ULONG)pMem);
- if (0 == pMem) /*Invalid argument */
- {
- SetLastError(ERROR_INVALID_PARAMETER);
- DPRINT1("Error: 0 handle.\n");
- return 0;
- }
-
- HeapLock(GetProcessHeap());
- /* Now test to see if this pointer is associated with a handle.
- * This is done by calling RtlValidateHeap() and seeing if it fails.
- */
- if (RtlValidateHeap(GetProcessHeap(), 0, (char *)pMem)) /*FIXED*/
- {
- handle = (HGLOBAL)pMem;
- return handle;
- }
- else /*MOVABLE*/
- {
- handle = POINTER_TO_HANDLE(pMem);
- }
-
-
- /* Test to see if this memory is valid*/
- test = HANDLE_TO_INTERN(handle);
- if (!IsBadReadPtr(test, sizeof(GLOBAL_HANDLE)))
- {
- if (MAGIC_GLOBAL_USED == test->Magic)
- {
- pointer_test = test->Pointer;
- if (!RtlValidateHeap(GetProcessHeap(), 0, ((char *)pointer_test) -
HANDLE_SIZE) ||
- !RtlValidateHeap(GetProcessHeap(), 0, test))
- {
- SetLastError(ERROR_INVALID_HANDLE);
- handle = 0;
- }
- }
- }
- else
- {
- DPRINT1("GlobalHandle: Bad read pointer.\n");
- SetLastError(ERROR_INVALID_HANDLE);
- handle = 0;
- }
-
- HeapUnlock(GetProcessHeap());
-
- return handle;
-}
-
-
-/*
- * @implemented
- */
-LPVOID STDCALL
-GlobalLock(HGLOBAL hMem)
-{
- PGLOBAL_HANDLE phandle;
- LPVOID palloc;
-
- DPRINT("GlobalLock( 0x%lX )\n", (ULONG)hMem);
-
- if (ISPOINTER(hMem))
- return (LPVOID) hMem;
-
- HeapLock(GetProcessHeap());
-
- phandle = HANDLE_TO_INTERN(hMem);
-
- if(MAGIC_GLOBAL_USED == phandle->Magic)
- {
- if(GLOBAL_LOCK_MAX > phandle->LockCount)
- {
- phandle->LockCount++;
- }
- palloc = phandle->Pointer;
- }
- else
- {
- DPRINT("GlobalLock: invalid handle\n");
- palloc = (LPVOID) hMem;
- }
-
- HeapUnlock(GetProcessHeap());
-
- return palloc;
-}
-
-/*
- * @implemented
- */
-BOOL
-STDCALL
-GlobalMemoryStatusEx(LPMEMORYSTATUSEX lpBuffer)
-{
- SYSTEM_BASIC_INFORMATION SysBasicInfo;
- SYSTEM_PERFORMANCE_INFORMATION SysPerfInfo;
- ULONG UserMemory;
- NTSTATUS Status;
-
- DPRINT("GlobalMemoryStatusEx\n");
-
- if (lpBuffer->dwLength != sizeof(MEMORYSTATUSEX))
- {
- SetLastError(ERROR_INVALID_PARAMETER);
- return FALSE;
- }
-
- Status = ZwQuerySystemInformation(SystemBasicInformation,
- &SysBasicInfo,
- sizeof(SysBasicInfo),
- NULL);
- if (!NT_SUCCESS(Status))
- {
- SetLastErrorByStatus(Status);
- return FALSE;
- }
-
- Status = ZwQuerySystemInformation(SystemPerformanceInformation,
- &SysPerfInfo,
- sizeof(SysPerfInfo),
- NULL);
- if (!NT_SUCCESS(Status))
- {
- SetLastErrorByStatus(Status);
- return FALSE;
- }
-
- Status = ZwQuerySystemInformation(SystemFullMemoryInformation,
- &UserMemory,
- sizeof(ULONG),
- NULL);
- if (!NT_SUCCESS(Status))
- {
- SetLastErrorByStatus(Status);
- return FALSE;
- }
-
-/*
- * Load percentage 0 thru 100. 0 is good and 100 is bad.
- *
- * Um = allocated memory / physical memory
- * Um = 177 MB / 256 MB = 69.1%
- *
- * Mult allocated memory by 100 to move decimal point up.
- */
- lpBuffer->dwMemoryLoad = (SysBasicInfo.NumberOfPhysicalPages -
- SysPerfInfo.AvailablePages) * 100 /
- SysBasicInfo.NumberOfPhysicalPages;
-
- DPRINT1("Memory Load: %d%%\n",lpBuffer->dwMemoryLoad );
-
- lpBuffer->ullTotalPhys = SysBasicInfo.NumberOfPhysicalPages *
- SysBasicInfo.PageSize;
- lpBuffer->ullAvailPhys = SysPerfInfo.AvailablePages *
- SysBasicInfo.PageSize;
-
- DPRINT("%d\n",SysPerfInfo.AvailablePages );
- DPRINT("%d\n",lpBuffer->ullAvailPhys );
-
- lpBuffer->ullTotalPageFile = SysPerfInfo.CommitLimit *
- SysBasicInfo.PageSize;
-
- DPRINT("%d\n",lpBuffer->ullTotalPageFile );
-
- lpBuffer->ullAvailPageFile = ((SysPerfInfo.CommitLimit -
- SysPerfInfo.CommittedPages) *
- SysBasicInfo.PageSize);
-
-/* VM available to the calling processes, User Mem? */
- lpBuffer->ullTotalVirtual = SysBasicInfo.MaximumUserModeAddress -
- SysBasicInfo.MinimumUserModeAddress;
-
- lpBuffer->ullAvailVirtual = (lpBuffer->ullTotalVirtual -
- (UserMemory *
- SysBasicInfo.PageSize));
-
- DPRINT("%d\n",lpBuffer->ullAvailVirtual );
- DPRINT("%d\n",UserMemory);
- DPRINT("%d\n",SysBasicInfo.PageSize);
-
-/* lol! Memory from beyond! */
- lpBuffer->ullAvailExtendedVirtual = 0;
- return TRUE;
-}
-
-/*
- * @implemented
- */
-VOID STDCALL
-GlobalMemoryStatus(LPMEMORYSTATUS lpBuffer)
-{
- MEMORYSTATUSEX lpBufferEx;
-#if 0
- if (lpBuffer->dwLength != sizeof(MEMORYSTATUS))
- {
- SetLastError(ERROR_INVALID_PARAMETER);
- return;
- }
-#endif
- lpBufferEx.dwLength = sizeof(MEMORYSTATUSEX);
-
- if (GlobalMemoryStatusEx(&lpBufferEx))
- {
-
- lpBuffer->dwLength = sizeof(MEMORYSTATUS);
-
- lpBuffer->dwMemoryLoad = lpBufferEx.dwMemoryLoad;
- lpBuffer->dwTotalPhys = lpBufferEx.ullTotalPhys;
- lpBuffer->dwAvailPhys = lpBufferEx.ullAvailPhys;
- lpBuffer->dwTotalPageFile = lpBufferEx.ullTotalPageFile;
- lpBuffer->dwAvailPageFile = lpBufferEx.ullAvailPageFile;
- lpBuffer->dwTotalVirtual = lpBufferEx.ullTotalVirtual;
- lpBuffer->dwAvailVirtual = lpBufferEx.ullAvailVirtual;
- }
-}
-
-
-HGLOBAL STDCALL
-GlobalReAlloc(HGLOBAL hMem,
- DWORD dwBytes,
- UINT uFlags)
-{
-
- LPVOID palloc = 0;
- HGLOBAL hnew = 0;
- PGLOBAL_HANDLE phandle = 0;
- ULONG heap_flags = 0;
-
- DPRINT("GlobalReAlloc( 0x%lX, 0x%lX, 0x%X )\n", (ULONG)hMem, dwBytes,
uFlags);
-
- if (uFlags & GMEM_ZEROINIT)
- {
- heap_flags = HEAP_ZERO_MEMORY;
- }
-
- HeapLock(GetProcessHeap());
-
- if(uFlags & GMEM_MODIFY) /* modify flags */
- {
- if( ISPOINTER(hMem) && (uFlags & GMEM_MOVEABLE))
- {
- /* make a fixed block moveable
- * actually only NT is able to do this. And it's soo simple
- */
- if (0 == hMem)
- {
- SetLastError( ERROR_NOACCESS );
- hnew = 0;
- }
- else
- {
- dwBytes = RtlSizeHeap(GetProcessHeap(), 0, (LPVOID) hMem);
- hnew = GlobalAlloc( uFlags, dwBytes);
- palloc = GlobalLock(hnew);
- memcpy(palloc, (LPVOID) hMem, dwBytes);
- GlobalUnlock(hnew);
- RtlFreeHeap(GetProcessHeap(),0,hMem);
- }
- }
- else if(ISPOINTER(hMem) && (uFlags & GMEM_DISCARDABLE))
- {
- /* change the flags to make our block "discardable" */
- phandle = HANDLE_TO_INTERN(hMem);
- phandle->Flags = phandle->Flags | (GMEM_DISCARDABLE >> 8);
- hnew = hMem;
- }
- else
- {
- SetLastError(ERROR_INVALID_PARAMETER);
- hnew = 0;
- }
- }
- else
- {
- if(ISPOINTER(hMem))
- {
- if (!(uFlags & GMEM_MOVEABLE))
- {
- heap_flags |= HEAP_REALLOC_IN_PLACE_ONLY;
- }
-
- /* reallocate fixed memory */
- hnew = (HANDLE)RtlReAllocateHeap(GetProcessHeap(), heap_flags, (LPVOID) hMem,
dwBytes);
- }
- else
- {
- /* reallocate a moveable block */
- phandle= HANDLE_TO_INTERN(hMem);
- hnew = hMem;
-
- if (0 != dwBytes)
- {
- if(phandle->Pointer)
- {
-
- if (phandle->LockCount && !(uFlags & GMEM_MOVEABLE))
- {
- /* Locked memory cant normally move but the MEM_MOVEABLE flag
- * override this behaviour. But in this case that flag was not
passed.
- */
- heap_flags |= HEAP_REALLOC_IN_PLACE_ONLY;
- }
-
- palloc = RtlReAllocateHeap(GetProcessHeap(), heap_flags,
- (PVOID)((ULONG_PTR)phandle->Pointer -
HANDLE_SIZE),
- dwBytes + HANDLE_SIZE);
- if (0 == palloc)
- {
- hnew = 0;
- }
- else
- {
- *(PHANDLE)palloc = hMem;
- phandle->Pointer = (PVOID)((ULONG_PTR)palloc + HANDLE_SIZE);
- }
- }
- else
- {
- palloc = RtlAllocateHeap(GetProcessHeap(), heap_flags, dwBytes +
HANDLE_SIZE);
- if (0 == palloc)
- {
- hnew = 0;
- }
- else
- {
- *(PHANDLE)palloc = hMem;
- phandle->Pointer = (PVOID)((ULONG_PTR)palloc + HANDLE_SIZE);
- }
- }
- }
- else
- {
- if(phandle->Pointer)
+ /* Otherwise, we're allocating, so set the new flags needed */
+ Flags |= HEAP_SETTABLE_USER_VALUE | GLOBAL_HEAP_FLAG_MOVABLE;
+ if (!Ptr)
{
- RtlFreeHeap(GetProcessHeap(), 0,
(PVOID)((ULONG_PTR)phandle->Pointer - HANDLE_SIZE));
- phandle->Pointer = 0;
+ /* We don't have a base, so allocate one */
+ Ptr = RtlAllocateHeap(hProcessHeap, Flags, dwBytes);
+ BASE_TRACE_ALLOC2(Ptr);
+ if (Ptr)
+ {
+ /* Allocation succeeded, so save our entry */
+ RtlSetUserValueHeap(hProcessHeap,
+ HEAP_NO_SERIALIZE,
+ Ptr,
+ hMem);
+ }
+ }
+ else
+ {
+ /*
+ * If it's not movable or currently locked, we MUST allocate
+ * in-place!
+ */
+ if (!(uFlags & GMEM_MOVEABLE) &&
(HandleEntry->LockCount))
+ {
+ /* Set the flag */
+ Flags |= HEAP_REALLOC_IN_PLACE_ONLY;
+ }
+ else
+ {
+ /* Otherwise clear the flag if we set it previously */
+ Flags &= ~HEAP_REALLOC_IN_PLACE_ONLY;
+ }
+
+ /* And do the re-allocation */
+ Ptr = RtlReAllocateHeap(hProcessHeap, Flags, Ptr, dwBytes);
+ }
+
+ /* Make sure we have a pointer by now */
+ if (Ptr)
+ {
+ /* Write it in the handle entry and mark it in use */
+ HandleEntry->Object = Ptr;
+ HandleEntry->Flags &= ~GLOBAL_HEAP_ENTRY_FLAG_REUSE;
+ }
+ else
+ {
+ /* Otherwise we failed */
+ hMem = NULL;
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
}
}
}
}
-
- HeapUnlock(GetProcessHeap());
-
- return hnew;
-}
-
-
-DWORD STDCALL
-GlobalSize(HGLOBAL hMem)
-{
- SIZE_T retval = 0;
- PGLOBAL_HANDLE phandle = 0;
-
- DPRINT("GlobalSize( 0x%lX )\n", (ULONG)hMem);
-
- if(ISPOINTER(hMem)) /*FIXED*/
- {
- retval = RtlSizeHeap(GetProcessHeap(), 0, hMem);
- }
- else /*MOVEABLE*/
- {
- HeapLock(GetProcessHeap());
-
- phandle = HANDLE_TO_INTERN(hMem);
-
- if (MAGIC_GLOBAL_USED == phandle->Magic)
- {
- if (0 != phandle->Pointer)/*NOT DISCARDED*/
+ else if (uFlags & GMEM_MODIFY)
+ {
+ /* This is not a handle-based heap and the caller wants it to be one */
+ if (uFlags & GMEM_MOVEABLE)
+ {
+ /* Get information on its current state */
+ Handle = hMem;
+ DPRINT1("h h %lx %lx\n", Handle, hMem);
+ RtlGetUserInfoHeap(hProcessHeap,
+ HEAP_NO_SERIALIZE,
+ hMem,
+ &Handle,
+ &Flags);
+ DPRINT1("h h %lx %lx\n", Handle, hMem);
+
+ /*
+ * Check if the handle matches the pointer or if the moveable flag
+ * isn't there, which is what we expect since it currenly isn't.
+ */
+ if (Handle == hMem || !(Flags & GLOBAL_HEAP_FLAG_MOVABLE))
{
- retval = RtlSizeHeap(GetProcessHeap(), 0,
(PVOID)((ULONG_PTR)phandle->Pointer - HANDLE_SIZE));
-
- if (retval == (SIZE_T)-1) /*RtlSizeHeap failed*/
+ /* Allocate a handle for it */
+ HandleEntry = GlobalAllocEntry();
+
+ /* Calculate the size of the current heap */
+ dwBytes = RtlSizeHeap(hProcessHeap, HEAP_NO_SERIALIZE, hMem);
+
+ /* Set the movable flag */
+ Flags |= HEAP_SETTABLE_USER_VALUE | GLOBAL_HEAP_FLAG_MOVABLE;
+
+ /* Now allocate the actual heap for it */
+ HandleEntry->Object = RtlAllocateHeap(hProcessHeap,
+ Flags,
+ dwBytes);
+ BASE_TRACE_PTR(HandleEntry->Object, HandleEntry);
+ if (!HandleEntry->Object)
{
/*
- **TODO: RtlSizeHeap does not set last error.
- ** We should choose an error value to set as
- ** the last error. Which One?
- */
- DPRINT("GlobalSize: RtlSizeHeap failed.\n");
- retval = 0;
+ * We failed, manually set the allocate flag and
+ * free the handle
+ */
+ HandleEntry->Flags = RTL_HANDLE_VALID;
+ GlobalFreeEntry(HandleEntry);
+
+ /* For the cleanup case */
+ BASE_TRACE_FAILURE();
+ HandleEntry = NULL;
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
}
- else /*Everything is ok*/
+ else
{
- retval = retval - HANDLE_SIZE;
+ /* Otherwise, copy the current heap and free the old one */
+ RtlMoveMemory(HandleEntry->Object, hMem, dwBytes);
+ RtlFreeHeap(hProcessHeap, HEAP_NO_SERIALIZE, hMem);
+
+ /* Select the heap pointer */
+ hMem = (HANDLE)&HandleEntry->Object;
+
+ /* Initialize the count and default flags */
+ HandleEntry->LockCount = 0;
+ HandleEntry->Flags = RTL_HANDLE_VALID |
+ GLOBAL_HEAP_ENTRY_FLAG_MOVABLE;
+
+ /* Check if it's also discardable */
+ if (uFlags & GMEM_DISCARDABLE)
+ {
+ /* Set the internal flag */
+ HandleEntry->Flags |= GLOBAL_HEAP_ENTRY_FLAG_REUSABLE;
+ }
+
+ /* Check if it's also DDE Shared */
+ if (uFlags & GMEM_DDESHARE)
+ {
+ /* Set the internal flag */
+ HandleEntry->Flags |= GLOBAL_HEAP_ENTRY_FLAG_DDESHARE;
+ }
+
+ /* Allocation succeeded, so save our entry */
+ RtlSetUserValueHeap(hProcessHeap,
+ HEAP_NO_SERIALIZE,
+ HandleEntry->Object,
+ hMem);
}
}
}
+ }
+ else
+ {
+ /* Otherwise, this is a simple RTL Managed Heap, so just call it */
+ hMem = RtlReAllocateHeap(hProcessHeap,
+ Flags | HEAP_NO_SERIALIZE,
+ hMem,
+ dwBytes);
+ if (!hMem)
+ {
+ /* Fail */
+ BASE_TRACE_FAILURE();
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ }
+
+ /* All done, unlock the heap and return the pointer */
+ RtlUnlockHeap(hProcessHeap);
+ return hMem;
+}
+
+/*
+ * @implemented
+ */
+DWORD
+NTAPI
+GlobalSize(HGLOBAL hMem)
+{
+ PGLOBAL_HEAP_HANDLE_ENTRY HandleEntry;
+ PVOID Handle = NULL;
+ ULONG Flags = 0;
+ SIZE_T dwSize = MAXULONG_PTR;
+
+ /* Lock the heap */
+ RtlLockHeap(hProcessHeap);
+
+ /* Check if this is a simple RTL Heap Managed block */
+ if (!((ULONG_PTR)hMem & GLOBAL_HEAP_IS_HANDLE_ENTRY))
+ {
+ /* Then we'll query RTL Heap */
+ RtlGetUserInfoHeap(hProcessHeap, Flags, hMem, &Handle, &Flags);
+ BASE_TRACE_PTR(Handle, hMem);
+
+ /*
+ * Check if RTL Heap didn't give us a handle or said that this heap
+ * isn't movable.
+ */
+ if (!(Handle) || !(Flags & GLOBAL_HEAP_FLAG_MOVABLE))
+ {
+ /* This implies we're not a handle heap, so use the generic call */
+ dwSize = RtlSizeHeap(hProcessHeap, HEAP_NO_SERIALIZE, hMem);
+ }
else
{
- DPRINT("GlobalSize: invalid handle\n");
- }
- HeapUnlock(GetProcessHeap());
- }
- return retval;
-}
-
-
-/*
- * @implemented
- */
-VOID STDCALL
+ /* Otherwise we're a handle heap, so get the internal handle */
+ hMem = Handle;
+ }
+ }
+
+ /* Make sure that this is an entry in our handle database */
+ if ((ULONG_PTR)hMem & GLOBAL_HEAP_IS_HANDLE_ENTRY)
+ {
+ /* Get the entry */
+ HandleEntry = GlobalGetEntry(hMem);
+ BASE_TRACE_HANDLE(HandleEntry, hMem);
+
+ /* Make sure the handle is valid */
+ if (!GlobalValidateEntry(HandleEntry))
+ {
+ /* Fail */
+ BASE_TRACE_FAILURE();
+ SetLastError(ERROR_INVALID_HANDLE);
+ }
+ else if (HandleEntry->Flags & GLOBAL_HEAP_ENTRY_FLAG_REUSE)
+ {
+ /* We've reused this block, but we've saved the size for you */
+ dwSize = HandleEntry->OldSize;
+ }
+ else
+ {
+ /* Otherwise, query RTL about it */
+ dwSize = RtlSizeHeap(hProcessHeap,
+ HEAP_NO_SERIALIZE,
+ HandleEntry->Object);
+ }
+ }
+
+ /* Check if by now, we still haven't gotten any useful size */
+ if (dwSize == MAXULONG_PTR)
+ {
+ /* Fail */
+ BASE_TRACE_FAILURE();
+ SetLastError(ERROR_INVALID_HANDLE);
+ dwSize = 0;
+ }
+
+ /* All done! Unlock heap and return the size */
+ RtlUnlockHeap(hProcessHeap);
+ return dwSize;
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
GlobalUnfix(HGLOBAL hMem)
{
- if (hMem != INVALID_HANDLE_VALUE)
- GlobalUnlock(hMem);
-}
-
-
-/*
- * @implemented
- */
-BOOL STDCALL
+ /* If the handle is valid, unlock it */
+ if (hMem != INVALID_HANDLE_VALUE) GlobalUnlock(hMem);
+}
+
+/*
+ * @implemented
+ */
+BOOL
+NTAPI
GlobalUnlock(HGLOBAL hMem)
{
-
- PGLOBAL_HANDLE phandle;
- BOOL locked = FALSE;
-
- DPRINT("GlobalUnlock( 0x%lX )\n", (ULONG)hMem);
-
- if(ISPOINTER(hMem))
- {
- SetLastError(ERROR_NOT_LOCKED);
- return FALSE;
- }
-
- HeapLock(GetProcessHeap());
-
- phandle = HANDLE_TO_INTERN(hMem);
- if(MAGIC_GLOBAL_USED == phandle->Magic)
- {
- if (0 >= phandle->LockCount)
- {
- locked = FALSE;
- SetLastError(ERROR_NOT_LOCKED);
- }
- else if (GLOBAL_LOCK_MAX > phandle->LockCount)
- {
- phandle->LockCount--;
- locked = (0 != phandle->LockCount) ? TRUE : FALSE;
- SetLastError(NO_ERROR);
- }
- }
- else
- {
- DPRINT("GlobalUnlock: invalid handle\n");
- locked = FALSE;
- }
- HeapUnlock(GetProcessHeap());
- return locked;
-}
-
-
-/*
- * @implemented
- */
-BOOL STDCALL
+ PGLOBAL_HEAP_HANDLE_ENTRY HandleEntry;
+ BOOL RetVal = TRUE;
+
+ /* Check if this was a simple allocated heap entry */
+ if (!((ULONG_PTR)hMem & GLOBAL_HEAP_IS_HANDLE_ENTRY)) return RetVal;
+
+ /* Otherwise, lock the heap */
+ RtlLockHeap(hProcessHeap);
+
+ /* Get the handle entry */
+ HandleEntry = GlobalGetEntry(hMem);
+ BASE_TRACE_HANDLE(HandleEntry, hMem);
+
+ /* Make sure it's valid */
+ if (!GlobalValidateEntry(HandleEntry))
+ {
+ /* It's not, fail */
+ BASE_TRACE_FAILURE();
+ SetLastError(ERROR_INVALID_HANDLE);
+ }
+ else
+ {
+ /* Otherwise, decrement lock count, unless we're already at 0*/
+ if (!HandleEntry->LockCount--)
+ {
+ /* In which case we simply lock it back and fail */
+ HandleEntry->LockCount++;
+ SetLastError(ERROR_NOT_LOCKED);
+ RetVal = FALSE;
+ }
+ else if (!HandleEntry->LockCount)
+ {
+ /* Nothing to unlock */
+ SetLastError(NO_ERROR);
+ RetVal = FALSE;
+ }
+ }
+
+ /* All done. Unlock the heap and return the pointer */
+ RtlUnlockHeap(hProcessHeap);
+ return RetVal;
+}
+
+/*
+ * @implemented
+ */
+BOOL
+NTAPI
GlobalUnWire(HGLOBAL hMem)
{
- return GlobalUnlock(hMem);
-}
-
-
-/*
- * @implemented
- */
-LPVOID STDCALL
+ /* This is simply an unlock */
+ return GlobalUnlock(hMem);
+}
+
+/*
+ * @implemented
+ */
+LPVOID
+NTAPI
GlobalWire(HGLOBAL hMem)
{
- return GlobalLock(hMem);
+ /* This is just a lock */
+ return GlobalLock(hMem);
+}
+
+/*
+ * @implemented
+ */
+BOOL
+NTAPI
+GlobalMemoryStatusEx(LPMEMORYSTATUSEX lpBuffer)
+{
+ SYSTEM_PERFORMANCE_INFORMATION PerformanceInfo;
+ VM_COUNTERS VmCounters;
+ QUOTA_LIMITS QuotaLimits;
+ ULONGLONG PageFile, PhysicalMemory;
+
+ /* Query performance information */
+ NtQuerySystemInformation(SystemPerformanceInformation,
+ &PerformanceInfo,
+ sizeof(PerformanceInfo),
+ NULL);
+
+ /* Calculate memory load */
+ lpBuffer->dwMemoryLoad = ((DWORD)(BaseCachedSysInfo.NumberOfPhysicalPages -
+ PerformanceInfo.AvailablePages) * 100) /
+ BaseCachedSysInfo.NumberOfPhysicalPages;
+
+ /* Save physical memory */
+ PhysicalMemory = BaseCachedSysInfo.NumberOfPhysicalPages *
+ BaseCachedSysInfo.PageSize;
+ lpBuffer->ullTotalPhys = PhysicalMemory;
+
+ /* Now save available physical memory */
+ PhysicalMemory = PerformanceInfo.AvailablePages *
+ BaseCachedSysInfo.PageSize;
+ lpBuffer->ullAvailPhys = PhysicalMemory;
+
+ /* Query VM and Quota Limits */
+ NtQueryInformationProcess(NtCurrentProcess(),
+ ProcessQuotaLimits,
+ &QuotaLimits,
+ sizeof(QUOTA_LIMITS),
+ NULL);
+ NtQueryInformationProcess(NtCurrentProcess(),
+ ProcessVmCounters,
+ &VmCounters,
+ sizeof(VM_COUNTERS),
+ NULL);
+
+ /* Save the commit limit */
+ lpBuffer->ullTotalPageFile = min(QuotaLimits.PagefileLimit,
+ PerformanceInfo.CommitLimit);
+
+ /* Calculate how many pages are left */
+ PageFile = PerformanceInfo.CommitLimit - PerformanceInfo.CommittedPages;
+
+ /* Save the total */
+ lpBuffer->ullAvailPageFile = min(PageFile,
+ QuotaLimits.PagefileLimit -
+ VmCounters.PagefileUsage);
+ lpBuffer->ullAvailPageFile *= BaseCachedSysInfo.PageSize;
+
+ /* Now calculate the total virtual space */
+ lpBuffer->ullTotalVirtual = (BaseCachedSysInfo.MaximumUserModeAddress -
+ BaseCachedSysInfo.MinimumUserModeAddress) + 1;
+
+ /* And finally the avilable virtual space */
+ lpBuffer->ullAvailVirtual = lpBuffer->ullTotalVirtual -
+ VmCounters.VirtualSize;
+ lpBuffer->ullAvailExtendedVirtual = 0;
+ return TRUE;
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+GlobalMemoryStatus(LPMEMORYSTATUS lpBuffer)
+{
+ MEMORYSTATUSEX lpBufferEx;
+
+ /* Call the extended function */
+ lpBufferEx.dwLength = sizeof(MEMORYSTATUSEX);
+ if (GlobalMemoryStatusEx(&lpBufferEx))
+ {
+ /* Reset the right size and fill out the information */
+ lpBuffer->dwLength = sizeof(MEMORYSTATUS);
+ lpBuffer->dwMemoryLoad = lpBufferEx.dwMemoryLoad;
+ lpBuffer->dwTotalPhys = lpBufferEx.ullTotalPhys;
+ lpBuffer->dwAvailPhys = lpBufferEx.ullAvailPhys;
+ lpBuffer->dwTotalPageFile = lpBufferEx.ullTotalPageFile;
+ lpBuffer->dwAvailPageFile = lpBufferEx.ullAvailPageFile;
+ lpBuffer->dwTotalVirtual = lpBufferEx.ullTotalVirtual;
+ lpBuffer->dwAvailVirtual = lpBufferEx.ullAvailVirtual;
+ }
}
/* EOF */
Modified: trunk/reactos/dll/win32/kernel32/misc/dllmain.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/kernel32/misc/dl…
==============================================================================
--- trunk/reactos/dll/win32/kernel32/misc/dllmain.c (original)
+++ trunk/reactos/dll/win32/kernel32/misc/dllmain.c Sat Jun 24 22:11:57 2006
@@ -339,6 +339,9 @@
}
hProcessHeap = RtlGetProcessHeap();
+ RtlInitializeHandleTable(0xFFFF,
+ sizeof(GLOBAL_HEAP_HANDLE_ENTRY),
+ &BaseGlobalHandleTable);
hCurrentModule = hDll;
DPRINT("Heap: %p\n", hProcessHeap);