Moved heap functions to ntdll.
Got rid of internal heap flags.
Reimplemented MapLS to not depend on the segptr heap.
diff --git a/dlls/kernel/kernel32.spec b/dlls/kernel/kernel32.spec
index da07c78..a8d09c6 100644
--- a/dlls/kernel/kernel32.spec
+++ b/dlls/kernel/kernel32.spec
@@ -500,15 +500,15 @@
@ stub Heap32ListFirst
@ stub Heap32ListNext
@ stub Heap32Next
-@ stdcall HeapAlloc(long long long) HeapAlloc
+@ forward HeapAlloc ntdll.RtlAllocateHeap
@ stdcall HeapCompact(long long) HeapCompact
@ stdcall HeapCreate(long long long) HeapCreate
@ stdcall HeapDestroy(long) HeapDestroy
-@ stdcall HeapFree(long long ptr) HeapFree
+@ forward HeapFree ntdll.RtlFreeHeap
@ stdcall HeapLock(long) HeapLock
-@ stdcall HeapReAlloc(long long ptr long) HeapReAlloc
+@ forward HeapReAlloc ntdll.RtlReAllocateHeap
@ stub HeapSetFlags
-@ stdcall HeapSize(long long ptr) HeapSize
+@ forward HeapSize ntdll.RtlSizeHeap
@ stdcall HeapUnlock(long) HeapUnlock
@ stdcall HeapValidate(long long ptr) HeapValidate
@ stdcall HeapWalk(long ptr) HeapWalk
diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in
index f3d214b..5a8a96a 100644
--- a/dlls/ntdll/Makefile.in
+++ b/dlls/ntdll/Makefile.in
@@ -11,6 +11,7 @@
exception.c \
error.c \
file.c \
+ heap.c \
large_int.c \
misc.c \
nt.c \
diff --git a/dlls/ntdll/debugtools.c b/dlls/ntdll/debugtools.c
index 8354bef..4c96fe3 100644
--- a/dlls/ntdll/debugtools.c
+++ b/dlls/ntdll/debugtools.c
@@ -14,6 +14,7 @@
#include "thread.h"
#include "winbase.h"
#include "winnt.h"
+#include "ntddk.h"
#include "wtypes.h"
DECLARE_DEBUG_CHANNEL(tid);
@@ -50,9 +51,9 @@
tmp.out_pos = tmp.output;
}
if (!GetProcessHeap()) return &tmp;
- /* setup the temp structure in case HeapAlloc wants to print something */
+ /* setup the temp structure in case RtlAllocateHeap wants to print something */
NtCurrentTeb()->debug_info = &tmp;
- info = HeapAlloc( GetProcessHeap(), 0, sizeof(*info) );
+ info = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*info) );
info->str_pos = info->strings;
info->out_pos = info->output;
NtCurrentTeb()->debug_info = info;
diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c
new file mode 100644
index 0000000..ac177e2
--- /dev/null
+++ b/dlls/ntdll/heap.c
@@ -0,0 +1,1424 @@
+/*
+ * Win32 heap functions
+ *
+ * Copyright 1996 Alexandre Julliard
+ * Copyright 1998 Ulrich Weigand
+ */
+
+#include "config.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "ntddk.h"
+#include "wine/winbase16.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "winnt.h"
+#include "heap.h"
+#include "thread.h"
+#include "debugtools.h"
+
+DEFAULT_DEBUG_CHANNEL(heap);
+
+/* Note: the heap data structures are based on what Pietrek describes in his
+ * book 'Windows 95 System Programming Secrets'. The layout is not exactly
+ * the same, but could be easily adapted if it turns out some programs
+ * require it.
+ */
+
+typedef struct tagARENA_INUSE
+{
+ DWORD size; /* Block size; must be the first field */
+ DWORD magic; /* Magic number */
+} ARENA_INUSE;
+
+typedef struct tagARENA_FREE
+{
+ DWORD size; /* Block size; must be the first field */
+ DWORD magic; /* Magic number */
+ struct tagARENA_FREE *next; /* Next free arena */
+ struct tagARENA_FREE *prev; /* Prev free arena */
+} ARENA_FREE;
+
+#define ARENA_FLAG_FREE 0x00000001 /* flags OR'ed with arena size */
+#define ARENA_FLAG_PREV_FREE 0x00000002
+#define ARENA_SIZE_MASK (~3)
+#define ARENA_INUSE_MAGIC 0x44455355 /* Value for arena 'magic' field */
+#define ARENA_FREE_MAGIC 0x45455246 /* Value for arena 'magic' field */
+
+#define ARENA_INUSE_FILLER 0x55
+#define ARENA_FREE_FILLER 0xaa
+
+#define QUIET 1 /* Suppress messages */
+#define NOISY 0 /* Report all errors */
+
+#define HEAP_NB_FREE_LISTS 4 /* Number of free lists */
+
+/* Max size of the blocks on the free lists */
+static const DWORD HEAP_freeListSizes[HEAP_NB_FREE_LISTS] =
+{
+ 0x20, 0x80, 0x200, ~0UL
+};
+
+typedef struct
+{
+ DWORD size;
+ ARENA_FREE arena;
+} FREE_LIST_ENTRY;
+
+struct tagHEAP;
+
+typedef struct tagSUBHEAP
+{
+ DWORD size; /* Size of the whole sub-heap */
+ DWORD commitSize; /* Committed size of the sub-heap */
+ DWORD headerSize; /* Size of the heap header */
+ struct tagSUBHEAP *next; /* Next sub-heap */
+ struct tagHEAP *heap; /* Main heap structure */
+ DWORD magic; /* Magic number */
+} SUBHEAP;
+
+#define SUBHEAP_MAGIC ((DWORD)('S' | ('U'<<8) | ('B'<<16) | ('H'<<24)))
+
+typedef struct tagHEAP
+{
+ SUBHEAP subheap; /* First sub-heap */
+ struct tagHEAP *next; /* Next heap for this process */
+ CRITICAL_SECTION critSection; /* Critical section for serialization */
+ FREE_LIST_ENTRY freeList[HEAP_NB_FREE_LISTS]; /* Free lists */
+ DWORD flags; /* Heap flags */
+ DWORD magic; /* Magic number */
+} HEAP;
+
+#define HEAP_MAGIC ((DWORD)('H' | ('E'<<8) | ('A'<<16) | ('P'<<24)))
+
+#define HEAP_DEF_SIZE 0x110000 /* Default heap size = 1Mb + 64Kb */
+#define HEAP_MIN_BLOCK_SIZE (8+sizeof(ARENA_FREE)) /* Min. heap block size */
+#define COMMIT_MASK 0xffff /* bitmask for commit/decommit granularity */
+
+static HANDLE processHeap; /* main process heap */
+
+static HEAP *firstHeap; /* head of secondary heaps list */
+
+static BOOL HEAP_IsRealArena( HEAP *heapPtr, DWORD flags, LPCVOID block, BOOL quiet );
+
+/* SetLastError for ntdll */
+inline static void set_status( NTSTATUS status )
+{
+#if defined(__i386__) && defined(__GNUC__)
+ /* in this case SetLastError is an inline function so we can use it */
+ SetLastError( RtlNtStatusToDosError( status ) );
+#else
+ /* cannot use SetLastError, do it manually */
+ NtCurrentTeb()->last_error = RtlNtStatusToDosError( status );
+#endif
+}
+
+/* set the process main heap */
+static void set_process_heap( HANDLE heap )
+{
+ HANDLE *pdb = (HANDLE *)NtCurrentTeb()->process;
+ pdb[0x18 / sizeof(HANDLE)] = heap; /* heap is at offset 0x18 in pdb */
+ processHeap = heap;
+}
+
+
+/***********************************************************************
+ * HEAP_Dump
+ */
+void HEAP_Dump( HEAP *heap )
+{
+ int i;
+ SUBHEAP *subheap;
+ char *ptr;
+
+ DPRINTF( "Heap: %08lx\n", (DWORD)heap );
+ DPRINTF( "Next: %08lx Sub-heaps: %08lx",
+ (DWORD)heap->next, (DWORD)&heap->subheap );
+ subheap = &heap->subheap;
+ while (subheap->next)
+ {
+ DPRINTF( " -> %08lx", (DWORD)subheap->next );
+ subheap = subheap->next;
+ }
+
+ DPRINTF( "\nFree lists:\n Block Stat Size Id\n" );
+ for (i = 0; i < HEAP_NB_FREE_LISTS; i++)
+ DPRINTF( "%08lx free %08lx prev=%08lx next=%08lx\n",
+ (DWORD)&heap->freeList[i].arena, heap->freeList[i].arena.size,
+ (DWORD)heap->freeList[i].arena.prev,
+ (DWORD)heap->freeList[i].arena.next );
+
+ subheap = &heap->subheap;
+ while (subheap)
+ {
+ DWORD freeSize = 0, usedSize = 0, arenaSize = subheap->headerSize;
+ DPRINTF( "\n\nSub-heap %08lx: size=%08lx committed=%08lx\n",
+ (DWORD)subheap, subheap->size, subheap->commitSize );
+
+ DPRINTF( "\n Block Stat Size Id\n" );
+ ptr = (char*)subheap + subheap->headerSize;
+ while (ptr < (char *)subheap + subheap->size)
+ {
+ if (*(DWORD *)ptr & ARENA_FLAG_FREE)
+ {
+ ARENA_FREE *pArena = (ARENA_FREE *)ptr;
+ DPRINTF( "%08lx free %08lx prev=%08lx next=%08lx\n",
+ (DWORD)pArena, pArena->size & ARENA_SIZE_MASK,
+ (DWORD)pArena->prev, (DWORD)pArena->next);
+ ptr += sizeof(*pArena) + (pArena->size & ARENA_SIZE_MASK);
+ arenaSize += sizeof(ARENA_FREE);
+ freeSize += pArena->size & ARENA_SIZE_MASK;
+ }
+ else if (*(DWORD *)ptr & ARENA_FLAG_PREV_FREE)
+ {
+ ARENA_INUSE *pArena = (ARENA_INUSE *)ptr;
+ DPRINTF( "%08lx Used %08lx back=%08lx\n",
+ (DWORD)pArena, pArena->size & ARENA_SIZE_MASK, *((DWORD *)pArena - 1) );
+ ptr += sizeof(*pArena) + (pArena->size & ARENA_SIZE_MASK);
+ arenaSize += sizeof(ARENA_INUSE);
+ usedSize += pArena->size & ARENA_SIZE_MASK;
+ }
+ else
+ {
+ ARENA_INUSE *pArena = (ARENA_INUSE *)ptr;
+ DPRINTF( "%08lx used %08lx\n",
+ (DWORD)pArena, pArena->size & ARENA_SIZE_MASK );
+ ptr += sizeof(*pArena) + (pArena->size & ARENA_SIZE_MASK);
+ arenaSize += sizeof(ARENA_INUSE);
+ usedSize += pArena->size & ARENA_SIZE_MASK;
+ }
+ }
+ DPRINTF( "\nTotal: Size=%08lx Committed=%08lx Free=%08lx Used=%08lx Arenas=%08lx (%ld%%)\n\n",
+ subheap->size, subheap->commitSize, freeSize, usedSize,
+ arenaSize, (arenaSize * 100) / subheap->size );
+ subheap = subheap->next;
+ }
+}
+
+
+/***********************************************************************
+ * HEAP_GetPtr
+ * RETURNS
+ * Pointer to the heap
+ * NULL: Failure
+ */
+static HEAP *HEAP_GetPtr(
+ HANDLE heap /* [in] Handle to the heap */
+) {
+ HEAP *heapPtr = (HEAP *)heap;
+ if (!heapPtr || (heapPtr->magic != HEAP_MAGIC))
+ {
+ ERR("Invalid heap %08x!\n", heap );
+ return NULL;
+ }
+ if (TRACE_ON(heap) && !HEAP_IsRealArena( heapPtr, 0, NULL, NOISY ))
+ {
+ HEAP_Dump( heapPtr );
+ assert( FALSE );
+ return NULL;
+ }
+ return heapPtr;
+}
+
+
+/***********************************************************************
+ * HEAP_InsertFreeBlock
+ *
+ * Insert a free block into the free list.
+ */
+static void HEAP_InsertFreeBlock( HEAP *heap, ARENA_FREE *pArena )
+{
+ FREE_LIST_ENTRY *pEntry = heap->freeList;
+ while (pEntry->size < pArena->size) pEntry++;
+ pArena->size |= ARENA_FLAG_FREE;
+ pArena->next = pEntry->arena.next;
+ pArena->next->prev = pArena;
+ pArena->prev = &pEntry->arena;
+ pEntry->arena.next = pArena;
+}
+
+
+/***********************************************************************
+ * HEAP_FindSubHeap
+ * Find the sub-heap containing a given address.
+ *
+ * RETURNS
+ * Pointer: Success
+ * NULL: Failure
+ */
+static SUBHEAP *HEAP_FindSubHeap(
+ HEAP *heap, /* [in] Heap pointer */
+ LPCVOID ptr /* [in] Address */
+) {
+ SUBHEAP *sub = &heap->subheap;
+ while (sub)
+ {
+ if (((char *)ptr >= (char *)sub) &&
+ ((char *)ptr < (char *)sub + sub->size)) return sub;
+ sub = sub->next;
+ }
+ return NULL;
+}
+
+
+/***********************************************************************
+ * HEAP_Commit
+ *
+ * Make sure the heap storage is committed up to (not including) ptr.
+ */
+static inline BOOL HEAP_Commit( SUBHEAP *subheap, void *ptr )
+{
+ DWORD size = (DWORD)((char *)ptr - (char *)subheap);
+ size = (size + COMMIT_MASK) & ~COMMIT_MASK;
+ if (size > subheap->size) size = subheap->size;
+ if (size <= subheap->commitSize) return TRUE;
+ if (!VirtualAlloc( (char *)subheap + subheap->commitSize,
+ size - subheap->commitSize, MEM_COMMIT,
+ PAGE_EXECUTE_READWRITE))
+ {
+ WARN("Could not commit %08lx bytes at %08lx for heap %08lx\n",
+ size - subheap->commitSize,
+ (DWORD)((char *)subheap + subheap->commitSize),
+ (DWORD)subheap->heap );
+ return FALSE;
+ }
+ subheap->commitSize = size;
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * HEAP_Decommit
+ *
+ * If possible, decommit the heap storage from (including) 'ptr'.
+ */
+static inline BOOL HEAP_Decommit( SUBHEAP *subheap, void *ptr )
+{
+ DWORD size = (DWORD)((char *)ptr - (char *)subheap);
+ /* round to next block and add one full block */
+ size = ((size + COMMIT_MASK) & ~COMMIT_MASK) + COMMIT_MASK + 1;
+ if (size >= subheap->commitSize) return TRUE;
+ if (!VirtualFree( (char *)subheap + size,
+ subheap->commitSize - size, MEM_DECOMMIT ))
+ {
+ WARN("Could not decommit %08lx bytes at %08lx for heap %08lx\n",
+ subheap->commitSize - size,
+ (DWORD)((char *)subheap + size),
+ (DWORD)subheap->heap );
+ return FALSE;
+ }
+ subheap->commitSize = size;
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * HEAP_CreateFreeBlock
+ *
+ * Create a free block at a specified address. 'size' is the size of the
+ * whole block, including the new arena.
+ */
+static void HEAP_CreateFreeBlock( SUBHEAP *subheap, void *ptr, DWORD size )
+{
+ ARENA_FREE *pFree;
+
+ /* Create a free arena */
+
+ pFree = (ARENA_FREE *)ptr;
+ pFree->magic = ARENA_FREE_MAGIC;
+
+ /* If debugging, erase the freed block content */
+
+ if (TRACE_ON(heap))
+ {
+ char *pEnd = (char *)ptr + size;
+ if (pEnd > (char *)subheap + subheap->commitSize)
+ pEnd = (char *)subheap + subheap->commitSize;
+ if (pEnd > (char *)(pFree + 1))
+ memset( pFree + 1, ARENA_FREE_FILLER, pEnd - (char *)(pFree + 1) );
+ }
+
+ /* Check if next block is free also */
+
+ if (((char *)ptr + size < (char *)subheap + subheap->size) &&
+ (*(DWORD *)((char *)ptr + size) & ARENA_FLAG_FREE))
+ {
+ /* Remove the next arena from the free list */
+ ARENA_FREE *pNext = (ARENA_FREE *)((char *)ptr + size);
+ pNext->next->prev = pNext->prev;
+ pNext->prev->next = pNext->next;
+ size += (pNext->size & ARENA_SIZE_MASK) + sizeof(*pNext);
+ if (TRACE_ON(heap))
+ memset( pNext, ARENA_FREE_FILLER, sizeof(ARENA_FREE) );
+ }
+
+ /* Set the next block PREV_FREE flag and pointer */
+
+ if ((char *)ptr + size < (char *)subheap + subheap->size)
+ {
+ DWORD *pNext = (DWORD *)((char *)ptr + size);
+ *pNext |= ARENA_FLAG_PREV_FREE;
+ *(ARENA_FREE **)(pNext - 1) = pFree;
+ }
+
+ /* Last, insert the new block into the free list */
+
+ pFree->size = size - sizeof(*pFree);
+ HEAP_InsertFreeBlock( subheap->heap, pFree );
+}
+
+
+/***********************************************************************
+ * HEAP_MakeInUseBlockFree
+ *
+ * Turn an in-use block into a free block. Can also decommit the end of
+ * the heap, and possibly even free the sub-heap altogether.
+ */
+static void HEAP_MakeInUseBlockFree( SUBHEAP *subheap, ARENA_INUSE *pArena )
+{
+ ARENA_FREE *pFree;
+ DWORD size = (pArena->size & ARENA_SIZE_MASK) + sizeof(*pArena);
+
+ /* Check if we can merge with previous block */
+
+ if (pArena->size & ARENA_FLAG_PREV_FREE)
+ {
+ pFree = *((ARENA_FREE **)pArena - 1);
+ size += (pFree->size & ARENA_SIZE_MASK) + sizeof(ARENA_FREE);
+ /* Remove it from the free list */
+ pFree->next->prev = pFree->prev;
+ pFree->prev->next = pFree->next;
+ }
+ else pFree = (ARENA_FREE *)pArena;
+
+ /* Create a free block */
+
+ HEAP_CreateFreeBlock( subheap, pFree, size );
+ size = (pFree->size & ARENA_SIZE_MASK) + sizeof(ARENA_FREE);
+ if ((char *)pFree + size < (char *)subheap + subheap->size)
+ return; /* Not the last block, so nothing more to do */
+
+ /* Free the whole sub-heap if it's empty and not the original one */
+
+ if (((char *)pFree == (char *)subheap + subheap->headerSize) &&
+ (subheap != &subheap->heap->subheap))
+ {
+ SUBHEAP *pPrev = &subheap->heap->subheap;
+ /* Remove the free block from the list */
+ pFree->next->prev = pFree->prev;
+ pFree->prev->next = pFree->next;
+ /* Remove the subheap from the list */
+ while (pPrev && (pPrev->next != subheap)) pPrev = pPrev->next;
+ if (pPrev) pPrev->next = subheap->next;
+ /* Free the memory */
+ subheap->magic = 0;
+ VirtualFree( subheap, 0, MEM_RELEASE );
+ return;
+ }
+
+ /* Decommit the end of the heap */
+
+ if (!(subheap->heap->flags & HEAP_SHARED)) HEAP_Decommit( subheap, pFree + 1 );
+}
+
+
+/***********************************************************************
+ * HEAP_ShrinkBlock
+ *
+ * Shrink an in-use block.
+ */
+static void HEAP_ShrinkBlock(SUBHEAP *subheap, ARENA_INUSE *pArena, DWORD size)
+{
+ if ((pArena->size & ARENA_SIZE_MASK) >= size + HEAP_MIN_BLOCK_SIZE)
+ {
+ HEAP_CreateFreeBlock( subheap, (char *)(pArena + 1) + size,
+ (pArena->size & ARENA_SIZE_MASK) - size );
+ /* assign size plus previous arena flags */
+ pArena->size = size | (pArena->size & ~ARENA_SIZE_MASK);
+ }
+ else
+ {
+ /* Turn off PREV_FREE flag in next block */
+ char *pNext = (char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK);
+ if (pNext < (char *)subheap + subheap->size)
+ *(DWORD *)pNext &= ~ARENA_FLAG_PREV_FREE;
+ }
+}
+
+/***********************************************************************
+ * HEAP_InitSubHeap
+ */
+static BOOL HEAP_InitSubHeap( HEAP *heap, LPVOID address, DWORD flags,
+ DWORD commitSize, DWORD totalSize )
+{
+ SUBHEAP *subheap = (SUBHEAP *)address;
+ FREE_LIST_ENTRY *pEntry;
+ int i;
+
+ /* Commit memory */
+
+ if (flags & HEAP_SHARED)
+ commitSize = totalSize; /* always commit everything in a shared heap */
+ if (!VirtualAlloc(address, commitSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE))
+ {
+ WARN("Could not commit %08lx bytes for sub-heap %08lx\n",
+ commitSize, (DWORD)address );
+ return FALSE;
+ }
+
+ /* Fill the sub-heap structure */
+
+ subheap->heap = heap;
+ subheap->size = totalSize;
+ subheap->commitSize = commitSize;
+ subheap->magic = SUBHEAP_MAGIC;
+
+ if ( subheap != (SUBHEAP *)heap )
+ {
+ /* If this is a secondary subheap, insert it into list */
+
+ subheap->headerSize = sizeof(SUBHEAP);
+ subheap->next = heap->subheap.next;
+ heap->subheap.next = subheap;
+ }
+ else
+ {
+ /* If this is a primary subheap, initialize main heap */
+
+ subheap->headerSize = sizeof(HEAP);
+ subheap->next = NULL;
+ heap->next = NULL;
+ heap->flags = flags;
+ heap->magic = HEAP_MAGIC;
+
+ /* Build the free lists */
+
+ for (i = 0, pEntry = heap->freeList; i < HEAP_NB_FREE_LISTS; i++, pEntry++)
+ {
+ pEntry->size = HEAP_freeListSizes[i];
+ pEntry->arena.size = 0 | ARENA_FLAG_FREE;
+ pEntry->arena.next = i < HEAP_NB_FREE_LISTS-1 ?
+ &heap->freeList[i+1].arena : &heap->freeList[0].arena;
+ pEntry->arena.prev = i ? &heap->freeList[i-1].arena :
+ &heap->freeList[HEAP_NB_FREE_LISTS-1].arena;
+ pEntry->arena.magic = ARENA_FREE_MAGIC;
+ }
+
+ /* Initialize critical section */
+
+ RtlInitializeCriticalSection( &heap->critSection );
+ }
+
+ /* Create the first free block */
+
+ HEAP_CreateFreeBlock( subheap, (LPBYTE)subheap + subheap->headerSize,
+ subheap->size - subheap->headerSize );
+
+ return TRUE;
+}
+
+/***********************************************************************
+ * HEAP_CreateSubHeap
+ *
+ * Create a sub-heap of the given size.
+ * If heap == NULL, creates a main heap.
+ */
+static SUBHEAP *HEAP_CreateSubHeap( HEAP *heap, void *base, DWORD flags,
+ DWORD commitSize, DWORD totalSize )
+{
+ LPVOID address = base;
+
+ if (!address)
+ {
+ /* round-up sizes on a 64K boundary */
+ totalSize = (totalSize + 0xffff) & 0xffff0000;
+ commitSize = (commitSize + 0xffff) & 0xffff0000;
+ if (!commitSize) commitSize = 0x10000;
+ if (totalSize < commitSize) totalSize = commitSize;
+
+ /* allocate the memory block */
+ if (!(address = VirtualAlloc( NULL, totalSize, MEM_RESERVE, PAGE_EXECUTE_READWRITE )))
+ {
+ WARN("Could not VirtualAlloc %08lx bytes\n",
+ totalSize );
+ return NULL;
+ }
+ }
+
+ /* Initialize subheap */
+
+ if (!HEAP_InitSubHeap( heap ? heap : (HEAP *)address,
+ address, flags, commitSize, totalSize ))
+ {
+ if (!base) VirtualFree( address, 0, MEM_RELEASE );
+ return NULL;
+ }
+
+ return (SUBHEAP *)address;
+}
+
+
+/***********************************************************************
+ * HEAP_FindFreeBlock
+ *
+ * Find a free block at least as large as the requested size, and make sure
+ * the requested size is committed.
+ */
+static ARENA_FREE *HEAP_FindFreeBlock( HEAP *heap, DWORD size,
+ SUBHEAP **ppSubHeap )
+{
+ SUBHEAP *subheap;
+ ARENA_FREE *pArena;
+ FREE_LIST_ENTRY *pEntry = heap->freeList;
+
+ /* Find a suitable free list, and in it find a block large enough */
+
+ while (pEntry->size < size) pEntry++;
+ pArena = pEntry->arena.next;
+ while (pArena != &heap->freeList[0].arena)
+ {
+ DWORD arena_size = (pArena->size & ARENA_SIZE_MASK) +
+ sizeof(ARENA_FREE) - sizeof(ARENA_INUSE);
+ if (arena_size >= size)
+ {
+ subheap = HEAP_FindSubHeap( heap, pArena );
+ if (!HEAP_Commit( subheap, (char *)pArena + sizeof(ARENA_INUSE)
+ + size + HEAP_MIN_BLOCK_SIZE))
+ return NULL;
+ *ppSubHeap = subheap;
+ return pArena;
+ }
+ pArena = pArena->next;
+ }
+
+ /* If no block was found, attempt to grow the heap */
+
+ if (!(heap->flags & HEAP_GROWABLE))
+ {
+ WARN("Not enough space in heap %08lx for %08lx bytes\n",
+ (DWORD)heap, size );
+ return NULL;
+ }
+ /* make sure that we have a big enough size *committed* to fit another
+ * last free arena in !
+ * So just one heap struct, one first free arena which will eventually
+ * get inuse, and HEAP_MIN_BLOCK_SIZE for the second free arena that
+ * might get assigned all remaining free space in HEAP_ShrinkBlock() */
+ size += sizeof(SUBHEAP) + sizeof(ARENA_INUSE) + HEAP_MIN_BLOCK_SIZE;
+ if (!(subheap = HEAP_CreateSubHeap( heap, NULL, heap->flags, size,
+ max( HEAP_DEF_SIZE, size ) )))
+ return NULL;
+
+ TRACE("created new sub-heap %08lx of %08lx bytes for heap %08lx\n",
+ (DWORD)subheap, size, (DWORD)heap );
+
+ *ppSubHeap = subheap;
+ return (ARENA_FREE *)(subheap + 1);
+}
+
+
+/***********************************************************************
+ * HEAP_IsValidArenaPtr
+ *
+ * Check that the pointer is inside the range possible for arenas.
+ */
+static BOOL HEAP_IsValidArenaPtr( HEAP *heap, void *ptr )
+{
+ int i;
+ SUBHEAP *subheap = HEAP_FindSubHeap( heap, ptr );
+ if (!subheap) return FALSE;
+ if ((char *)ptr >= (char *)subheap + subheap->headerSize) return TRUE;
+ if (subheap != &heap->subheap) return FALSE;
+ for (i = 0; i < HEAP_NB_FREE_LISTS; i++)
+ if (ptr == (void *)&heap->freeList[i].arena) return TRUE;
+ return FALSE;
+}
+
+
+/***********************************************************************
+ * HEAP_ValidateFreeArena
+ */
+static BOOL HEAP_ValidateFreeArena( SUBHEAP *subheap, ARENA_FREE *pArena )
+{
+ char *heapEnd = (char *)subheap + subheap->size;
+
+#if !defined(ALLOW_UNALIGNED_ACCESS)
+ /* Check for unaligned pointers */
+ if ( (long)pArena % sizeof(void *) != 0 )
+ {
+ ERR( "Heap %08lx: unaligned arena pointer %08lx\n",
+ (DWORD)subheap->heap, (DWORD)pArena );
+ return FALSE;
+ }
+#endif
+
+ /* Check magic number */
+ if (pArena->magic != ARENA_FREE_MAGIC)
+ {
+ ERR("Heap %08lx: invalid free arena magic for %08lx\n",
+ (DWORD)subheap->heap, (DWORD)pArena );
+ return FALSE;
+ }
+ /* Check size flags */
+ if (!(pArena->size & ARENA_FLAG_FREE) ||
+ (pArena->size & ARENA_FLAG_PREV_FREE))
+ {
+ ERR("Heap %08lx: bad flags %lx for free arena %08lx\n",
+ (DWORD)subheap->heap, pArena->size & ~ARENA_SIZE_MASK, (DWORD)pArena );
+ }
+ /* Check arena size */
+ if ((char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK) > heapEnd)
+ {
+ ERR("Heap %08lx: bad size %08lx for free arena %08lx\n",
+ (DWORD)subheap->heap, (DWORD)pArena->size & ARENA_SIZE_MASK, (DWORD)pArena );
+ return FALSE;
+ }
+ /* Check that next pointer is valid */
+ if (!HEAP_IsValidArenaPtr( subheap->heap, pArena->next ))
+ {
+ ERR("Heap %08lx: bad next ptr %08lx for arena %08lx\n",
+ (DWORD)subheap->heap, (DWORD)pArena->next, (DWORD)pArena );
+ return FALSE;
+ }
+ /* Check that next arena is free */
+ if (!(pArena->next->size & ARENA_FLAG_FREE) ||
+ (pArena->next->magic != ARENA_FREE_MAGIC))
+ {
+ ERR("Heap %08lx: next arena %08lx invalid for %08lx\n",
+ (DWORD)subheap->heap, (DWORD)pArena->next, (DWORD)pArena );
+ return FALSE;
+ }
+ /* Check that prev pointer is valid */
+ if (!HEAP_IsValidArenaPtr( subheap->heap, pArena->prev ))
+ {
+ ERR("Heap %08lx: bad prev ptr %08lx for arena %08lx\n",
+ (DWORD)subheap->heap, (DWORD)pArena->prev, (DWORD)pArena );
+ return FALSE;
+ }
+ /* Check that prev arena is free */
+ if (!(pArena->prev->size & ARENA_FLAG_FREE) ||
+ (pArena->prev->magic != ARENA_FREE_MAGIC))
+ {
+ /* this often means that the prev arena got overwritten
+ * by a memory write before that prev arena */
+ ERR("Heap %08lx: prev arena %08lx invalid for %08lx\n",
+ (DWORD)subheap->heap, (DWORD)pArena->prev, (DWORD)pArena );
+ return FALSE;
+ }
+ /* Check that next block has PREV_FREE flag */
+ if ((char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK) < heapEnd)
+ {
+ if (!(*(DWORD *)((char *)(pArena + 1) +
+ (pArena->size & ARENA_SIZE_MASK)) & ARENA_FLAG_PREV_FREE))
+ {
+ ERR("Heap %08lx: free arena %08lx next block has no PREV_FREE flag\n",
+ (DWORD)subheap->heap, (DWORD)pArena );
+ return FALSE;
+ }
+ /* Check next block back pointer */
+ if (*((ARENA_FREE **)((char *)(pArena + 1) +
+ (pArena->size & ARENA_SIZE_MASK)) - 1) != pArena)
+ {
+ ERR("Heap %08lx: arena %08lx has wrong back ptr %08lx\n",
+ (DWORD)subheap->heap, (DWORD)pArena,
+ *((DWORD *)((char *)(pArena+1)+ (pArena->size & ARENA_SIZE_MASK)) - 1));
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * HEAP_ValidateInUseArena
+ */
+static BOOL HEAP_ValidateInUseArena( SUBHEAP *subheap, ARENA_INUSE *pArena, BOOL quiet )
+{
+ char *heapEnd = (char *)subheap + subheap->size;
+
+#if !defined(ALLOW_UNALIGNED_ACCESS)
+ /* Check for unaligned pointers */
+ if ( (long)pArena % sizeof(void *) != 0 )
+ {
+ if ( quiet == NOISY )
+ {
+ ERR( "Heap %08lx: unaligned arena pointer %08lx\n",
+ (DWORD)subheap->heap, (DWORD)pArena );
+ if ( TRACE_ON(heap) )
+ HEAP_Dump( subheap->heap );
+ }
+ else if ( WARN_ON(heap) )
+ {
+ WARN( "Heap %08lx: unaligned arena pointer %08lx\n",
+ (DWORD)subheap->heap, (DWORD)pArena );
+ if ( TRACE_ON(heap) )
+ HEAP_Dump( subheap->heap );
+ }
+ return FALSE;
+ }
+#endif
+
+ /* Check magic number */
+ if (pArena->magic != ARENA_INUSE_MAGIC)
+ {
+ if (quiet == NOISY) {
+ ERR("Heap %08lx: invalid in-use arena magic for %08lx\n",
+ (DWORD)subheap->heap, (DWORD)pArena );
+ if (TRACE_ON(heap))
+ HEAP_Dump( subheap->heap );
+ } else if (WARN_ON(heap)) {
+ WARN("Heap %08lx: invalid in-use arena magic for %08lx\n",
+ (DWORD)subheap->heap, (DWORD)pArena );
+ if (TRACE_ON(heap))
+ HEAP_Dump( subheap->heap );
+ }
+ return FALSE;
+ }
+ /* Check size flags */
+ if (pArena->size & ARENA_FLAG_FREE)
+ {
+ ERR("Heap %08lx: bad flags %lx for in-use arena %08lx\n",
+ (DWORD)subheap->heap, pArena->size & ~ARENA_SIZE_MASK, (DWORD)pArena );
+ }
+ /* Check arena size */
+ if ((char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK) > heapEnd)
+ {
+ ERR("Heap %08lx: bad size %08lx for in-use arena %08lx\n",
+ (DWORD)subheap->heap, (DWORD)pArena->size & ARENA_SIZE_MASK, (DWORD)pArena );
+ return FALSE;
+ }
+ /* Check next arena PREV_FREE flag */
+ if (((char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK) < heapEnd) &&
+ (*(DWORD *)((char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK)) & ARENA_FLAG_PREV_FREE))
+ {
+ ERR("Heap %08lx: in-use arena %08lx next block has PREV_FREE flag\n",
+ (DWORD)subheap->heap, (DWORD)pArena );
+ return FALSE;
+ }
+ /* Check prev free arena */
+ if (pArena->size & ARENA_FLAG_PREV_FREE)
+ {
+ ARENA_FREE *pPrev = *((ARENA_FREE **)pArena - 1);
+ /* Check prev pointer */
+ if (!HEAP_IsValidArenaPtr( subheap->heap, pPrev ))
+ {
+ ERR("Heap %08lx: bad back ptr %08lx for arena %08lx\n",
+ (DWORD)subheap->heap, (DWORD)pPrev, (DWORD)pArena );
+ return FALSE;
+ }
+ /* Check that prev arena is free */
+ if (!(pPrev->size & ARENA_FLAG_FREE) ||
+ (pPrev->magic != ARENA_FREE_MAGIC))
+ {
+ ERR("Heap %08lx: prev arena %08lx invalid for in-use %08lx\n",
+ (DWORD)subheap->heap, (DWORD)pPrev, (DWORD)pArena );
+ return FALSE;
+ }
+ /* Check that prev arena is really the previous block */
+ if ((char *)(pPrev + 1) + (pPrev->size & ARENA_SIZE_MASK) != (char *)pArena)
+ {
+ ERR("Heap %08lx: prev arena %08lx is not prev for in-use %08lx\n",
+ (DWORD)subheap->heap, (DWORD)pPrev, (DWORD)pArena );
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * HEAP_IsRealArena [Internal]
+ * Validates a block is a valid arena.
+ *
+ * RETURNS
+ * TRUE: Success
+ * FALSE: Failure
+ */
+static BOOL HEAP_IsRealArena( HEAP *heapPtr, /* [in] ptr to the heap */
+ DWORD flags, /* [in] Bit flags that control access during operation */
+ LPCVOID block, /* [in] Optional pointer to memory block to validate */
+ BOOL quiet ) /* [in] Flag - if true, HEAP_ValidateInUseArena
+ * does not complain */
+{
+ SUBHEAP *subheap;
+ BOOL ret = TRUE;
+
+ if (!heapPtr || (heapPtr->magic != HEAP_MAGIC))
+ {
+ ERR("Invalid heap %p!\n", heapPtr );
+ return FALSE;
+ }
+
+ flags &= HEAP_NO_SERIALIZE;
+ flags |= heapPtr->flags;
+ /* calling HeapLock may result in infinite recursion, so do the critsect directly */
+ if (!(flags & HEAP_NO_SERIALIZE))
+ RtlEnterCriticalSection( &heapPtr->critSection );
+
+ if (block)
+ {
+ /* Only check this single memory block */
+
+ if (!(subheap = HEAP_FindSubHeap( heapPtr, block )) ||
+ ((char *)block < (char *)subheap + subheap->headerSize
+ + sizeof(ARENA_INUSE)))
+ {
+ if (quiet == NOISY)
+ ERR("Heap %p: block %p is not inside heap\n", heapPtr, block );
+ else if (WARN_ON(heap))
+ WARN("Heap %p: block %p is not inside heap\n", heapPtr, block );
+ ret = FALSE;
+ } else
+ ret = HEAP_ValidateInUseArena( subheap, (ARENA_INUSE *)block - 1, quiet );
+
+ if (!(flags & HEAP_NO_SERIALIZE))
+ RtlLeaveCriticalSection( &heapPtr->critSection );
+ return ret;
+ }
+
+ subheap = &heapPtr->subheap;
+ while (subheap && ret)
+ {
+ char *ptr = (char *)subheap + subheap->headerSize;
+ while (ptr < (char *)subheap + subheap->size)
+ {
+ if (*(DWORD *)ptr & ARENA_FLAG_FREE)
+ {
+ if (!HEAP_ValidateFreeArena( subheap, (ARENA_FREE *)ptr )) {
+ ret = FALSE;
+ break;
+ }
+ ptr += sizeof(ARENA_FREE) + (*(DWORD *)ptr & ARENA_SIZE_MASK);
+ }
+ else
+ {
+ if (!HEAP_ValidateInUseArena( subheap, (ARENA_INUSE *)ptr, NOISY )) {
+ ret = FALSE;
+ break;
+ }
+ ptr += sizeof(ARENA_INUSE) + (*(DWORD *)ptr & ARENA_SIZE_MASK);
+ }
+ }
+ subheap = subheap->next;
+ }
+
+ if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection );
+ return ret;
+}
+
+
+/***********************************************************************
+ * RtlCreateHeap (NTDLL.@)
+ */
+HANDLE WINAPI RtlCreateHeap( ULONG flags, PVOID addr, ULONG totalSize, ULONG commitSize,
+ PVOID unknown, PRTL_HEAP_DEFINITION definition )
+{
+ SUBHEAP *subheap;
+
+ /* Allocate the heap block */
+
+ if (!totalSize)
+ {
+ totalSize = HEAP_DEF_SIZE;
+ flags |= HEAP_GROWABLE;
+ }
+ /* round up sizes */
+ totalSize = (totalSize + 0xffff) & 0xffff0000;
+ commitSize = (commitSize + 0xffff) & 0xffff0000;
+ if (!commitSize) commitSize = 0x10000;
+ if (totalSize < commitSize) totalSize = commitSize;
+
+ if (!(subheap = HEAP_CreateSubHeap( NULL, addr, flags, commitSize, totalSize ))) return 0;
+
+ /* link it into the per-process heap list */
+ if (processHeap)
+ {
+ HEAP *heapPtr = subheap->heap;
+ RtlLockHeap( processHeap );
+ heapPtr->next = firstHeap;
+ firstHeap = heapPtr;
+ RtlUnlockHeap( processHeap );
+ }
+ else /* assume the first heap we create is the process main heap */
+ {
+ set_process_heap( (HANDLE)subheap->heap );
+ }
+ return (HANDLE)subheap;
+}
+
+
+/***********************************************************************
+ * RtlDestroyHeap (NTDLL.@)
+ */
+HANDLE WINAPI RtlDestroyHeap( HANDLE heap )
+{
+ HEAP *heapPtr = HEAP_GetPtr( heap );
+ SUBHEAP *subheap;
+
+ TRACE("%08x\n", heap );
+ if (!heapPtr) return heap;
+
+ if (heap == processHeap) return heap; /* cannot delete the main process heap */
+ else /* remove it from the per-process list */
+ {
+ HEAP **pptr;
+ RtlLockHeap( processHeap );
+ pptr = &firstHeap;
+ while (*pptr && *pptr != heapPtr) pptr = &(*pptr)->next;
+ if (*pptr) *pptr = (*pptr)->next;
+ RtlUnlockHeap( processHeap );
+ }
+
+ RtlDeleteCriticalSection( &heapPtr->critSection );
+ subheap = &heapPtr->subheap;
+ while (subheap)
+ {
+ SUBHEAP *next = subheap->next;
+ VirtualFree( subheap, 0, MEM_RELEASE );
+ subheap = next;
+ }
+ return 0;
+}
+
+
+/***********************************************************************
+ * RtlAllocateHeap (NTDLL.@)
+ *
+ * NOTE: does not set last error.
+ */
+PVOID WINAPI RtlAllocateHeap( HANDLE heap, ULONG flags, ULONG size )
+{
+ ARENA_FREE *pArena;
+ ARENA_INUSE *pInUse;
+ SUBHEAP *subheap;
+ HEAP *heapPtr = HEAP_GetPtr( heap );
+
+ /* Validate the parameters */
+
+ if (!heapPtr) return NULL;
+ flags &= HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY;
+ flags |= heapPtr->flags;
+ size = (size + 3) & ~3;
+ if (size < HEAP_MIN_BLOCK_SIZE) size = HEAP_MIN_BLOCK_SIZE;
+
+ if (!(flags & HEAP_NO_SERIALIZE)) RtlEnterCriticalSection( &heapPtr->critSection );
+ /* Locate a suitable free block */
+
+ if (!(pArena = HEAP_FindFreeBlock( heapPtr, size, &subheap )))
+ {
+ TRACE("(%08x,%08lx,%08lx): returning NULL\n",
+ heap, flags, size );
+ if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection );
+ if (flags & HEAP_GENERATE_EXCEPTIONS) RtlRaiseStatus( STATUS_NO_MEMORY );
+ return NULL;
+ }
+
+ /* Remove the arena from the free list */
+
+ pArena->next->prev = pArena->prev;
+ pArena->prev->next = pArena->next;
+
+ /* Build the in-use arena */
+
+ pInUse = (ARENA_INUSE *)pArena;
+
+ /* in-use arena is smaller than free arena,
+ * so we have to add the difference to the size */
+ pInUse->size = (pInUse->size & ~ARENA_FLAG_FREE) + sizeof(ARENA_FREE) - sizeof(ARENA_INUSE);
+ pInUse->magic = ARENA_INUSE_MAGIC;
+
+ /* Shrink the block */
+
+ HEAP_ShrinkBlock( subheap, pInUse, size );
+
+ if (flags & HEAP_ZERO_MEMORY)
+ memset( pInUse + 1, 0, pInUse->size & ARENA_SIZE_MASK );
+ else if (TRACE_ON(heap))
+ memset( pInUse + 1, ARENA_INUSE_FILLER, pInUse->size & ARENA_SIZE_MASK );
+
+ if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection );
+
+ TRACE("(%08x,%08lx,%08lx): returning %08lx\n",
+ heap, flags, size, (DWORD)(pInUse + 1) );
+ return (LPVOID)(pInUse + 1);
+}
+
+
+/***********************************************************************
+ * RtlFreeHeap (NTDLL.@)
+ */
+BOOLEAN WINAPI RtlFreeHeap( HANDLE heap, ULONG flags, PVOID ptr )
+{
+ ARENA_INUSE *pInUse;
+ SUBHEAP *subheap;
+ HEAP *heapPtr = HEAP_GetPtr( heap );
+
+ /* Validate the parameters */
+
+ if (!ptr) return TRUE; /* freeing a NULL ptr isn't an error in Win2k */
+ if (!heapPtr)
+ {
+ set_status( STATUS_INVALID_HANDLE );
+ return FALSE;
+ }
+
+ flags &= HEAP_NO_SERIALIZE;
+ flags |= heapPtr->flags;
+ if (!(flags & HEAP_NO_SERIALIZE)) RtlEnterCriticalSection( &heapPtr->critSection );
+ if (!HEAP_IsRealArena( heapPtr, HEAP_NO_SERIALIZE, ptr, QUIET ))
+ {
+ if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection );
+ set_status( STATUS_INVALID_PARAMETER );
+ TRACE("(%08x,%08lx,%08lx): returning FALSE\n",
+ heap, flags, (DWORD)ptr );
+ return FALSE;
+ }
+
+ /* Turn the block into a free block */
+
+ pInUse = (ARENA_INUSE *)ptr - 1;
+ subheap = HEAP_FindSubHeap( heapPtr, pInUse );
+ HEAP_MakeInUseBlockFree( subheap, pInUse );
+
+ if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection );
+
+ TRACE("(%08x,%08lx,%08lx): returning TRUE\n",
+ heap, flags, (DWORD)ptr );
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * RtlReAllocateHeap (NTDLL.@)
+ */
+PVOID WINAPI RtlReAllocateHeap( HANDLE heap, ULONG flags, PVOID ptr, ULONG size )
+{
+ ARENA_INUSE *pArena;
+ DWORD oldSize;
+ HEAP *heapPtr;
+ SUBHEAP *subheap;
+
+ if (!ptr) return RtlAllocateHeap( heap, flags, size ); /* FIXME: correct? */
+ if (!(heapPtr = HEAP_GetPtr( heap )))
+ {
+ set_status( STATUS_INVALID_HANDLE );
+ return FALSE;
+ }
+
+ /* Validate the parameters */
+
+ flags &= HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY |
+ HEAP_REALLOC_IN_PLACE_ONLY;
+ flags |= heapPtr->flags;
+ size = (size + 3) & ~3;
+ if (size < HEAP_MIN_BLOCK_SIZE) size = HEAP_MIN_BLOCK_SIZE;
+
+ if (!(flags & HEAP_NO_SERIALIZE)) RtlEnterCriticalSection( &heapPtr->critSection );
+ if (!HEAP_IsRealArena( heapPtr, HEAP_NO_SERIALIZE, ptr, QUIET ))
+ {
+ if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection );
+ set_status( STATUS_INVALID_PARAMETER );
+ TRACE("(%08x,%08lx,%08lx,%08lx): returning NULL\n",
+ heap, flags, (DWORD)ptr, size );
+ return NULL;
+ }
+
+ /* Check if we need to grow the block */
+
+ pArena = (ARENA_INUSE *)ptr - 1;
+ subheap = HEAP_FindSubHeap( heapPtr, pArena );
+ oldSize = (pArena->size & ARENA_SIZE_MASK);
+ if (size > oldSize)
+ {
+ char *pNext = (char *)(pArena + 1) + oldSize;
+ if ((pNext < (char *)subheap + subheap->size) &&
+ (*(DWORD *)pNext & ARENA_FLAG_FREE) &&
+ (oldSize + (*(DWORD *)pNext & ARENA_SIZE_MASK) + sizeof(ARENA_FREE) >= size))
+ {
+ /* The next block is free and large enough */
+ ARENA_FREE *pFree = (ARENA_FREE *)pNext;
+ pFree->next->prev = pFree->prev;
+ pFree->prev->next = pFree->next;
+ pArena->size += (pFree->size & ARENA_SIZE_MASK) + sizeof(*pFree);
+ if (!HEAP_Commit( subheap, (char *)pArena + sizeof(ARENA_INUSE)
+ + size + HEAP_MIN_BLOCK_SIZE))
+ {
+ if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection );
+ if (flags & HEAP_GENERATE_EXCEPTIONS) RtlRaiseStatus( STATUS_NO_MEMORY );
+ set_status( STATUS_NO_MEMORY );
+ return NULL;
+ }
+ HEAP_ShrinkBlock( subheap, pArena, size );
+ }
+ else /* Do it the hard way */
+ {
+ ARENA_FREE *pNew;
+ ARENA_INUSE *pInUse;
+ SUBHEAP *newsubheap;
+
+ if ((flags & HEAP_REALLOC_IN_PLACE_ONLY) ||
+ !(pNew = HEAP_FindFreeBlock( heapPtr, size, &newsubheap )))
+ {
+ if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection );
+ if (flags & HEAP_GENERATE_EXCEPTIONS) RtlRaiseStatus( STATUS_NO_MEMORY );
+ set_status( STATUS_NO_MEMORY );
+ return NULL;
+ }
+
+ /* Build the in-use arena */
+
+ pNew->next->prev = pNew->prev;
+ pNew->prev->next = pNew->next;
+ pInUse = (ARENA_INUSE *)pNew;
+ pInUse->size = (pInUse->size & ~ARENA_FLAG_FREE)
+ + sizeof(ARENA_FREE) - sizeof(ARENA_INUSE);
+ pInUse->magic = ARENA_INUSE_MAGIC;
+ HEAP_ShrinkBlock( newsubheap, pInUse, size );
+ memcpy( pInUse + 1, pArena + 1, oldSize );
+
+ /* Free the previous block */
+
+ HEAP_MakeInUseBlockFree( subheap, pArena );
+ subheap = newsubheap;
+ pArena = pInUse;
+ }
+ }
+ else HEAP_ShrinkBlock( subheap, pArena, size ); /* Shrink the block */
+
+ /* Clear the extra bytes if needed */
+
+ if (size > oldSize)
+ {
+ if (flags & HEAP_ZERO_MEMORY)
+ memset( (char *)(pArena + 1) + oldSize, 0,
+ (pArena->size & ARENA_SIZE_MASK) - oldSize );
+ else if (TRACE_ON(heap))
+ memset( (char *)(pArena + 1) + oldSize, ARENA_INUSE_FILLER,
+ (pArena->size & ARENA_SIZE_MASK) - oldSize );
+ }
+
+ /* Return the new arena */
+
+ if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection );
+
+ TRACE("(%08x,%08lx,%08lx,%08lx): returning %08lx\n",
+ heap, flags, (DWORD)ptr, size, (DWORD)(pArena + 1) );
+ return (LPVOID)(pArena + 1);
+}
+
+
+/***********************************************************************
+ * RtlCompactHeap (NTDLL.@)
+ */
+ULONG WINAPI RtlCompactHeap( HANDLE heap, ULONG flags )
+{
+ FIXME( "stub\n" );
+ return 0;
+}
+
+
+/***********************************************************************
+ * RtlLockHeap (NTDLL.@)
+ */
+BOOLEAN WINAPI RtlLockHeap( HANDLE heap )
+{
+ HEAP *heapPtr = HEAP_GetPtr( heap );
+ if (!heapPtr) return FALSE;
+ RtlEnterCriticalSection( &heapPtr->critSection );
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * RtlUnlockHeap (NTDLL.@)
+ */
+BOOLEAN WINAPI RtlUnlockHeap( HANDLE heap )
+{
+ HEAP *heapPtr = HEAP_GetPtr( heap );
+ if (!heapPtr) return FALSE;
+ RtlLeaveCriticalSection( &heapPtr->critSection );
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * RtlSizeHeap (NTDLL.@)
+ */
+ULONG WINAPI RtlSizeHeap( HANDLE heap, ULONG flags, PVOID ptr )
+{
+ DWORD ret;
+ HEAP *heapPtr = HEAP_GetPtr( heap );
+
+ if (!heapPtr)
+ {
+ set_status( STATUS_INVALID_HANDLE );
+ return (ULONG)-1;
+ }
+ flags &= HEAP_NO_SERIALIZE;
+ flags |= heapPtr->flags;
+ if (!(flags & HEAP_NO_SERIALIZE)) RtlEnterCriticalSection( &heapPtr->critSection );
+ if (!HEAP_IsRealArena( heapPtr, HEAP_NO_SERIALIZE, ptr, QUIET ))
+ {
+ set_status( STATUS_INVALID_PARAMETER );
+ ret = (ULONG)-1;
+ }
+ else
+ {
+ ARENA_INUSE *pArena = (ARENA_INUSE *)ptr - 1;
+ ret = pArena->size & ARENA_SIZE_MASK;
+ }
+ if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection );
+
+ TRACE("(%08x,%08lx,%08lx): returning %08lx\n",
+ heap, flags, (DWORD)ptr, ret );
+ return ret;
+}
+
+
+/***********************************************************************
+ * RtlValidateHeap (NTDLL.@)
+ */
+BOOLEAN WINAPI RtlValidateHeap( HANDLE heap, ULONG flags, PCVOID block )
+{
+ HEAP *heapPtr = HEAP_GetPtr( heap );
+ if (!heapPtr) return FALSE;
+ return HEAP_IsRealArena( heapPtr, flags, block, QUIET );
+}
+
+
+/***********************************************************************
+ * RtlWalkHeap (NTDLL.@)
+ *
+ * FIXME: the PROCESS_HEAP_ENTRY flag values seem different between this
+ * function and HeapWalk. To be checked.
+ */
+NTSTATUS WINAPI RtlWalkHeap( HANDLE heap, PVOID entry_ptr )
+{
+ LPPROCESS_HEAP_ENTRY entry = entry_ptr; /* FIXME */
+ HEAP *heapPtr = HEAP_GetPtr(heap);
+ SUBHEAP *sub, *currentheap = NULL;
+ NTSTATUS ret;
+ char *ptr;
+ int region_index = 0;
+
+ FIXME( "not fully compatible\n" );
+
+ if (!heapPtr || !entry) return STATUS_INVALID_PARAMETER;
+
+ if (!(heapPtr->flags & HEAP_NO_SERIALIZE)) EnterCriticalSection( &heapPtr->critSection );
+
+ /* set ptr to the next arena to be examined */
+
+ if (!entry->lpData) /* first call (init) ? */
+ {
+ TRACE("begin walking of heap 0x%08x.\n", heap);
+ currentheap = &heapPtr->subheap;
+ ptr = (char*)currentheap + currentheap->headerSize;
+ }
+ else
+ {
+ ptr = entry->lpData;
+ sub = &heapPtr->subheap;
+ while (sub)
+ {
+ if (((char *)ptr >= (char *)sub) &&
+ ((char *)ptr < (char *)sub + sub->size))
+ {
+ currentheap = sub;
+ break;
+ }
+ sub = sub->next;
+ region_index++;
+ }
+ if (currentheap == NULL)
+ {
+ ERR("no matching subheap found, shouldn't happen !\n");
+ ret = STATUS_NO_MORE_ENTRIES;
+ goto HW_end;
+ }
+
+ ptr += entry->cbData; /* point to next arena */
+ if (ptr > (char *)currentheap + currentheap->size - 1)
+ { /* proceed with next subheap */
+ if (!(currentheap = currentheap->next))
+ { /* successfully finished */
+ TRACE("end reached.\n");
+ ret = STATUS_NO_MORE_ENTRIES;
+ goto HW_end;
+ }
+ ptr = (char*)currentheap + currentheap->headerSize;
+ }
+ }
+
+ entry->wFlags = 0;
+ if (*(DWORD *)ptr & ARENA_FLAG_FREE)
+ {
+ ARENA_FREE *pArena = (ARENA_FREE *)ptr;
+
+ /*TRACE("free, magic: %04x\n", pArena->magic);*/
+
+ entry->lpData = pArena + 1;
+ entry->cbData = pArena->size & ARENA_SIZE_MASK;
+ entry->cbOverhead = sizeof(ARENA_FREE);
+ entry->wFlags = PROCESS_HEAP_UNCOMMITTED_RANGE;
+ }
+ else
+ {
+ ARENA_INUSE *pArena = (ARENA_INUSE *)ptr;
+
+ /*TRACE("busy, magic: %04x\n", pArena->magic);*/
+
+ entry->lpData = pArena + 1;
+ entry->cbData = pArena->size & ARENA_SIZE_MASK;
+ entry->cbOverhead = sizeof(ARENA_INUSE);
+ entry->wFlags = PROCESS_HEAP_ENTRY_BUSY;
+ /* FIXME: can't handle PROCESS_HEAP_ENTRY_MOVEABLE
+ and PROCESS_HEAP_ENTRY_DDESHARE yet */
+ }
+
+ entry->iRegionIndex = region_index;
+
+ /* first element of heap ? */
+ if (ptr == (char *)(currentheap + currentheap->headerSize))
+ {
+ entry->wFlags |= PROCESS_HEAP_REGION;
+ entry->u.Region.dwCommittedSize = currentheap->commitSize;
+ entry->u.Region.dwUnCommittedSize =
+ currentheap->size - currentheap->commitSize;
+ entry->u.Region.lpFirstBlock = /* first valid block */
+ currentheap + currentheap->headerSize;
+ entry->u.Region.lpLastBlock = /* first invalid block */
+ currentheap + currentheap->size;
+ }
+ ret = STATUS_SUCCESS;
+
+HW_end:
+ if (!(heapPtr->flags & HEAP_NO_SERIALIZE)) LeaveCriticalSection( &heapPtr->critSection );
+ return ret;
+}
+
+
+/***********************************************************************
+ * RtlGetProcessHeaps (NTDLL.@)
+ */
+ULONG WINAPI RtlGetProcessHeaps( ULONG count, HANDLE *heaps )
+{
+ DWORD total;
+ HEAP *ptr;
+
+ if (!processHeap) return 0; /* should never happen */
+ total = 1; /* main heap */
+ RtlLockHeap( processHeap );
+ for (ptr = firstHeap; ptr; ptr = ptr->next) total++;
+ if (total <= count)
+ {
+ *heaps++ = (HANDLE)processHeap;
+ for (ptr = firstHeap; ptr; ptr = ptr->next) *heaps++ = (HANDLE)ptr;
+ }
+ RtlUnlockHeap( processHeap );
+ return total;
+}
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index 3ac3485..8e055fa 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -300,7 +300,7 @@
@ stub RtlCheckRegistryKey
@ stub RtlClearAllBits
@ stdcall RtlClearBits(long long long) RtlClearBits
-@ stub RtlCompactHeap
+@ stdcall RtlCompactHeap(long long) RtlCompactHeap
@ stdcall RtlCompareMemory(ptr ptr long) RtlCompareMemory
@ stub RtlCompareMemoryUlong
@ stdcall RtlCompareString(ptr ptr long) RtlCompareString
@@ -406,7 +406,7 @@
@ stub RtlGetNtGlobalFlags
@ stdcall RtlGetNtProductType(ptr) RtlGetNtProductType
@ stdcall RtlGetOwnerSecurityDescriptor(ptr ptr ptr) RtlGetOwnerSecurityDescriptor
-@ stub RtlGetProcessHeaps
+@ stdcall RtlGetProcessHeaps(long ptr) RtlGetProcessHeaps
@ stdcall RtlGetSaclSecurityDescriptor(ptr ptr ptr ptr)RtlGetSaclSecurityDescriptor
@ stub RtlGetUserInfoHeap
@ stdcall RtlIdentifierAuthoritySid(ptr) RtlIdentifierAuthoritySid
@@ -446,7 +446,7 @@
@ stdcall RtlLengthSecurityDescriptor(ptr) RtlLengthSecurityDescriptor
@ stdcall RtlLengthSid(ptr) RtlLengthSid
@ stub RtlLocalTimeToSystemTime
-@ stub RtlLockHeap
+@ stdcall RtlLockHeap(long) RtlLockHeap
@ stub RtlLookupElementGenericTable
@ stdcall RtlMakeSelfRelativeSD(ptr ptr ptr) RtlMakeSelfRelativeSD
@ stub RtlMapGenericMask
@@ -482,7 +482,7 @@
@ stdcall RtlRaiseException(ptr) RtlRaiseException
@ stdcall RtlRaiseStatus(long) RtlRaiseStatus
@ stub RtlRandom
-@ stub RtlReAllocateHeap
+@ stdcall RtlReAllocateHeap(long long ptr long) RtlReAllocateHeap
@ stub RtlRealPredecessor
@ stub RtlRealSuccessor
@ stdcall RtlReleasePebLock() RtlReleasePebLock
@@ -508,7 +508,7 @@
@ stub RtlSetTimeZoneInformation
@ stub RtlSetUserFlagsHeap
@ stub RtlSetUserValueHeap
-@ stdcall RtlSizeHeap(long long long) HeapSize
+@ stdcall RtlSizeHeap(long long ptr) RtlSizeHeap
@ stub RtlSplay
@ stub RtlStartRXact
@ stdcall RtlSubAuthorityCountSid(ptr) RtlSubAuthorityCountSid
@@ -532,7 +532,7 @@
@ stdcall RtlUnicodeToMultiByteSize(ptr wstr long) RtlUnicodeToMultiByteSize
@ stdcall RtlUnicodeToOemN(ptr long ptr ptr long) RtlUnicodeToOemN
@ stub RtlUniform
-@ stub RtlUnlockHeap
+@ stdcall RtlUnlockHeap(long) RtlUnlockHeap
@ stdcall RtlUnwind(ptr ptr ptr long) RtlUnwind
@ stub RtlUpcaseUnicodeChar
@ stdcall RtlUpcaseUnicodeString(ptr ptr long) RtlUpcaseUnicodeString
@@ -548,9 +548,9 @@
@ stub RtlValidAcl
@ stdcall RtlValidSecurityDescriptor(ptr) RtlValidSecurityDescriptor
@ stdcall RtlValidSid(ptr) RtlValidSid
-@ stub RtlValidateHeap
+@ stdcall RtlValidateHeap(long long ptr) RtlValidateHeap
@ stub RtlValidateProcessHeaps
-@ stub RtlWalkHeap
+@ stdcall RtlWalkHeap(long ptr) RtlWalkHeap
@ stub RtlWriteRegistryValue
@ stub RtlZeroHeap
@ stdcall RtlZeroMemory(ptr long) RtlZeroMemory
diff --git a/dlls/ntdll/rtl.c b/dlls/ntdll/rtl.c
index 4311ea2..a6cf39d 100644
--- a/dlls/ntdll/rtl.c
+++ b/dlls/ntdll/rtl.c
@@ -213,64 +213,6 @@
}
/*
- * heap functions
- */
-
-/******************************************************************************
- * RtlCreateHeap [NTDLL.@]
- */
-HANDLE WINAPI RtlCreateHeap(
- ULONG Flags,
- PVOID BaseAddress,
- ULONG SizeToReserve,
- ULONG SizeToCommit,
- PVOID Unknown,
- PRTL_HEAP_DEFINITION Definition)
-{
- FIXME("(0x%08lx, %p, 0x%08lx, 0x%08lx, %p, %p) semi-stub\n",
- Flags, BaseAddress, SizeToReserve, SizeToCommit, Unknown, Definition);
-
- return HeapCreate ( Flags, SizeToCommit, SizeToReserve);
-
-}
-/******************************************************************************
- * RtlAllocateHeap [NTDLL.@]
- */
-PVOID WINAPI RtlAllocateHeap(
- HANDLE Heap,
- ULONG Flags,
- ULONG Size)
-{
- TRACE("(0x%08x, 0x%08lx, 0x%08lx) semi stub\n",
- Heap, Flags, Size);
- return HeapAlloc(Heap, Flags, Size);
-}
-
-/******************************************************************************
- * RtlFreeHeap [NTDLL.@]
- */
-BOOLEAN WINAPI RtlFreeHeap(
- HANDLE Heap,
- ULONG Flags,
- PVOID Address)
-{
- TRACE("(0x%08x, 0x%08lx, %p) semi stub\n",
- Heap, Flags, Address);
- return HeapFree(Heap, Flags, Address);
-}
-
-/******************************************************************************
- * RtlDestroyHeap [NTDLL.@]
- */
-HANDLE WINAPI RtlDestroyHeap(
- HANDLE Heap)
-{
- TRACE("(0x%08x) semi stub\n", Heap);
- if (!HeapDestroy(Heap)) return Heap;
- return 0;
-}
-
-/*
* misc functions
*/
diff --git a/dlls/ole32/ifs.c b/dlls/ole32/ifs.c
index 6d8c042..6531d4a 100644
--- a/dlls/ole32/ifs.c
+++ b/dlls/ole32/ifs.c
@@ -143,25 +143,32 @@
SEGPTR WINAPI IMalloc16_fnAlloc(IMalloc16* iface,DWORD cb) {
ICOM_THIS(IMalloc16Impl,iface);
TRACE("(%p)->Alloc(%ld)\n",This,cb);
- return MapLS( HeapAlloc( GetProcessHeap(), HEAP_WINE_SEGPTR, cb ) );
+ return MapLS( HeapAlloc( GetProcessHeap(), 0, cb ) );
}
/******************************************************************************
* IMalloc16_Realloc [COMPOBJ.504]
*/
-SEGPTR WINAPI IMalloc16_fnRealloc(IMalloc16* iface,SEGPTR pv,DWORD cb) {
- ICOM_THIS(IMalloc16Impl,iface);
- TRACE("(%p)->Realloc(%08lx,%ld)\n",This,pv,cb);
- return MapLS( HeapReAlloc( GetProcessHeap(), HEAP_WINE_SEGPTR, MapSL(pv), cb ) );
+SEGPTR WINAPI IMalloc16_fnRealloc(IMalloc16* iface,SEGPTR pv,DWORD cb)
+{
+ SEGPTR ret;
+ ICOM_THIS(IMalloc16Impl,iface);
+ TRACE("(%p)->Realloc(%08lx,%ld)\n",This,pv,cb);
+ ret = MapLS( HeapReAlloc( GetProcessHeap(), 0, MapSL(pv), cb ) );
+ UnMapLS(pv);
+ return ret;
}
/******************************************************************************
* IMalloc16_Free [COMPOBJ.505]
*/
-VOID WINAPI IMalloc16_fnFree(IMalloc16* iface,SEGPTR pv) {
- ICOM_THIS(IMalloc16Impl,iface);
- TRACE("(%p)->Free(%08lx)\n",This,pv);
- HeapFree( GetProcessHeap(), HEAP_WINE_SEGPTR, MapSL(pv) );
+VOID WINAPI IMalloc16_fnFree(IMalloc16* iface,SEGPTR pv)
+{
+ void *ptr = MapSL(pv);
+ ICOM_THIS(IMalloc16Impl,iface);
+ TRACE("(%p)->Free(%08lx)\n",This,pv);
+ UnMapLS(pv);
+ HeapFree( GetProcessHeap(), 0, ptr );
}
/******************************************************************************
@@ -171,7 +178,7 @@
{
ICOM_CTHIS(IMalloc16Impl,iface);
TRACE("(%p)->GetSize(%08lx)\n",This,pv);
- return HeapSize( GetProcessHeap(), HEAP_WINE_SEGPTR, MapSL(pv) );
+ return HeapSize( GetProcessHeap(), 0, MapSL(pv) );
}
/******************************************************************************
diff --git a/graphics/win16drv/font.c b/graphics/win16drv/font.c
index b6ad490..5ebe6e1 100644
--- a/graphics/win16drv/font.c
+++ b/graphics/win16drv/font.c
@@ -95,7 +95,7 @@
&physDev->lf, 0, 0);
if( physDev->FontInfo &&
- HeapSize( GetProcessHeap(), HEAP_WINE_SEGPTR, physDev->FontInfo ) < nSize )
+ HeapSize( GetProcessHeap(), 0, physDev->FontInfo ) < nSize )
{
SEGPTR_FREE( physDev->FontInfo );
physDev->FontInfo = NULL;
diff --git a/include/heap.h b/include/heap.h
index b9fc6fc..4830554 100644
--- a/include/heap.h
+++ b/include/heap.h
@@ -14,18 +14,16 @@
#include "wine/unicode.h"
#include "wine/windef16.h" /* for SEGPTR */
-extern SEGPTR HEAP_GetSegptr( HANDLE heap, DWORD flags, LPCVOID ptr );
-
/* SEGPTR helper macros */
#define SEGPTR_ALLOC(size) \
- (HeapAlloc( GetProcessHeap(), HEAP_WINE_SEGPTR, (size) ))
+ (HeapAlloc( GetProcessHeap(), 0, (size) ))
#define SEGPTR_NEW(type) \
- ((type *)HeapAlloc( GetProcessHeap(), HEAP_WINE_SEGPTR, sizeof(type) ))
+ ((type *)HeapAlloc( GetProcessHeap(), 0, sizeof(type) ))
#define SEGPTR_STRDUP_WtoA(str) \
- (HIWORD(str) ? HEAP_strdupWtoA( GetProcessHeap(), HEAP_WINE_SEGPTR, (str) ) : (LPSTR)(str))
+ (HIWORD(str) ? HEAP_strdupWtoA( GetProcessHeap(), 0, (str) ) : (LPSTR)(str))
#define SEGPTR_FREE(ptr) \
- (HIWORD(ptr) ? HeapFree( GetProcessHeap(), HEAP_WINE_SEGPTR, (ptr) ) : 0)
+ (HIWORD(ptr) ? HeapFree( GetProcessHeap(), 0, (ptr) ) : 0)
#define SEGPTR_GET(ptr) MapLS(ptr)
inline static LPSTR SEGPTR_STRDUP( LPCSTR str )
@@ -33,7 +31,7 @@
if (HIWORD(str))
{
INT len = strlen(str) + 1;
- LPSTR p = HeapAlloc( GetProcessHeap(), HEAP_WINE_SEGPTR, len );
+ LPSTR p = HeapAlloc( GetProcessHeap(), 0, len );
if (p) memcpy( p, str, len );
return p;
}
diff --git a/include/ntddk.h b/include/ntddk.h
index 9977c51..a4cd777 100644
--- a/include/ntddk.h
+++ b/include/ntddk.h
@@ -723,6 +723,7 @@
ULONG WINAPI RtlSizeHeap(HANDLE,ULONG,PVOID);
BOOLEAN WINAPI RtlValidateHeap(HANDLE,ULONG,PCVOID);
ULONG WINAPI RtlGetProcessHeaps(ULONG,HANDLE*);
+NTSTATUS WINAPI RtlWalkHeap(HANDLE,PVOID);
/* exception */
diff --git a/include/winbase.h b/include/winbase.h
index 9355baf..388dda8 100644
--- a/include/winbase.h
+++ b/include/winbase.h
@@ -985,20 +985,33 @@
/*int WinMain(HINSTANCE, HINSTANCE prev, char *cmd, int show);*/
-LONG WINAPI RtlEnterCriticalSection( CRITICAL_SECTION *crit );
-LONG WINAPI RtlLeaveCriticalSection( CRITICAL_SECTION *crit );
-LONG WINAPI RtlDeleteCriticalSection( CRITICAL_SECTION *crit );
-BOOL WINAPI RtlTryEnterCriticalSection( CRITICAL_SECTION *crit );
-/* FIXME: need to use defines because we don't have proper imports yet */
+/* FIXME: need to use defines because we don't have proper imports everywhere yet */
+#ifndef have_proper_imports
+LONG WINAPI RtlEnterCriticalSection( CRITICAL_SECTION *crit );
+LONG WINAPI RtlLeaveCriticalSection( CRITICAL_SECTION *crit );
+LONG WINAPI RtlDeleteCriticalSection( CRITICAL_SECTION *crit );
+BOOL WINAPI RtlTryEnterCriticalSection( CRITICAL_SECTION *crit );
+PVOID WINAPI RtlAllocateHeap(HANDLE,ULONG,ULONG);
+BOOLEAN WINAPI RtlFreeHeap(HANDLE,ULONG,PVOID);
+PVOID WINAPI RtlReAllocateHeap(HANDLE,ULONG,PVOID,ULONG);
+ULONG WINAPI RtlSizeHeap(HANDLE,ULONG,PVOID);
+#define HeapAlloc(heap,flags,size) RtlAllocateHeap(heap,flags,size)
+#define HeapFree(heap,flags,ptr) RtlFreeHeap(heap,flags,ptr)
+#define HeapReAlloc(heap,flags,ptr,size) RtlReAllocateHeap(heap,flags,ptr,size)
+#define HeapSize(heap,flags,ptr) RtlSizeHeap(heap,flags,ptr)
#define EnterCriticalSection(crit) RtlEnterCriticalSection(crit)
#define LeaveCriticalSection(crit) RtlLeaveCriticalSection(crit)
#define DeleteCriticalSection(crit) RtlDeleteCriticalSection(crit)
#define TryEnterCriticalSection(crit) RtlTryEnterCriticalSection(crit)
-#if 0
-void WINAPI DeleteCriticalSection(CRITICAL_SECTION *lpCrit);
-void WINAPI EnterCriticalSection(CRITICAL_SECTION *lpCrit);
-BOOL WINAPI TryEnterCriticalSection(CRITICAL_SECTION *lpCrit);
-void WINAPI LeaveCriticalSection(CRITICAL_SECTION *lpCrit);
+#else
+LPVOID WINAPI HeapAlloc(HANDLE,DWORD,DWORD);
+BOOL WINAPI HeapFree(HANDLE,DWORD,LPVOID);
+LPVOID WINAPI HeapReAlloc(HANDLE,DWORD,LPVOID,DWORD);
+DWORD WINAPI HeapSize(HANDLE,DWORD,LPVOID);
+void WINAPI DeleteCriticalSection(CRITICAL_SECTION *lpCrit);
+void WINAPI EnterCriticalSection(CRITICAL_SECTION *lpCrit);
+BOOL WINAPI TryEnterCriticalSection(CRITICAL_SECTION *lpCrit);
+void WINAPI LeaveCriticalSection(CRITICAL_SECTION *lpCrit);
#endif
void WINAPI InitializeCriticalSection(CRITICAL_SECTION *lpCrit);
@@ -1237,14 +1250,10 @@
BOOL WINAPI GetUserNameW(LPWSTR,LPDWORD);
#define GetUserName WINELIB_NAME_AW(GetUserName)
VOID WINAPI GlobalMemoryStatus(LPMEMORYSTATUS);
-LPVOID WINAPI HeapAlloc(HANDLE,DWORD,DWORD);
DWORD WINAPI HeapCompact(HANDLE,DWORD);
HANDLE WINAPI HeapCreate(DWORD,DWORD,DWORD);
BOOL WINAPI HeapDestroy(HANDLE);
-BOOL WINAPI HeapFree(HANDLE,DWORD,LPVOID);
BOOL WINAPI HeapLock(HANDLE);
-LPVOID WINAPI HeapReAlloc(HANDLE,DWORD,LPVOID,DWORD);
-DWORD WINAPI HeapSize(HANDLE,DWORD,LPVOID);
BOOL WINAPI HeapUnlock(HANDLE);
BOOL WINAPI HeapValidate(HANDLE,DWORD,LPCVOID);
BOOL WINAPI HeapWalk(HANDLE,LPPROCESS_HEAP_ENTRY);
diff --git a/include/winnt.h b/include/winnt.h
index 172fa55..5064e50 100644
--- a/include/winnt.h
+++ b/include/winnt.h
@@ -524,11 +524,7 @@
/* This flag allows it to create heaps shared by all processes under win95,
FIXME: correct name */
-#define HEAP_SHARED 0x04000000
-
-#define HEAP_WINE_SEGPTR 0x10000000 /* Not a Win32 flag */
-#define HEAP_WINE_CODESEG 0x20000000 /* Not a Win32 flag */
-#define HEAP_WINE_CODE16SEG 0x40000000 /* Not a Win32 flag */
+#define HEAP_SHARED 0x04000000
/* Processor feature flags. */
#define PF_FLOATING_POINT_PRECISION_ERRATA 0
diff --git a/memory/heap.c b/memory/heap.c
index 9942330..bcf501f 100644
--- a/memory/heap.c
+++ b/memory/heap.c
@@ -12,1668 +12,24 @@
#include <stdio.h>
#include <string.h>
+#include "winbase.h"
#include "wine/winbase16.h"
+#include "winerror.h"
+#include "winnt.h"
+#include "ntddk.h"
#include "wine/unicode.h"
#include "selectors.h"
#include "global.h"
-#include "winbase.h"
-#include "winerror.h"
-#include "winnt.h"
-#include "heap.h"
+#include "thread.h"
#include "toolhelp.h"
#include "debugtools.h"
-#include "winnls.h"
DEFAULT_DEBUG_CHANNEL(heap);
-/* Note: the heap data structures are based on what Pietrek describes in his
- * book 'Windows 95 System Programming Secrets'. The layout is not exactly
- * the same, but could be easily adapted if it turns out some programs
- * require it.
- */
-
-typedef struct tagARENA_INUSE
-{
- DWORD size; /* Block size; must be the first field */
- WORD magic; /* Magic number */
- WORD threadId; /* Allocating thread id */
- void *callerEIP; /* EIP of caller upon allocation */
-} ARENA_INUSE;
-
-typedef struct tagARENA_FREE
-{
- DWORD size; /* Block size; must be the first field */
- WORD magic; /* Magic number */
- WORD threadId; /* Freeing thread id */
- struct tagARENA_FREE *next; /* Next free arena */
- struct tagARENA_FREE *prev; /* Prev free arena */
-} ARENA_FREE;
-
-#define ARENA_FLAG_FREE 0x00000001 /* flags OR'ed with arena size */
-#define ARENA_FLAG_PREV_FREE 0x00000002
-#define ARENA_SIZE_MASK 0xfffffffc
-#define ARENA_INUSE_MAGIC 0x4842 /* Value for arena 'magic' field */
-#define ARENA_FREE_MAGIC 0x4846 /* Value for arena 'magic' field */
-
-#define ARENA_INUSE_FILLER 0x55
-#define ARENA_FREE_FILLER 0xaa
-
-#define QUIET 1 /* Suppress messages */
-#define NOISY 0 /* Report all errors */
-
-#define HEAP_NB_FREE_LISTS 4 /* Number of free lists */
-
-/* Max size of the blocks on the free lists */
-static const DWORD HEAP_freeListSizes[HEAP_NB_FREE_LISTS] =
-{
- 0x20, 0x80, 0x200, 0xffffffff
-};
-
-typedef struct
-{
- DWORD size;
- ARENA_FREE arena;
-} FREE_LIST_ENTRY;
-
-struct tagHEAP;
-
-typedef struct tagSUBHEAP
-{
- DWORD size; /* Size of the whole sub-heap */
- DWORD commitSize; /* Committed size of the sub-heap */
- DWORD headerSize; /* Size of the heap header */
- struct tagSUBHEAP *next; /* Next sub-heap */
- struct tagHEAP *heap; /* Main heap structure */
- DWORD magic; /* Magic number */
- WORD selector; /* Selector for HEAP_WINE_SEGPTR heaps */
-} SUBHEAP;
-
-#define SUBHEAP_MAGIC ((DWORD)('S' | ('U'<<8) | ('B'<<16) | ('H'<<24)))
-
-typedef struct tagHEAP
-{
- SUBHEAP subheap; /* First sub-heap */
- struct tagHEAP *next; /* Next heap for this process */
- FREE_LIST_ENTRY freeList[HEAP_NB_FREE_LISTS]; /* Free lists */
- CRITICAL_SECTION critSection; /* Critical section for serialization */
- DWORD flags; /* Heap flags */
- DWORD magic; /* Magic number */
-} HEAP;
-
-#define HEAP_MAGIC ((DWORD)('H' | ('E'<<8) | ('A'<<16) | ('P'<<24)))
-
-#define HEAP_DEF_SIZE 0x110000 /* Default heap size = 1Mb + 64Kb */
-#define HEAP_MIN_BLOCK_SIZE (8+sizeof(ARENA_FREE)) /* Min. heap block size */
-#define COMMIT_MASK 0xffff /* bitmask for commit/decommit granularity */
-
-static HEAP *systemHeap; /* globally shared heap */
-static HEAP *processHeap; /* main process heap */
-static HEAP *segptrHeap; /* main segptr heap */
-static HEAP *firstHeap; /* head of secondary heaps list */
-
/* address where we try to map the system heap */
#define SYSTEM_HEAP_BASE ((void*)0x65430000)
-
-static BOOL HEAP_IsRealArena( HEAP *heapPtr, DWORD flags, LPCVOID block, BOOL quiet );
-
-#ifdef __GNUC__
-#define GET_EIP() (__builtin_return_address(0))
-#define SET_EIP(ptr) ((ARENA_INUSE*)(ptr) - 1)->callerEIP = GET_EIP()
-#else
-#define GET_EIP() 0
-#define SET_EIP(ptr) /* nothing */
-#endif /* __GNUC__ */
-
-/***********************************************************************
- * HEAP_Dump
- */
-void HEAP_Dump( HEAP *heap )
-{
- int i;
- SUBHEAP *subheap;
- char *ptr;
-
- DPRINTF( "Heap: %08lx\n", (DWORD)heap );
- DPRINTF( "Next: %08lx Sub-heaps: %08lx",
- (DWORD)heap->next, (DWORD)&heap->subheap );
- subheap = &heap->subheap;
- while (subheap->next)
- {
- DPRINTF( " -> %08lx", (DWORD)subheap->next );
- subheap = subheap->next;
- }
-
- DPRINTF( "\nFree lists:\n Block Stat Size Id\n" );
- for (i = 0; i < HEAP_NB_FREE_LISTS; i++)
- DPRINTF( "%08lx free %08lx %04x prev=%08lx next=%08lx\n",
- (DWORD)&heap->freeList[i].arena, heap->freeList[i].arena.size,
- heap->freeList[i].arena.threadId,
- (DWORD)heap->freeList[i].arena.prev,
- (DWORD)heap->freeList[i].arena.next );
-
- subheap = &heap->subheap;
- while (subheap)
- {
- DWORD freeSize = 0, usedSize = 0, arenaSize = subheap->headerSize;
- DPRINTF( "\n\nSub-heap %08lx: size=%08lx committed=%08lx\n",
- (DWORD)subheap, subheap->size, subheap->commitSize );
-
- DPRINTF( "\n Block Stat Size Id\n" );
- ptr = (char*)subheap + subheap->headerSize;
- while (ptr < (char *)subheap + subheap->size)
- {
- if (*(DWORD *)ptr & ARENA_FLAG_FREE)
- {
- ARENA_FREE *pArena = (ARENA_FREE *)ptr;
- DPRINTF( "%08lx free %08lx %04x prev=%08lx next=%08lx\n",
- (DWORD)pArena, pArena->size & ARENA_SIZE_MASK,
- pArena->threadId, (DWORD)pArena->prev,
- (DWORD)pArena->next);
- ptr += sizeof(*pArena) + (pArena->size & ARENA_SIZE_MASK);
- arenaSize += sizeof(ARENA_FREE);
- freeSize += pArena->size & ARENA_SIZE_MASK;
- }
- else if (*(DWORD *)ptr & ARENA_FLAG_PREV_FREE)
- {
- ARENA_INUSE *pArena = (ARENA_INUSE *)ptr;
- DPRINTF( "%08lx Used %08lx %04x back=%08lx EIP=%p\n",
- (DWORD)pArena, pArena->size & ARENA_SIZE_MASK,
- pArena->threadId, *((DWORD *)pArena - 1),
- pArena->callerEIP );
- ptr += sizeof(*pArena) + (pArena->size & ARENA_SIZE_MASK);
- arenaSize += sizeof(ARENA_INUSE);
- usedSize += pArena->size & ARENA_SIZE_MASK;
- }
- else
- {
- ARENA_INUSE *pArena = (ARENA_INUSE *)ptr;
- DPRINTF( "%08lx used %08lx %04x EIP=%p\n",
- (DWORD)pArena, pArena->size & ARENA_SIZE_MASK,
- pArena->threadId, pArena->callerEIP );
- ptr += sizeof(*pArena) + (pArena->size & ARENA_SIZE_MASK);
- arenaSize += sizeof(ARENA_INUSE);
- usedSize += pArena->size & ARENA_SIZE_MASK;
- }
- }
- DPRINTF( "\nTotal: Size=%08lx Committed=%08lx Free=%08lx Used=%08lx Arenas=%08lx (%ld%%)\n\n",
- subheap->size, subheap->commitSize, freeSize, usedSize,
- arenaSize, (arenaSize * 100) / subheap->size );
- subheap = subheap->next;
- }
-}
-
-
-/***********************************************************************
- * HEAP_GetPtr
- * RETURNS
- * Pointer to the heap
- * NULL: Failure
- */
-static HEAP *HEAP_GetPtr(
- HANDLE heap /* [in] Handle to the heap */
-) {
- HEAP *heapPtr = (HEAP *)heap;
- if (!heapPtr || (heapPtr->magic != HEAP_MAGIC))
- {
- ERR("Invalid heap %08x!\n", heap );
- SetLastError( ERROR_INVALID_HANDLE );
- return NULL;
- }
- if (TRACE_ON(heap) && !HEAP_IsRealArena( heapPtr, 0, NULL, NOISY ))
- {
- HEAP_Dump( heapPtr );
- assert( FALSE );
- SetLastError( ERROR_INVALID_HANDLE );
- return NULL;
- }
- return heapPtr;
-}
-
-
-/***********************************************************************
- * HEAP_InsertFreeBlock
- *
- * Insert a free block into the free list.
- */
-static void HEAP_InsertFreeBlock( HEAP *heap, ARENA_FREE *pArena )
-{
- FREE_LIST_ENTRY *pEntry = heap->freeList;
- while (pEntry->size < pArena->size) pEntry++;
- pArena->size |= ARENA_FLAG_FREE;
- pArena->next = pEntry->arena.next;
- pArena->next->prev = pArena;
- pArena->prev = &pEntry->arena;
- pEntry->arena.next = pArena;
-}
-
-
-/***********************************************************************
- * HEAP_FindSubHeap
- * Find the sub-heap containing a given address.
- *
- * RETURNS
- * Pointer: Success
- * NULL: Failure
- */
-static SUBHEAP *HEAP_FindSubHeap(
- HEAP *heap, /* [in] Heap pointer */
- LPCVOID ptr /* [in] Address */
-) {
- SUBHEAP *sub = &heap->subheap;
- while (sub)
- {
- if (((char *)ptr >= (char *)sub) &&
- ((char *)ptr < (char *)sub + sub->size)) return sub;
- sub = sub->next;
- }
- return NULL;
-}
-
-
-/***********************************************************************
- * HEAP_Commit
- *
- * Make sure the heap storage is committed up to (not including) ptr.
- */
-static inline BOOL HEAP_Commit( SUBHEAP *subheap, void *ptr )
-{
- DWORD size = (DWORD)((char *)ptr - (char *)subheap);
- size = (size + COMMIT_MASK) & ~COMMIT_MASK;
- if (size > subheap->size) size = subheap->size;
- if (size <= subheap->commitSize) return TRUE;
- if (!VirtualAlloc( (char *)subheap + subheap->commitSize,
- size - subheap->commitSize, MEM_COMMIT,
- PAGE_EXECUTE_READWRITE))
- {
- WARN("Could not commit %08lx bytes at %08lx for heap %08lx\n",
- size - subheap->commitSize,
- (DWORD)((char *)subheap + subheap->commitSize),
- (DWORD)subheap->heap );
- return FALSE;
- }
- subheap->commitSize = size;
- return TRUE;
-}
-
-
-/***********************************************************************
- * HEAP_Decommit
- *
- * If possible, decommit the heap storage from (including) 'ptr'.
- */
-static inline BOOL HEAP_Decommit( SUBHEAP *subheap, void *ptr )
-{
- DWORD size = (DWORD)((char *)ptr - (char *)subheap);
- /* round to next block and add one full block */
- size = ((size + COMMIT_MASK) & ~COMMIT_MASK) + COMMIT_MASK + 1;
- if (size >= subheap->commitSize) return TRUE;
- if (!VirtualFree( (char *)subheap + size,
- subheap->commitSize - size, MEM_DECOMMIT ))
- {
- WARN("Could not decommit %08lx bytes at %08lx for heap %08lx\n",
- subheap->commitSize - size,
- (DWORD)((char *)subheap + size),
- (DWORD)subheap->heap );
- return FALSE;
- }
- subheap->commitSize = size;
- return TRUE;
-}
-
-
-/***********************************************************************
- * HEAP_CreateFreeBlock
- *
- * Create a free block at a specified address. 'size' is the size of the
- * whole block, including the new arena.
- */
-static void HEAP_CreateFreeBlock( SUBHEAP *subheap, void *ptr, DWORD size )
-{
- ARENA_FREE *pFree;
-
- /* Create a free arena */
-
- pFree = (ARENA_FREE *)ptr;
- pFree->threadId = GetCurrentTask();
- pFree->magic = ARENA_FREE_MAGIC;
-
- /* If debugging, erase the freed block content */
-
- if (TRACE_ON(heap))
- {
- char *pEnd = (char *)ptr + size;
- if (pEnd > (char *)subheap + subheap->commitSize)
- pEnd = (char *)subheap + subheap->commitSize;
- if (pEnd > (char *)(pFree + 1))
- memset( pFree + 1, ARENA_FREE_FILLER, pEnd - (char *)(pFree + 1) );
- }
-
- /* Check if next block is free also */
-
- if (((char *)ptr + size < (char *)subheap + subheap->size) &&
- (*(DWORD *)((char *)ptr + size) & ARENA_FLAG_FREE))
- {
- /* Remove the next arena from the free list */
- ARENA_FREE *pNext = (ARENA_FREE *)((char *)ptr + size);
- pNext->next->prev = pNext->prev;
- pNext->prev->next = pNext->next;
- size += (pNext->size & ARENA_SIZE_MASK) + sizeof(*pNext);
- if (TRACE_ON(heap))
- memset( pNext, ARENA_FREE_FILLER, sizeof(ARENA_FREE) );
- }
-
- /* Set the next block PREV_FREE flag and pointer */
-
- if ((char *)ptr + size < (char *)subheap + subheap->size)
- {
- DWORD *pNext = (DWORD *)((char *)ptr + size);
- *pNext |= ARENA_FLAG_PREV_FREE;
- *(ARENA_FREE **)(pNext - 1) = pFree;
- }
-
- /* Last, insert the new block into the free list */
-
- pFree->size = size - sizeof(*pFree);
- HEAP_InsertFreeBlock( subheap->heap, pFree );
-}
-
-
-/***********************************************************************
- * HEAP_MakeInUseBlockFree
- *
- * Turn an in-use block into a free block. Can also decommit the end of
- * the heap, and possibly even free the sub-heap altogether.
- */
-static void HEAP_MakeInUseBlockFree( SUBHEAP *subheap, ARENA_INUSE *pArena )
-{
- ARENA_FREE *pFree;
- DWORD size = (pArena->size & ARENA_SIZE_MASK) + sizeof(*pArena);
-
- /* Check if we can merge with previous block */
-
- if (pArena->size & ARENA_FLAG_PREV_FREE)
- {
- pFree = *((ARENA_FREE **)pArena - 1);
- size += (pFree->size & ARENA_SIZE_MASK) + sizeof(ARENA_FREE);
- /* Remove it from the free list */
- pFree->next->prev = pFree->prev;
- pFree->prev->next = pFree->next;
- }
- else pFree = (ARENA_FREE *)pArena;
-
- /* Create a free block */
-
- HEAP_CreateFreeBlock( subheap, pFree, size );
- size = (pFree->size & ARENA_SIZE_MASK) + sizeof(ARENA_FREE);
- if ((char *)pFree + size < (char *)subheap + subheap->size)
- return; /* Not the last block, so nothing more to do */
-
- /* Free the whole sub-heap if it's empty and not the original one */
-
- if (((char *)pFree == (char *)subheap + subheap->headerSize) &&
- (subheap != &subheap->heap->subheap))
- {
- SUBHEAP *pPrev = &subheap->heap->subheap;
- /* Remove the free block from the list */
- pFree->next->prev = pFree->prev;
- pFree->prev->next = pFree->next;
- /* Remove the subheap from the list */
- while (pPrev && (pPrev->next != subheap)) pPrev = pPrev->next;
- if (pPrev) pPrev->next = subheap->next;
- /* Free the memory */
- subheap->magic = 0;
- if (subheap->selector) FreeSelector16( subheap->selector );
- VirtualFree( subheap, 0, MEM_RELEASE );
- return;
- }
-
- /* Decommit the end of the heap */
-
- if (!(subheap->heap->flags & HEAP_SHARED)) HEAP_Decommit( subheap, pFree + 1 );
-}
-
-
-/***********************************************************************
- * HEAP_ShrinkBlock
- *
- * Shrink an in-use block.
- */
-static void HEAP_ShrinkBlock(SUBHEAP *subheap, ARENA_INUSE *pArena, DWORD size)
-{
- if ((pArena->size & ARENA_SIZE_MASK) >= size + HEAP_MIN_BLOCK_SIZE)
- {
- HEAP_CreateFreeBlock( subheap, (char *)(pArena + 1) + size,
- (pArena->size & ARENA_SIZE_MASK) - size );
- /* assign size plus previous arena flags */
- pArena->size = size | (pArena->size & ~ARENA_SIZE_MASK);
- }
- else
- {
- /* Turn off PREV_FREE flag in next block */
- char *pNext = (char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK);
- if (pNext < (char *)subheap + subheap->size)
- *(DWORD *)pNext &= ~ARENA_FLAG_PREV_FREE;
- }
-}
-
-/***********************************************************************
- * HEAP_InitSubHeap
- */
-static BOOL HEAP_InitSubHeap( HEAP *heap, LPVOID address, DWORD flags,
- DWORD commitSize, DWORD totalSize )
-{
- SUBHEAP *subheap = (SUBHEAP *)address;
- WORD selector = 0;
- FREE_LIST_ENTRY *pEntry;
- int i;
-
- /* Commit memory */
-
- if (flags & HEAP_SHARED)
- commitSize = totalSize; /* always commit everything in a shared heap */
- if (!VirtualAlloc(address, commitSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE))
- {
- WARN("Could not commit %08lx bytes for sub-heap %08lx\n",
- commitSize, (DWORD)address );
- return FALSE;
- }
-
- /* Allocate a selector if needed */
-
- if (flags & HEAP_WINE_SEGPTR)
- {
- unsigned char selflags = WINE_LDT_FLAGS_DATA;
-
- if (flags & (HEAP_WINE_CODESEG | HEAP_WINE_CODE16SEG))
- selflags = WINE_LDT_FLAGS_CODE;
- if (flags & HEAP_WINE_CODESEG)
- selflags |= WINE_LDT_FLAGS_32BIT;
- selector = SELECTOR_AllocBlock( address, totalSize, selflags );
- if (!selector)
- {
- ERR("Could not allocate selector\n" );
- return FALSE;
- }
- }
-
- /* Fill the sub-heap structure */
-
- subheap->heap = heap;
- subheap->selector = selector;
- subheap->size = totalSize;
- subheap->commitSize = commitSize;
- subheap->magic = SUBHEAP_MAGIC;
-
- if ( subheap != (SUBHEAP *)heap )
- {
- /* If this is a secondary subheap, insert it into list */
-
- subheap->headerSize = sizeof(SUBHEAP);
- subheap->next = heap->subheap.next;
- heap->subheap.next = subheap;
- }
- else
- {
- /* If this is a primary subheap, initialize main heap */
-
- subheap->headerSize = sizeof(HEAP);
- subheap->next = NULL;
- heap->next = NULL;
- heap->flags = flags;
- heap->magic = HEAP_MAGIC;
-
- /* Build the free lists */
-
- for (i = 0, pEntry = heap->freeList; i < HEAP_NB_FREE_LISTS; i++, pEntry++)
- {
- pEntry->size = HEAP_freeListSizes[i];
- pEntry->arena.size = 0 | ARENA_FLAG_FREE;
- pEntry->arena.next = i < HEAP_NB_FREE_LISTS-1 ?
- &heap->freeList[i+1].arena : &heap->freeList[0].arena;
- pEntry->arena.prev = i ? &heap->freeList[i-1].arena :
- &heap->freeList[HEAP_NB_FREE_LISTS-1].arena;
- pEntry->arena.threadId = 0;
- pEntry->arena.magic = ARENA_FREE_MAGIC;
- }
-
- /* Initialize critical section */
-
- InitializeCriticalSection( &heap->critSection );
- }
-
- /* Create the first free block */
-
- HEAP_CreateFreeBlock( subheap, (LPBYTE)subheap + subheap->headerSize,
- subheap->size - subheap->headerSize );
-
- return TRUE;
-}
-
-/***********************************************************************
- * HEAP_CreateSubHeap
- *
- * Create a sub-heap of the given size.
- * If heap == NULL, creates a main heap.
- */
-static SUBHEAP *HEAP_CreateSubHeap( HEAP *heap, DWORD flags,
- DWORD commitSize, DWORD totalSize )
-{
- LPVOID address;
-
- /* Round-up sizes on a 64K boundary */
-
- if (flags & HEAP_WINE_SEGPTR)
- {
- totalSize = commitSize = 0x10000; /* Only 64K at a time for SEGPTRs */
- }
- else
- {
- totalSize = (totalSize + 0xffff) & 0xffff0000;
- commitSize = (commitSize + 0xffff) & 0xffff0000;
- if (!commitSize) commitSize = 0x10000;
- if (totalSize < commitSize) totalSize = commitSize;
- }
-
- /* Allocate the memory block */
-
- if (!(address = VirtualAlloc( NULL, totalSize,
- MEM_RESERVE, PAGE_EXECUTE_READWRITE )))
- {
- WARN("Could not VirtualAlloc %08lx bytes\n",
- totalSize );
- return NULL;
- }
-
- /* Initialize subheap */
-
- if (!HEAP_InitSubHeap( heap? heap : (HEAP *)address,
- address, flags, commitSize, totalSize ))
- {
- VirtualFree( address, 0, MEM_RELEASE );
- return NULL;
- }
-
- return (SUBHEAP *)address;
-}
-
-
-/***********************************************************************
- * HEAP_FindFreeBlock
- *
- * Find a free block at least as large as the requested size, and make sure
- * the requested size is committed.
- */
-static ARENA_FREE *HEAP_FindFreeBlock( HEAP *heap, DWORD size,
- SUBHEAP **ppSubHeap )
-{
- SUBHEAP *subheap;
- ARENA_FREE *pArena;
- FREE_LIST_ENTRY *pEntry = heap->freeList;
-
- /* Find a suitable free list, and in it find a block large enough */
-
- while (pEntry->size < size) pEntry++;
- pArena = pEntry->arena.next;
- while (pArena != &heap->freeList[0].arena)
- {
- DWORD arena_size = (pArena->size & ARENA_SIZE_MASK) +
- sizeof(ARENA_FREE) - sizeof(ARENA_INUSE);
- if (arena_size >= size)
- {
- subheap = HEAP_FindSubHeap( heap, pArena );
- if (!HEAP_Commit( subheap, (char *)pArena + sizeof(ARENA_INUSE)
- + size + HEAP_MIN_BLOCK_SIZE))
- return NULL;
- *ppSubHeap = subheap;
- return pArena;
- }
- pArena = pArena->next;
- }
-
- /* If no block was found, attempt to grow the heap */
-
- if (!(heap->flags & HEAP_GROWABLE))
- {
- WARN("Not enough space in heap %08lx for %08lx bytes\n",
- (DWORD)heap, size );
- return NULL;
- }
- /* make sure that we have a big enough size *committed* to fit another
- * last free arena in !
- * So just one heap struct, one first free arena which will eventually
- * get inuse, and HEAP_MIN_BLOCK_SIZE for the second free arena that
- * might get assigned all remaining free space in HEAP_ShrinkBlock() */
- size += sizeof(SUBHEAP) + sizeof(ARENA_INUSE) + HEAP_MIN_BLOCK_SIZE;
- if (!(subheap = HEAP_CreateSubHeap( heap, heap->flags, size,
- max( HEAP_DEF_SIZE, size ) )))
- return NULL;
-
- TRACE("created new sub-heap %08lx of %08lx bytes for heap %08lx\n",
- (DWORD)subheap, size, (DWORD)heap );
-
- *ppSubHeap = subheap;
- return (ARENA_FREE *)(subheap + 1);
-}
-
-
-/***********************************************************************
- * HEAP_IsValidArenaPtr
- *
- * Check that the pointer is inside the range possible for arenas.
- */
-static BOOL HEAP_IsValidArenaPtr( HEAP *heap, void *ptr )
-{
- int i;
- SUBHEAP *subheap = HEAP_FindSubHeap( heap, ptr );
- if (!subheap) return FALSE;
- if ((char *)ptr >= (char *)subheap + subheap->headerSize) return TRUE;
- if (subheap != &heap->subheap) return FALSE;
- for (i = 0; i < HEAP_NB_FREE_LISTS; i++)
- if (ptr == (void *)&heap->freeList[i].arena) return TRUE;
- return FALSE;
-}
-
-
-/***********************************************************************
- * HEAP_ValidateFreeArena
- */
-static BOOL HEAP_ValidateFreeArena( SUBHEAP *subheap, ARENA_FREE *pArena )
-{
- char *heapEnd = (char *)subheap + subheap->size;
-
-#if !defined(ALLOW_UNALIGNED_ACCESS)
- /* Check for unaligned pointers */
- if ( (long)pArena % sizeof(void *) != 0 )
- {
- ERR( "Heap %08lx: unaligned arena pointer %08lx\n",
- (DWORD)subheap->heap, (DWORD)pArena );
- return FALSE;
- }
-#endif
-
- /* Check magic number */
- if (pArena->magic != ARENA_FREE_MAGIC)
- {
- ERR("Heap %08lx: invalid free arena magic for %08lx\n",
- (DWORD)subheap->heap, (DWORD)pArena );
- return FALSE;
- }
- /* Check size flags */
- if (!(pArena->size & ARENA_FLAG_FREE) ||
- (pArena->size & ARENA_FLAG_PREV_FREE))
- {
- ERR("Heap %08lx: bad flags %lx for free arena %08lx\n",
- (DWORD)subheap->heap, pArena->size & ~ARENA_SIZE_MASK, (DWORD)pArena );
- }
- /* Check arena size */
- if ((char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK) > heapEnd)
- {
- ERR("Heap %08lx: bad size %08lx for free arena %08lx\n",
- (DWORD)subheap->heap, (DWORD)pArena->size & ARENA_SIZE_MASK, (DWORD)pArena );
- return FALSE;
- }
- /* Check that next pointer is valid */
- if (!HEAP_IsValidArenaPtr( subheap->heap, pArena->next ))
- {
- ERR("Heap %08lx: bad next ptr %08lx for arena %08lx\n",
- (DWORD)subheap->heap, (DWORD)pArena->next, (DWORD)pArena );
- return FALSE;
- }
- /* Check that next arena is free */
- if (!(pArena->next->size & ARENA_FLAG_FREE) ||
- (pArena->next->magic != ARENA_FREE_MAGIC))
- {
- ERR("Heap %08lx: next arena %08lx invalid for %08lx\n",
- (DWORD)subheap->heap, (DWORD)pArena->next, (DWORD)pArena );
- return FALSE;
- }
- /* Check that prev pointer is valid */
- if (!HEAP_IsValidArenaPtr( subheap->heap, pArena->prev ))
- {
- ERR("Heap %08lx: bad prev ptr %08lx for arena %08lx\n",
- (DWORD)subheap->heap, (DWORD)pArena->prev, (DWORD)pArena );
- return FALSE;
- }
- /* Check that prev arena is free */
- if (!(pArena->prev->size & ARENA_FLAG_FREE) ||
- (pArena->prev->magic != ARENA_FREE_MAGIC))
- {
- /* this often means that the prev arena got overwritten
- * by a memory write before that prev arena */
- ERR("Heap %08lx: prev arena %08lx invalid for %08lx\n",
- (DWORD)subheap->heap, (DWORD)pArena->prev, (DWORD)pArena );
- return FALSE;
- }
- /* Check that next block has PREV_FREE flag */
- if ((char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK) < heapEnd)
- {
- if (!(*(DWORD *)((char *)(pArena + 1) +
- (pArena->size & ARENA_SIZE_MASK)) & ARENA_FLAG_PREV_FREE))
- {
- ERR("Heap %08lx: free arena %08lx next block has no PREV_FREE flag\n",
- (DWORD)subheap->heap, (DWORD)pArena );
- return FALSE;
- }
- /* Check next block back pointer */
- if (*((ARENA_FREE **)((char *)(pArena + 1) +
- (pArena->size & ARENA_SIZE_MASK)) - 1) != pArena)
- {
- ERR("Heap %08lx: arena %08lx has wrong back ptr %08lx\n",
- (DWORD)subheap->heap, (DWORD)pArena,
- *((DWORD *)((char *)(pArena+1)+ (pArena->size & ARENA_SIZE_MASK)) - 1));
- return FALSE;
- }
- }
- return TRUE;
-}
-
-
-/***********************************************************************
- * HEAP_ValidateInUseArena
- */
-static BOOL HEAP_ValidateInUseArena( SUBHEAP *subheap, ARENA_INUSE *pArena, BOOL quiet )
-{
- char *heapEnd = (char *)subheap + subheap->size;
-
-#if !defined(ALLOW_UNALIGNED_ACCESS)
- /* Check for unaligned pointers */
- if ( (long)pArena % sizeof(void *) != 0 )
- {
- if ( quiet == NOISY )
- {
- ERR( "Heap %08lx: unaligned arena pointer %08lx\n",
- (DWORD)subheap->heap, (DWORD)pArena );
- if ( TRACE_ON(heap) )
- HEAP_Dump( subheap->heap );
- }
- else if ( WARN_ON(heap) )
- {
- WARN( "Heap %08lx: unaligned arena pointer %08lx\n",
- (DWORD)subheap->heap, (DWORD)pArena );
- if ( TRACE_ON(heap) )
- HEAP_Dump( subheap->heap );
- }
- return FALSE;
- }
-#endif
-
- /* Check magic number */
- if (pArena->magic != ARENA_INUSE_MAGIC)
- {
- if (quiet == NOISY) {
- ERR("Heap %08lx: invalid in-use arena magic for %08lx\n",
- (DWORD)subheap->heap, (DWORD)pArena );
- if (TRACE_ON(heap))
- HEAP_Dump( subheap->heap );
- } else if (WARN_ON(heap)) {
- WARN("Heap %08lx: invalid in-use arena magic for %08lx\n",
- (DWORD)subheap->heap, (DWORD)pArena );
- if (TRACE_ON(heap))
- HEAP_Dump( subheap->heap );
- }
- return FALSE;
- }
- /* Check size flags */
- if (pArena->size & ARENA_FLAG_FREE)
- {
- ERR("Heap %08lx: bad flags %lx for in-use arena %08lx\n",
- (DWORD)subheap->heap, pArena->size & ~ARENA_SIZE_MASK, (DWORD)pArena );
- }
- /* Check arena size */
- if ((char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK) > heapEnd)
- {
- ERR("Heap %08lx: bad size %08lx for in-use arena %08lx\n",
- (DWORD)subheap->heap, (DWORD)pArena->size & ARENA_SIZE_MASK, (DWORD)pArena );
- return FALSE;
- }
- /* Check next arena PREV_FREE flag */
- if (((char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK) < heapEnd) &&
- (*(DWORD *)((char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK)) & ARENA_FLAG_PREV_FREE))
- {
- ERR("Heap %08lx: in-use arena %08lx next block has PREV_FREE flag\n",
- (DWORD)subheap->heap, (DWORD)pArena );
- return FALSE;
- }
- /* Check prev free arena */
- if (pArena->size & ARENA_FLAG_PREV_FREE)
- {
- ARENA_FREE *pPrev = *((ARENA_FREE **)pArena - 1);
- /* Check prev pointer */
- if (!HEAP_IsValidArenaPtr( subheap->heap, pPrev ))
- {
- ERR("Heap %08lx: bad back ptr %08lx for arena %08lx\n",
- (DWORD)subheap->heap, (DWORD)pPrev, (DWORD)pArena );
- return FALSE;
- }
- /* Check that prev arena is free */
- if (!(pPrev->size & ARENA_FLAG_FREE) ||
- (pPrev->magic != ARENA_FREE_MAGIC))
- {
- ERR("Heap %08lx: prev arena %08lx invalid for in-use %08lx\n",
- (DWORD)subheap->heap, (DWORD)pPrev, (DWORD)pArena );
- return FALSE;
- }
- /* Check that prev arena is really the previous block */
- if ((char *)(pPrev + 1) + (pPrev->size & ARENA_SIZE_MASK) != (char *)pArena)
- {
- ERR("Heap %08lx: prev arena %08lx is not prev for in-use %08lx\n",
- (DWORD)subheap->heap, (DWORD)pPrev, (DWORD)pArena );
- return FALSE;
- }
- }
- return TRUE;
-}
-
-
-/***********************************************************************
- * HEAP_GetSegptr
- *
- * Transform a linear pointer into a SEGPTR. The pointer must have been
- * allocated from a HEAP_WINE_SEGPTR heap.
- */
-SEGPTR HEAP_GetSegptr( HANDLE heap, DWORD flags, LPCVOID ptr )
-{
- HEAP *heapPtr = HEAP_GetPtr( heap );
- SUBHEAP *subheap;
- SEGPTR ret = 0;
-
- /* Validate the parameters */
-
- if (!heapPtr) return 0;
- flags |= heapPtr->flags;
- if (!(flags & HEAP_WINE_SEGPTR))
- {
- ERR("Heap %08x is not a SEGPTR heap\n",
- heap );
- return 0;
- }
- if (!(flags & HEAP_NO_SERIALIZE)) EnterCriticalSection( &heapPtr->critSection );
-
- /* Get the subheap */
-
- if ((subheap = HEAP_FindSubHeap( heapPtr, ptr )))
- ret = MAKESEGPTR(subheap->selector, (char *)ptr - (char *)subheap);
-
- if (!(flags & HEAP_NO_SERIALIZE)) LeaveCriticalSection( &heapPtr->critSection );
- return ret;
-}
-
-/***********************************************************************
- * MapLS (KERNEL32.@)
- * MapLS (KERNEL.358)
- *
- * Maps linear pointer to segmented.
- */
-SEGPTR WINAPI MapLS( LPCVOID ptr )
-{
- SUBHEAP *subheap;
- SEGPTR ret = 0;
-
- if (!HIWORD(ptr)) return (SEGPTR)ptr;
-
- /* check if the pointer is inside the segptr heap */
- EnterCriticalSection( &segptrHeap->critSection );
- if ((subheap = HEAP_FindSubHeap( segptrHeap, ptr )))
- ret = MAKESEGPTR( subheap->selector, (char *)ptr - (char *)subheap );
- LeaveCriticalSection( &segptrHeap->critSection );
-
- /* otherwise, allocate a brand-new selector */
- if (!ret)
- {
- WORD sel = SELECTOR_AllocBlock( ptr, 0x10000, WINE_LDT_FLAGS_DATA );
- ret = MAKESEGPTR( sel, 0 );
- }
- return ret;
-}
-
-
-/***********************************************************************
- * UnMapLS (KERNEL32.@)
- * UnMapLS (KERNEL.359)
- *
- * Free mapped selector.
- */
-void WINAPI UnMapLS( SEGPTR sptr )
-{
- SUBHEAP *subheap;
- if (!SELECTOROF(sptr)) return;
-
- /* check if ptr is inside segptr heap */
- EnterCriticalSection( &segptrHeap->critSection );
- subheap = HEAP_FindSubHeap( segptrHeap, MapSL(sptr) );
- if ((subheap) && (subheap->selector != SELECTOROF(sptr))) subheap = NULL;
- LeaveCriticalSection( &segptrHeap->critSection );
- /* if not inside heap, free the selector */
- if (!subheap) FreeSelector16( SELECTOROF(sptr) );
-}
-
-/***********************************************************************
- * HEAP_IsRealArena [Internal]
- * Validates a block is a valid arena.
- *
- * RETURNS
- * TRUE: Success
- * FALSE: Failure
- */
-static BOOL HEAP_IsRealArena( HEAP *heapPtr, /* [in] ptr to the heap */
- DWORD flags, /* [in] Bit flags that control access during operation */
- LPCVOID block, /* [in] Optional pointer to memory block to validate */
- BOOL quiet ) /* [in] Flag - if true, HEAP_ValidateInUseArena
- * does not complain */
-{
- SUBHEAP *subheap;
- BOOL ret = TRUE;
-
- if (!heapPtr || (heapPtr->magic != HEAP_MAGIC))
- {
- ERR("Invalid heap %p!\n", heapPtr );
- return FALSE;
- }
-
- flags &= HEAP_NO_SERIALIZE;
- flags |= heapPtr->flags;
- /* calling HeapLock may result in infinite recursion, so do the critsect directly */
- if (!(flags & HEAP_NO_SERIALIZE))
- EnterCriticalSection( &heapPtr->critSection );
-
- if (block)
- {
- /* Only check this single memory block */
-
- if (!(subheap = HEAP_FindSubHeap( heapPtr, block )) ||
- ((char *)block < (char *)subheap + subheap->headerSize
- + sizeof(ARENA_INUSE)))
- {
- if (quiet == NOISY)
- ERR("Heap %p: block %p is not inside heap\n", heapPtr, block );
- else if (WARN_ON(heap))
- WARN("Heap %p: block %p is not inside heap\n", heapPtr, block );
- ret = FALSE;
- } else
- ret = HEAP_ValidateInUseArena( subheap, (ARENA_INUSE *)block - 1, quiet );
-
- if (!(flags & HEAP_NO_SERIALIZE))
- LeaveCriticalSection( &heapPtr->critSection );
- return ret;
- }
-
- subheap = &heapPtr->subheap;
- while (subheap && ret)
- {
- char *ptr = (char *)subheap + subheap->headerSize;
- while (ptr < (char *)subheap + subheap->size)
- {
- if (*(DWORD *)ptr & ARENA_FLAG_FREE)
- {
- if (!HEAP_ValidateFreeArena( subheap, (ARENA_FREE *)ptr )) {
- ret = FALSE;
- break;
- }
- ptr += sizeof(ARENA_FREE) + (*(DWORD *)ptr & ARENA_SIZE_MASK);
- }
- else
- {
- if (!HEAP_ValidateInUseArena( subheap, (ARENA_INUSE *)ptr, NOISY )) {
- ret = FALSE;
- break;
- }
- ptr += sizeof(ARENA_INUSE) + (*(DWORD *)ptr & ARENA_SIZE_MASK);
- }
- }
- subheap = subheap->next;
- }
-
- if (!(flags & HEAP_NO_SERIALIZE))
- LeaveCriticalSection( &heapPtr->critSection );
- return ret;
-}
-
-
-/***********************************************************************
- * HEAP_CreateSystemHeap
- *
- * Create the system heap.
- */
-static HANDLE HEAP_CreateSystemHeap(void)
-{
- int created;
-
- HANDLE map = CreateFileMappingA( INVALID_HANDLE_VALUE, NULL, SEC_COMMIT | PAGE_READWRITE,
- 0, HEAP_DEF_SIZE, "__SystemHeap" );
- if (!map) return 0;
- created = (GetLastError() != ERROR_ALREADY_EXISTS);
-
- if (!(systemHeap = MapViewOfFileEx( map, FILE_MAP_ALL_ACCESS, 0, 0, 0, SYSTEM_HEAP_BASE )))
- {
- /* pre-defined address not available, use any one */
- ERR( "system heap base address %p not available\n", SYSTEM_HEAP_BASE );
- return 0;
- }
-
- if (created) /* newly created heap */
- {
- HEAP_InitSubHeap( systemHeap, systemHeap, HEAP_SHARED, 0, HEAP_DEF_SIZE );
- MakeCriticalSectionGlobal( &systemHeap->critSection );
- }
- else
- {
- /* wait for the heap to be initialized */
- while (!systemHeap->critSection.LockSemaphore) Sleep(1);
- }
- CloseHandle( map );
- return (HANDLE)systemHeap;
-}
-
-
-/***********************************************************************
- * HeapCreate (KERNEL32.@)
- * RETURNS
- * Handle of heap: Success
- * NULL: Failure
- */
-HANDLE WINAPI HeapCreate(
- DWORD flags, /* [in] Heap allocation flag */
- DWORD initialSize, /* [in] Initial heap size */
- DWORD maxSize /* [in] Maximum heap size */
-) {
- SUBHEAP *subheap;
-
- if ( flags & HEAP_SHARED ) {
- if (!systemHeap) HEAP_CreateSystemHeap();
- else WARN( "Shared Heap requested, returning system heap.\n" );
- return (HANDLE)systemHeap;
- }
-
- /* Allocate the heap block */
-
- if (!maxSize)
- {
- maxSize = HEAP_DEF_SIZE;
- flags |= HEAP_GROWABLE;
- }
- if (!(subheap = HEAP_CreateSubHeap( NULL, flags, initialSize, maxSize )))
- {
- SetLastError( ERROR_OUTOFMEMORY );
- return 0;
- }
-
- /* link it into the per-process heap list */
- if (processHeap)
- {
- HEAP *heapPtr = subheap->heap;
- EnterCriticalSection( &processHeap->critSection );
- heapPtr->next = firstHeap;
- firstHeap = heapPtr;
- LeaveCriticalSection( &processHeap->critSection );
- }
- else /* assume the first heap we create is the process main heap */
- {
- SUBHEAP *segptr;
- processHeap = subheap->heap;
- /* create the SEGPTR heap */
- if (!(segptr = HEAP_CreateSubHeap( NULL, flags|HEAP_WINE_SEGPTR|HEAP_GROWABLE, 0, 0 )))
- {
- SetLastError( ERROR_OUTOFMEMORY );
- return 0;
- }
- segptrHeap = segptr->heap;
- }
- return (HANDLE)subheap;
-}
-
-/***********************************************************************
- * HeapDestroy (KERNEL32.@)
- * RETURNS
- * TRUE: Success
- * FALSE: Failure
- */
-BOOL WINAPI HeapDestroy( HANDLE heap /* [in] Handle of heap */ )
-{
- HEAP *heapPtr = HEAP_GetPtr( heap );
- SUBHEAP *subheap;
-
- TRACE("%08x\n", heap );
- if (!heapPtr) return FALSE;
-
- if (heapPtr == systemHeap)
- {
- WARN( "attempt to destroy system heap, returning TRUE!\n" );
- return TRUE;
- }
- if (heapPtr == processHeap) /* cannot delete the main process heap */
- {
- SetLastError( ERROR_INVALID_PARAMETER );
- return FALSE;
- }
- else /* remove it from the per-process list */
- {
- HEAP **pptr;
- EnterCriticalSection( &processHeap->critSection );
- pptr = &firstHeap;
- while (*pptr && *pptr != heapPtr) pptr = &(*pptr)->next;
- if (*pptr) *pptr = (*pptr)->next;
- LeaveCriticalSection( &processHeap->critSection );
- }
-
- DeleteCriticalSection( &heapPtr->critSection );
- subheap = &heapPtr->subheap;
- while (subheap)
- {
- SUBHEAP *next = subheap->next;
- if (subheap->selector) FreeSelector16( subheap->selector );
- VirtualFree( subheap, 0, MEM_RELEASE );
- subheap = next;
- }
- return TRUE;
-}
-
-
-/***********************************************************************
- * HeapAlloc (KERNEL32.@)
- * RETURNS
- * Pointer to allocated memory block
- * NULL: Failure
- */
-LPVOID WINAPI HeapAlloc(
- HANDLE heap, /* [in] Handle of private heap block */
- DWORD flags, /* [in] Heap allocation control flags */
- DWORD size /* [in] Number of bytes to allocate */
-) {
- ARENA_FREE *pArena;
- ARENA_INUSE *pInUse;
- SUBHEAP *subheap;
- HEAP *heapPtr = HEAP_GetPtr( heap );
-
- /* Validate the parameters */
-
- if ((flags & HEAP_WINE_SEGPTR) && size < 0x10000) heapPtr = segptrHeap;
- if (!heapPtr) return NULL;
- flags &= HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY;
- flags |= heapPtr->flags;
- size = (size + 3) & ~3;
- if (size < HEAP_MIN_BLOCK_SIZE) size = HEAP_MIN_BLOCK_SIZE;
-
- if (!(flags & HEAP_NO_SERIALIZE)) EnterCriticalSection( &heapPtr->critSection );
- /* Locate a suitable free block */
-
- if (!(pArena = HEAP_FindFreeBlock( heapPtr, size, &subheap )))
- {
- TRACE("(%08x,%08lx,%08lx): returning NULL\n",
- heap, flags, size );
- if (!(flags & HEAP_NO_SERIALIZE)) LeaveCriticalSection( &heapPtr->critSection );
- SetLastError( ERROR_COMMITMENT_LIMIT );
- return NULL;
- }
-
- /* Remove the arena from the free list */
-
- pArena->next->prev = pArena->prev;
- pArena->prev->next = pArena->next;
-
- /* Build the in-use arena */
-
- pInUse = (ARENA_INUSE *)pArena;
-
- /* in-use arena is smaller than free arena,
- * so we have to add the difference to the size */
- pInUse->size = (pInUse->size & ~ARENA_FLAG_FREE)
- + sizeof(ARENA_FREE) - sizeof(ARENA_INUSE);
- pInUse->callerEIP = GET_EIP();
- pInUse->threadId = GetCurrentTask();
- pInUse->magic = ARENA_INUSE_MAGIC;
-
- /* Shrink the block */
-
- HEAP_ShrinkBlock( subheap, pInUse, size );
-
- if (flags & HEAP_ZERO_MEMORY)
- memset( pInUse + 1, 0, pInUse->size & ARENA_SIZE_MASK );
- else if (TRACE_ON(heap))
- memset( pInUse + 1, ARENA_INUSE_FILLER, pInUse->size & ARENA_SIZE_MASK );
-
- if (!(flags & HEAP_NO_SERIALIZE)) LeaveCriticalSection( &heapPtr->critSection );
-
- TRACE("(%08x,%08lx,%08lx): returning %08lx\n",
- heap, flags, size, (DWORD)(pInUse + 1) );
- return (LPVOID)(pInUse + 1);
-}
-
-
-/***********************************************************************
- * HeapFree (KERNEL32.@)
- * RETURNS
- * TRUE: Success
- * FALSE: Failure
- */
-BOOL WINAPI HeapFree(
- HANDLE heap, /* [in] Handle of heap */
- DWORD flags, /* [in] Heap freeing flags */
- LPVOID ptr /* [in] Address of memory to free */
-) {
- ARENA_INUSE *pInUse;
- SUBHEAP *subheap;
- HEAP *heapPtr = HEAP_GetPtr( heap );
-
- /* Validate the parameters */
-
- if (!ptr) return TRUE; /* freeing a NULL ptr isn't an error in Win2k */
- if (flags & HEAP_WINE_SEGPTR) heapPtr = segptrHeap;
- if (!heapPtr) return FALSE;
-
- flags &= HEAP_NO_SERIALIZE;
- flags |= heapPtr->flags;
- if (!(flags & HEAP_NO_SERIALIZE)) EnterCriticalSection( &heapPtr->critSection );
- if (!HEAP_IsRealArena( heapPtr, HEAP_NO_SERIALIZE, ptr, QUIET ))
- {
- if (!(flags & HEAP_NO_SERIALIZE)) LeaveCriticalSection( &heapPtr->critSection );
- SetLastError( ERROR_INVALID_PARAMETER );
- TRACE("(%08x,%08lx,%08lx): returning FALSE\n",
- heap, flags, (DWORD)ptr );
- return FALSE;
- }
-
- /* Turn the block into a free block */
-
- pInUse = (ARENA_INUSE *)ptr - 1;
- subheap = HEAP_FindSubHeap( heapPtr, pInUse );
- HEAP_MakeInUseBlockFree( subheap, pInUse );
-
- if (!(flags & HEAP_NO_SERIALIZE)) LeaveCriticalSection( &heapPtr->critSection );
-
- TRACE("(%08x,%08lx,%08lx): returning TRUE\n",
- heap, flags, (DWORD)ptr );
- return TRUE;
-}
-
-
-/***********************************************************************
- * HeapReAlloc (KERNEL32.@)
- * RETURNS
- * Pointer to reallocated memory block
- * NULL: Failure
- */
-LPVOID WINAPI HeapReAlloc(
- HANDLE heap, /* [in] Handle of heap block */
- DWORD flags, /* [in] Heap reallocation flags */
- LPVOID ptr, /* [in] Address of memory to reallocate */
- DWORD size /* [in] Number of bytes to reallocate */
-) {
- ARENA_INUSE *pArena;
- DWORD oldSize;
- HEAP *heapPtr;
- SUBHEAP *subheap;
-
- if (!ptr) return HeapAlloc( heap, flags, size ); /* FIXME: correct? */
- if ((flags & HEAP_WINE_SEGPTR) && size < 0x10000) heapPtr = segptrHeap;
- if (!(heapPtr = HEAP_GetPtr( heap ))) return FALSE;
-
- /* Validate the parameters */
-
- flags &= HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY |
- HEAP_REALLOC_IN_PLACE_ONLY;
- flags |= heapPtr->flags;
- size = (size + 3) & ~3;
- if (size < HEAP_MIN_BLOCK_SIZE) size = HEAP_MIN_BLOCK_SIZE;
-
- if (!(flags & HEAP_NO_SERIALIZE)) EnterCriticalSection( &heapPtr->critSection );
- if (!HEAP_IsRealArena( heapPtr, HEAP_NO_SERIALIZE, ptr, QUIET ))
- {
- if (!(flags & HEAP_NO_SERIALIZE)) LeaveCriticalSection( &heapPtr->critSection );
- SetLastError( ERROR_INVALID_PARAMETER );
- TRACE("(%08x,%08lx,%08lx,%08lx): returning NULL\n",
- heap, flags, (DWORD)ptr, size );
- return NULL;
- }
-
- /* Check if we need to grow the block */
-
- pArena = (ARENA_INUSE *)ptr - 1;
- pArena->threadId = GetCurrentTask();
- subheap = HEAP_FindSubHeap( heapPtr, pArena );
- oldSize = (pArena->size & ARENA_SIZE_MASK);
- if (size > oldSize)
- {
- char *pNext = (char *)(pArena + 1) + oldSize;
- if ((pNext < (char *)subheap + subheap->size) &&
- (*(DWORD *)pNext & ARENA_FLAG_FREE) &&
- (oldSize + (*(DWORD *)pNext & ARENA_SIZE_MASK) + sizeof(ARENA_FREE) >= size))
- {
- /* The next block is free and large enough */
- ARENA_FREE *pFree = (ARENA_FREE *)pNext;
- pFree->next->prev = pFree->prev;
- pFree->prev->next = pFree->next;
- pArena->size += (pFree->size & ARENA_SIZE_MASK) + sizeof(*pFree);
- if (!HEAP_Commit( subheap, (char *)pArena + sizeof(ARENA_INUSE)
- + size + HEAP_MIN_BLOCK_SIZE))
- {
- if (!(flags & HEAP_NO_SERIALIZE)) LeaveCriticalSection( &heapPtr->critSection );
- SetLastError( ERROR_OUTOFMEMORY );
- return NULL;
- }
- HEAP_ShrinkBlock( subheap, pArena, size );
- }
- else /* Do it the hard way */
- {
- ARENA_FREE *pNew;
- ARENA_INUSE *pInUse;
- SUBHEAP *newsubheap;
-
- if ((flags & HEAP_REALLOC_IN_PLACE_ONLY) ||
- !(pNew = HEAP_FindFreeBlock( heapPtr, size, &newsubheap )))
- {
- if (!(flags & HEAP_NO_SERIALIZE)) LeaveCriticalSection( &heapPtr->critSection );
- SetLastError( ERROR_OUTOFMEMORY );
- return NULL;
- }
-
- /* Build the in-use arena */
-
- pNew->next->prev = pNew->prev;
- pNew->prev->next = pNew->next;
- pInUse = (ARENA_INUSE *)pNew;
- pInUse->size = (pInUse->size & ~ARENA_FLAG_FREE)
- + sizeof(ARENA_FREE) - sizeof(ARENA_INUSE);
- pInUse->threadId = GetCurrentTask();
- pInUse->magic = ARENA_INUSE_MAGIC;
- HEAP_ShrinkBlock( newsubheap, pInUse, size );
- memcpy( pInUse + 1, pArena + 1, oldSize );
-
- /* Free the previous block */
-
- HEAP_MakeInUseBlockFree( subheap, pArena );
- subheap = newsubheap;
- pArena = pInUse;
- }
- }
- else HEAP_ShrinkBlock( subheap, pArena, size ); /* Shrink the block */
-
- /* Clear the extra bytes if needed */
-
- if (size > oldSize)
- {
- if (flags & HEAP_ZERO_MEMORY)
- memset( (char *)(pArena + 1) + oldSize, 0,
- (pArena->size & ARENA_SIZE_MASK) - oldSize );
- else if (TRACE_ON(heap))
- memset( (char *)(pArena + 1) + oldSize, ARENA_INUSE_FILLER,
- (pArena->size & ARENA_SIZE_MASK) - oldSize );
- }
-
- /* Return the new arena */
-
- pArena->callerEIP = GET_EIP();
- if (!(flags & HEAP_NO_SERIALIZE)) LeaveCriticalSection( &heapPtr->critSection );
-
- TRACE("(%08x,%08lx,%08lx,%08lx): returning %08lx\n",
- heap, flags, (DWORD)ptr, size, (DWORD)(pArena + 1) );
- return (LPVOID)(pArena + 1);
-}
-
-
-/***********************************************************************
- * HeapCompact (KERNEL32.@)
- */
-DWORD WINAPI HeapCompact( HANDLE heap, DWORD flags )
-{
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- return 0;
-}
-
-
-/***********************************************************************
- * HeapLock (KERNEL32.@)
- * Attempts to acquire the critical section object for a specified heap.
- *
- * RETURNS
- * TRUE: Success
- * FALSE: Failure
- */
-BOOL WINAPI HeapLock(
- HANDLE heap /* [in] Handle of heap to lock for exclusive access */
-) {
- HEAP *heapPtr = HEAP_GetPtr( heap );
- if (!heapPtr) return FALSE;
- EnterCriticalSection( &heapPtr->critSection );
- return TRUE;
-}
-
-
-/***********************************************************************
- * HeapUnlock (KERNEL32.@)
- * Releases ownership of the critical section object.
- *
- * RETURNS
- * TRUE: Success
- * FALSE: Failure
- */
-BOOL WINAPI HeapUnlock(
- HANDLE heap /* [in] Handle to the heap to unlock */
-) {
- HEAP *heapPtr = HEAP_GetPtr( heap );
- if (!heapPtr) return FALSE;
- LeaveCriticalSection( &heapPtr->critSection );
- return TRUE;
-}
-
-
-/***********************************************************************
- * HeapSize (KERNEL32.@)
- * RETURNS
- * Size in bytes of allocated memory
- * 0xffffffff: Failure
- */
-DWORD WINAPI HeapSize(
- HANDLE heap, /* [in] Handle of heap */
- DWORD flags, /* [in] Heap size control flags */
- LPVOID ptr /* [in] Address of memory to return size for */
-) {
- DWORD ret;
- HEAP *heapPtr = HEAP_GetPtr( heap );
-
- if (flags & HEAP_WINE_SEGPTR) heapPtr = segptrHeap;
- if (!heapPtr) return FALSE;
- flags &= HEAP_NO_SERIALIZE;
- flags |= heapPtr->flags;
- if (!(flags & HEAP_NO_SERIALIZE)) EnterCriticalSection( &heapPtr->critSection );
- if (!HEAP_IsRealArena( heapPtr, HEAP_NO_SERIALIZE, ptr, QUIET ))
- {
- SetLastError( ERROR_INVALID_PARAMETER );
- ret = 0xffffffff;
- }
- else
- {
- ARENA_INUSE *pArena = (ARENA_INUSE *)ptr - 1;
- ret = pArena->size & ARENA_SIZE_MASK;
- }
- if (!(flags & HEAP_NO_SERIALIZE)) LeaveCriticalSection( &heapPtr->critSection );
-
- TRACE("(%08x,%08lx,%08lx): returning %08lx\n",
- heap, flags, (DWORD)ptr, ret );
- return ret;
-}
-
-
-/***********************************************************************
- * HeapValidate (KERNEL32.@)
- * Validates a specified heap.
- *
- * NOTES
- * Flags is ignored.
- *
- * RETURNS
- * TRUE: Success
- * FALSE: Failure
- */
-BOOL WINAPI HeapValidate(
- HANDLE heap, /* [in] Handle to the heap */
- DWORD flags, /* [in] Bit flags that control access during operation */
- LPCVOID block /* [in] Optional pointer to memory block to validate */
-) {
- HEAP *heapPtr = HEAP_GetPtr( heap );
- if (flags & HEAP_WINE_SEGPTR) heapPtr = segptrHeap;
- if (!heapPtr) return FALSE;
- return HEAP_IsRealArena( heapPtr, flags, block, QUIET );
-}
-
-
-/***********************************************************************
- * HeapWalk (KERNEL32.@)
- * Enumerates the memory blocks in a specified heap.
- * See HEAP_Dump() for info on heap structure.
- *
- * TODO
- * - handling of PROCESS_HEAP_ENTRY_MOVEABLE and
- * PROCESS_HEAP_ENTRY_DDESHARE (needs heap.c support)
- *
- * RETURNS
- * TRUE: Success
- * FALSE: Failure
- */
-BOOL WINAPI HeapWalk(
- HANDLE heap, /* [in] Handle to heap to enumerate */
- LPPROCESS_HEAP_ENTRY entry /* [out] Pointer to structure of enumeration info */
-) {
- HEAP *heapPtr = HEAP_GetPtr(heap);
- SUBHEAP *sub, *currentheap = NULL;
- BOOL ret = FALSE;
- char *ptr;
- int region_index = 0;
-
- if (!heapPtr || !entry)
- {
- SetLastError(ERROR_INVALID_PARAMETER);
- return FALSE;
- }
-
- if (!(heapPtr->flags & HEAP_NO_SERIALIZE)) EnterCriticalSection( &heapPtr->critSection );
-
- /* set ptr to the next arena to be examined */
-
- if (!entry->lpData) /* first call (init) ? */
- {
- TRACE("begin walking of heap 0x%08x.\n", heap);
- /*HEAP_Dump(heapPtr);*/
- currentheap = &heapPtr->subheap;
- ptr = (char*)currentheap + currentheap->headerSize;
- }
- else
- {
- ptr = entry->lpData;
- sub = &heapPtr->subheap;
- while (sub)
- {
- if (((char *)ptr >= (char *)sub) &&
- ((char *)ptr < (char *)sub + sub->size))
- {
- currentheap = sub;
- break;
- }
- sub = sub->next;
- region_index++;
- }
- if (currentheap == NULL)
- {
- ERR("no matching subheap found, shouldn't happen !\n");
- SetLastError(ERROR_NO_MORE_ITEMS);
- goto HW_end;
- }
-
- ptr += entry->cbData; /* point to next arena */
- if (ptr > (char *)currentheap + currentheap->size - 1)
- { /* proceed with next subheap */
- if (!(currentheap = currentheap->next))
- { /* successfully finished */
- TRACE("end reached.\n");
- SetLastError(ERROR_NO_MORE_ITEMS);
- goto HW_end;
- }
- ptr = (char*)currentheap + currentheap->headerSize;
- }
- }
-
- entry->wFlags = 0;
- if (*(DWORD *)ptr & ARENA_FLAG_FREE)
- {
- ARENA_FREE *pArena = (ARENA_FREE *)ptr;
-
- /*TRACE("free, magic: %04x\n", pArena->magic);*/
-
- entry->lpData = pArena + 1;
- entry->cbData = pArena->size & ARENA_SIZE_MASK;
- entry->cbOverhead = sizeof(ARENA_FREE);
- entry->wFlags = PROCESS_HEAP_UNCOMMITTED_RANGE;
- }
- else
- {
- ARENA_INUSE *pArena = (ARENA_INUSE *)ptr;
-
- /*TRACE("busy, magic: %04x\n", pArena->magic);*/
-
- entry->lpData = pArena + 1;
- entry->cbData = pArena->size & ARENA_SIZE_MASK;
- entry->cbOverhead = sizeof(ARENA_INUSE);
- entry->wFlags = PROCESS_HEAP_ENTRY_BUSY;
- /* FIXME: can't handle PROCESS_HEAP_ENTRY_MOVEABLE
- and PROCESS_HEAP_ENTRY_DDESHARE yet */
- }
-
- entry->iRegionIndex = region_index;
-
- /* first element of heap ? */
- if (ptr == (char *)(currentheap + currentheap->headerSize))
- {
- entry->wFlags |= PROCESS_HEAP_REGION;
- entry->u.Region.dwCommittedSize = currentheap->commitSize;
- entry->u.Region.dwUnCommittedSize =
- currentheap->size - currentheap->commitSize;
- entry->u.Region.lpFirstBlock = /* first valid block */
- currentheap + currentheap->headerSize;
- entry->u.Region.lpLastBlock = /* first invalid block */
- currentheap + currentheap->size;
- }
- ret = TRUE;
-
-HW_end:
- if (!(heapPtr->flags & HEAP_NO_SERIALIZE)) LeaveCriticalSection( &heapPtr->critSection );
-
- return ret;
-}
-
-
-/***********************************************************************
- * GetProcessHeap (KERNEL32.@)
- */
-HANDLE WINAPI GetProcessHeap(void)
-{
- return (HANDLE)processHeap;
-}
-
-
-/***********************************************************************
- * GetProcessHeaps (KERNEL32.@)
- */
-DWORD WINAPI GetProcessHeaps( DWORD count, HANDLE *heaps )
-{
- DWORD total;
- HEAP *ptr;
-
- if (!processHeap) return 0; /* should never happen */
- total = 1; /* main heap */
- EnterCriticalSection( &processHeap->critSection );
- for (ptr = firstHeap; ptr; ptr = ptr->next) total++;
- if (total <= count)
- {
- *heaps++ = (HANDLE)processHeap;
- for (ptr = firstHeap; ptr; ptr = ptr->next) *heaps++ = (HANDLE)ptr;
- }
- LeaveCriticalSection( &processHeap->critSection );
- return total;
-}
-
+#define SYSTEM_HEAP_SIZE 0x100000 /* Default heap size = 1Mb */
-/***********************************************************************
- * 32-bit local heap functions (Win95; undocumented)
- */
#define HTABLE_SIZE 0x10000
#define HTABLE_PAGESIZE 0x1000
@@ -1704,6 +60,208 @@
#define LOCAL32_MAGIC ((DWORD)('L' | ('H'<<8) | ('3'<<16) | ('2'<<24)))
+static HANDLE systemHeap; /* globally shared heap */
+
+/***********************************************************************
+ * HEAP_CreateSystemHeap
+ *
+ * Create the system heap.
+ */
+inline static HANDLE HEAP_CreateSystemHeap(void)
+{
+ int created;
+ void *base;
+ HANDLE map, event;
+ UNICODE_STRING event_name;
+ OBJECT_ATTRIBUTES event_attr;
+
+ if (!(map = CreateFileMappingA( INVALID_HANDLE_VALUE, NULL, SEC_COMMIT | PAGE_READWRITE,
+ 0, SYSTEM_HEAP_SIZE, "__SystemHeap" ))) return 0;
+ created = (GetLastError() != ERROR_ALREADY_EXISTS);
+
+ if (!(base = MapViewOfFileEx( map, FILE_MAP_ALL_ACCESS, 0, 0, 0, SYSTEM_HEAP_BASE )))
+ {
+ /* pre-defined address not available */
+ ERR( "system heap base address %p not available\n", SYSTEM_HEAP_BASE );
+ return 0;
+ }
+
+ /* create the system heap event */
+ RtlCreateUnicodeStringFromAsciiz( &event_name, "__SystemHeapEvent" );
+ event_attr.Length = sizeof(event_attr);
+ event_attr.RootDirectory = 0;
+ event_attr.ObjectName = &event_name;
+ event_attr.Attributes = 0;
+ event_attr.SecurityDescriptor = NULL;
+ event_attr.SecurityQualityOfService = NULL;
+ NtCreateEvent( &event, EVENT_ALL_ACCESS, &event_attr, TRUE, FALSE );
+
+ if (created) /* newly created heap */
+ {
+ systemHeap = RtlCreateHeap( HEAP_SHARED, base, SYSTEM_HEAP_SIZE,
+ SYSTEM_HEAP_SIZE, NULL, NULL );
+ NtSetEvent( event, NULL );
+ }
+ else
+ {
+ /* wait for the heap to be initialized */
+ WaitForSingleObject( event, INFINITE );
+ }
+ CloseHandle( map );
+ return systemHeap;
+}
+
+
+/***********************************************************************
+ * HeapCreate (KERNEL32.@)
+ * RETURNS
+ * Handle of heap: Success
+ * NULL: Failure
+ */
+HANDLE WINAPI HeapCreate(
+ DWORD flags, /* [in] Heap allocation flag */
+ DWORD initialSize, /* [in] Initial heap size */
+ DWORD maxSize /* [in] Maximum heap size */
+) {
+ HANDLE ret;
+
+ if ( flags & HEAP_SHARED )
+ {
+ if (!systemHeap) HEAP_CreateSystemHeap();
+ else WARN( "Shared Heap requested, returning system heap.\n" );
+ ret = systemHeap;
+ }
+ else
+ {
+ ret = RtlCreateHeap( flags, NULL, maxSize, initialSize, NULL, NULL );
+ if (!ret) SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+ }
+ return ret;
+}
+
+/***********************************************************************
+ * HeapDestroy (KERNEL32.@)
+ * RETURNS
+ * TRUE: Success
+ * FALSE: Failure
+ */
+BOOL WINAPI HeapDestroy( HANDLE heap /* [in] Handle of heap */ )
+{
+ if (heap == systemHeap)
+ {
+ WARN( "attempt to destroy system heap, returning TRUE!\n" );
+ return TRUE;
+ }
+ if (!RtlDestroyHeap( heap )) return TRUE;
+ SetLastError( ERROR_INVALID_HANDLE );
+ return FALSE;
+}
+
+
+/***********************************************************************
+ * HeapCompact (KERNEL32.@)
+ */
+DWORD WINAPI HeapCompact( HANDLE heap, DWORD flags )
+{
+ return RtlCompactHeap( heap, flags );
+}
+
+
+/***********************************************************************
+ * HeapLock (KERNEL32.@)
+ * Attempts to acquire the critical section object for a specified heap.
+ *
+ * RETURNS
+ * TRUE: Success
+ * FALSE: Failure
+ */
+BOOL WINAPI HeapLock(
+ HANDLE heap /* [in] Handle of heap to lock for exclusive access */
+) {
+ return RtlLockHeap( heap );
+}
+
+
+/***********************************************************************
+ * HeapUnlock (KERNEL32.@)
+ * Releases ownership of the critical section object.
+ *
+ * RETURNS
+ * TRUE: Success
+ * FALSE: Failure
+ */
+BOOL WINAPI HeapUnlock(
+ HANDLE heap /* [in] Handle to the heap to unlock */
+) {
+ return RtlUnlockHeap( heap );
+}
+
+
+/***********************************************************************
+ * HeapValidate (KERNEL32.@)
+ * Validates a specified heap.
+ *
+ * NOTES
+ * Flags is ignored.
+ *
+ * RETURNS
+ * TRUE: Success
+ * FALSE: Failure
+ */
+BOOL WINAPI HeapValidate(
+ HANDLE heap, /* [in] Handle to the heap */
+ DWORD flags, /* [in] Bit flags that control access during operation */
+ LPCVOID block /* [in] Optional pointer to memory block to validate */
+) {
+ return RtlValidateHeap( heap, flags, block );
+}
+
+
+/***********************************************************************
+ * HeapWalk (KERNEL32.@)
+ * Enumerates the memory blocks in a specified heap.
+ *
+ * TODO
+ * - handling of PROCESS_HEAP_ENTRY_MOVEABLE and
+ * PROCESS_HEAP_ENTRY_DDESHARE (needs heap.c support)
+ *
+ * RETURNS
+ * TRUE: Success
+ * FALSE: Failure
+ */
+BOOL WINAPI HeapWalk(
+ HANDLE heap, /* [in] Handle to heap to enumerate */
+ LPPROCESS_HEAP_ENTRY entry /* [out] Pointer to structure of enumeration info */
+) {
+ NTSTATUS ret = RtlWalkHeap( heap, entry );
+ if (ret) SetLastError( RtlNtStatusToDosError(ret) );
+ return !ret;
+}
+
+
+/***********************************************************************
+ * GetProcessHeap (KERNEL32.@)
+ */
+HANDLE WINAPI GetProcessHeap(void)
+{
+ HANDLE *pdb = (HANDLE *)NtCurrentTeb()->process;
+ return pdb[0x18 / sizeof(HANDLE)]; /* get dword at offset 0x18 in pdb */
+}
+
+
+/***********************************************************************
+ * GetProcessHeaps (KERNEL32.@)
+ */
+DWORD WINAPI GetProcessHeaps( DWORD count, HANDLE *heaps )
+{
+ return RtlGetProcessHeaps( count, heaps );
+}
+
+
+/***********************************************************************
+ * 32-bit local heap functions (Win95; undocumented)
+ */
+
/***********************************************************************
* K208 (KERNEL.208)
*/
@@ -1713,7 +271,7 @@
DWORD totSize, segSize = 0;
LPBYTE base;
LOCAL32HEADER *header;
- HEAP *heap;
+ HANDLE heap;
WORD *selectorTable;
WORD selectorEven, selectorOdd;
int i, nrBlocks;
@@ -1748,8 +306,7 @@
return 0;
}
- heap = (HEAP *)(base + segSize + HTABLE_SIZE);
- if ( !HEAP_InitSubHeap( heap, (LPVOID)heap, 0, 0x10000, heapSize ) )
+ if (!(heap = RtlCreateHeap( 0, base + segSize + HTABLE_SIZE, heapSize, 0x10000, NULL, NULL )))
{
VirtualFree( base, 0, MEM_RELEASE );
return 0;
@@ -1763,7 +320,7 @@
header->limit = HTABLE_PAGESIZE-1;
header->flags = 0;
header->magic = LOCAL32_MAGIC;
- header->heap = (HANDLE)heap;
+ header->heap = heap;
header->freeListFirst[0] = sizeof(LOCAL32HEADER);
header->freeListLast[0] = HTABLE_PAGESIZE - 4;
@@ -2146,8 +703,7 @@
*/
BOOL16 WINAPI Local32Info16( LOCAL32INFO *pLocal32Info, HGLOBAL16 handle )
{
- SUBHEAP *heapPtr;
- LPBYTE ptr;
+ PROCESS_HEAP_ENTRY entry;
int i;
LOCAL32HEADER *header = Local32_GetHeap( handle );
@@ -2156,31 +712,24 @@
if ( !pLocal32Info || pLocal32Info->dwSize < sizeof(LOCAL32INFO) )
return FALSE;
- heapPtr = (SUBHEAP *)HEAP_GetPtr( header->heap );
- pLocal32Info->dwMemReserved = heapPtr->size;
- pLocal32Info->dwMemCommitted = heapPtr->commitSize;
- pLocal32Info->dwTotalFree = 0L;
- pLocal32Info->dwLargestFreeBlock = 0L;
+ pLocal32Info->dwMemReserved = 0;
+ pLocal32Info->dwMemCommitted = 0;
+ pLocal32Info->dwTotalFree = 0;
+ pLocal32Info->dwLargestFreeBlock = 0;
- /* Note: Local32 heaps always have only one subheap! */
- ptr = (LPBYTE)heapPtr + heapPtr->headerSize;
- while ( ptr < (LPBYTE)heapPtr + heapPtr->size )
+ while (HeapWalk( header->heap, &entry ))
{
- if (*(DWORD *)ptr & ARENA_FLAG_FREE)
+ if (entry.wFlags & PROCESS_HEAP_REGION)
{
- ARENA_FREE *pArena = (ARENA_FREE *)ptr;
- DWORD size = (pArena->size & ARENA_SIZE_MASK);
- ptr += sizeof(*pArena) + size;
-
- pLocal32Info->dwTotalFree += size;
- if ( size > pLocal32Info->dwLargestFreeBlock )
- pLocal32Info->dwLargestFreeBlock = size;
+ pLocal32Info->dwMemReserved += entry.u.Region.dwCommittedSize
+ + entry.u.Region.dwUnCommittedSize;
+ pLocal32Info->dwMemCommitted = entry.u.Region.dwCommittedSize;
}
- else
+ else if (!(entry.wFlags & PROCESS_HEAP_ENTRY_BUSY))
{
- ARENA_INUSE *pArena = (ARENA_INUSE *)ptr;
- DWORD size = (pArena->size & ARENA_SIZE_MASK);
- ptr += sizeof(*pArena) + size;
+ DWORD size = entry.cbData + entry.cbOverhead;
+ pLocal32Info->dwTotalFree += size;
+ if (size > pLocal32Info->dwLargestFreeBlock) pLocal32Info->dwLargestFreeBlock = size;
}
}
diff --git a/memory/selector.c b/memory/selector.c
index c3ce313..e68a92f 100644
--- a/memory/selector.c
+++ b/memory/selector.c
@@ -518,6 +518,84 @@
*
*/
+struct mapls_entry
+{
+ struct mapls_entry *next;
+ void *addr; /* linear address */
+ int count; /* ref count */
+ WORD sel; /* selector */
+};
+
+static struct mapls_entry *first_entry;
+
+
+/***********************************************************************
+ * MapLS (KERNEL32.@)
+ * MapLS (KERNEL.358)
+ *
+ * Maps linear pointer to segmented.
+ */
+SEGPTR WINAPI MapLS( LPCVOID ptr )
+{
+ struct mapls_entry *entry, *free = NULL;
+ void *base;
+ SEGPTR ret = 0;
+
+ if (!HIWORD(ptr)) return (SEGPTR)ptr;
+
+ base = (char *)ptr - ((unsigned int)ptr & 0x7fff);
+ HeapLock( GetProcessHeap() );
+ for (entry = first_entry; entry; entry = entry->next)
+ {
+ if (entry->addr == base) break;
+ if (!entry->count) free = entry;
+ }
+
+ if (!entry)
+ {
+ if (!free) /* no free entry found, create a new one */
+ {
+ if (!(free = HeapAlloc( GetProcessHeap(), 0, sizeof(*free) ))) goto done;
+ if (!(free->sel = SELECTOR_AllocBlock( base, 0x10000, WINE_LDT_FLAGS_DATA )))
+ {
+ HeapFree( GetProcessHeap(), 0, free );
+ goto done;
+ }
+ free->count = 0;
+ free->next = first_entry;
+ first_entry = free;
+ }
+ SetSelectorBase( free->sel, (DWORD)base );
+ free->addr = base;
+ entry = free;
+ }
+ entry->count++;
+ ret = MAKESEGPTR( entry->sel, (char *)ptr - (char *)entry->addr );
+ done:
+ HeapUnlock( GetProcessHeap() );
+ return ret;
+}
+
+/***********************************************************************
+ * UnMapLS (KERNEL32.@)
+ * UnMapLS (KERNEL.359)
+ *
+ * Free mapped selector.
+ */
+void WINAPI UnMapLS( SEGPTR sptr )
+{
+ struct mapls_entry *entry;
+ WORD sel = SELECTOROF(sptr);
+
+ if (sel)
+ {
+ HeapLock( GetProcessHeap() );
+ for (entry = first_entry; entry; entry = entry->next) if (entry->sel == sel) break;
+ if (entry && entry->count > 0) entry->count--;
+ HeapUnlock( GetProcessHeap() );
+ }
+}
+
/***********************************************************************
* MapSL (KERNEL32.@)
* MapSL (KERNEL.357)