From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/ntdll/heap.c | 28 ++++------------------------ 1 file changed, 4 insertions(+), 24 deletions(-)
diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 767a010d93e..5fe23a3502e 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -595,28 +595,6 @@ static HEAP *HEAP_GetPtr( }
-/*********************************************************************** - * HEAP_InsertFreeBlock - * - * Insert a free block into the free list. - */ -static inline void HEAP_InsertFreeBlock( HEAP *heap, ARENA_FREE *pArena, BOOL last ) -{ - SIZE_T block_size = (pArena->size & ARENA_SIZE_MASK) + sizeof(*pArena); - struct entry *list = find_free_list( heap, block_size, last ); - if (last) - { - /* insert at end of free list, i.e. before the next free list entry */ - list_add_before( &list->entry, &pArena->entry ); - } - else - { - /* insert at head of free list */ - list_add_after( &list->entry, &pArena->entry ); - } -} - - static SUBHEAP *find_subheap( const HEAP *heap, const struct block *block, BOOL heap_walk ) { SUBHEAP *subheap; @@ -692,7 +670,7 @@ static inline BOOL HEAP_Decommit( SUBHEAP *subheap, void *ptr ) static void create_free_block( SUBHEAP *subheap, struct block *block, SIZE_T block_size ) { const char *end = (char *)block + block_size, *commit_end = subheap_commit_end( subheap ); - struct entry *entry = (struct entry *)block; + struct entry *entry = (struct entry *)block, *list; HEAP *heap = subheap->heap; DWORD flags = heap->flags; struct block *next; @@ -724,7 +702,9 @@ static void create_free_block( SUBHEAP *subheap, struct block *block, SIZE_T blo *((struct block **)next - 1) = block; }
- HEAP_InsertFreeBlock( heap, entry, !next ); + list = find_free_list( heap, block_get_size( block ), !next ); + if (!next) list_add_before( &list->entry, &entry->entry ); + else list_add_after( &list->entry, &entry->entry ); }
From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/ntdll/heap.c | 71 +++++++++++++++++------------------------------ 1 file changed, 26 insertions(+), 45 deletions(-)
diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 5fe23a3502e..51fdbc370f5 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -708,70 +708,51 @@ static void create_free_block( SUBHEAP *subheap, struct block *block, SIZE_T blo }
-/*********************************************************************** - * 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 ) +static void free_used_block( SUBHEAP *subheap, struct block *block ) { HEAP *heap = subheap->heap; - ARENA_FREE *pFree; - SIZE_T size; + struct entry *entry; + SIZE_T block_size;
if (heap->pending_free) { - ARENA_INUSE *prev = heap->pending_free[heap->pending_pos]; - heap->pending_free[heap->pending_pos] = pArena; + struct block *tmp = heap->pending_free[heap->pending_pos]; + heap->pending_free[heap->pending_pos] = block; heap->pending_pos = (heap->pending_pos + 1) % MAX_FREE_PENDING; - block_set_type( pArena, ARENA_PENDING_MAGIC ); - mark_block_free( pArena + 1, pArena->size & ARENA_SIZE_MASK, heap->flags ); - if (!prev) return; - pArena = prev; - subheap = find_subheap( heap, pArena, FALSE ); + block_set_type( block, ARENA_PENDING_MAGIC ); + mark_block_free( block + 1, block->size & ARENA_SIZE_MASK, heap->flags ); + if (!(block = tmp) || !(subheap = find_subheap( heap, block, FALSE ))) return; }
- /* Check if we can merge with previous block */ - - size = (pArena->size & ARENA_SIZE_MASK) + sizeof(*pArena); - if (pArena->size & ARENA_FLAG_PREV_FREE) + block_size = (block->size & ARENA_SIZE_MASK) + sizeof(*block); + if (block->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 */ - list_remove( &pFree->entry ); + /* merge with previous block if it is free */ + block = *((struct block **)block - 1); + block_size += (block->size & ARENA_SIZE_MASK) + sizeof(*entry); + entry = (struct entry *)block; + list_remove( &entry->entry ); } - else pFree = (ARENA_FREE *)pArena; - - /* Create a free block */ - - create_free_block( subheap, (struct block *)pFree, size ); - size = (pFree->size & ARENA_SIZE_MASK) + sizeof(ARENA_FREE); - if ((char *)pFree + size < (char *)subheap->base + subheap->size) - return; /* Not the last block, so nothing more to do */ + else entry = (struct entry *)block;
- /* Free the whole sub-heap if it's empty and not the original one */ + create_free_block( subheap, block, block_size ); + block_size = (block->size & ARENA_SIZE_MASK) + sizeof(*entry); + if ((char *)block + block_size < (char *)subheap->base + subheap->size) return; /* not the last block */
- if (((char *)pFree == (char *)subheap->base + subheap->headerSize) && + if (((char *)block == (char *)subheap->base + subheap->headerSize) && (subheap != &subheap->heap->subheap)) { + /* free the subheap if it's empty and not the main one */ void *addr = subheap->base; + SIZE_T size = 0;
- size = 0; - /* Remove the free block from the list */ - list_remove( &pFree->entry ); - /* Remove the subheap from the list */ + list_remove( &entry->entry ); list_remove( &subheap->entry ); - /* Free the memory */ - subheap->magic = 0; NtFreeVirtualMemory( NtCurrentProcess(), &addr, &size, MEM_RELEASE ); return; }
- /* Decommit the end of the heap */ - - if (!(subheap->heap->shared)) HEAP_Decommit( subheap, pFree + 1 ); + if (!heap->shared) HEAP_Decommit( subheap, entry + 1 ); }
@@ -1568,7 +1549,7 @@ static NTSTATUS heap_free( HEAP *heap, void *ptr )
if (!(block = unsafe_block_from_ptr( heap, ptr, &subheap ))) return STATUS_INVALID_PARAMETER; if (!subheap) free_large_block( heap, ptr ); - else HEAP_MakeInUseBlockFree( subheap, block ); + else free_used_block( subheap, block );
return STATUS_SUCCESS; } @@ -1640,7 +1621,7 @@ static NTSTATUS heap_reallocate( HEAP *heap, ULONG flags, void *ptr, SIZE_T size memcpy( *ret, block + 1, old_size ); if (flags & HEAP_ZERO_MEMORY) memset( (char *)*ret + old_size, 0, size - old_size ); notify_free( ptr ); - HEAP_MakeInUseBlockFree( subheap, block ); + free_used_block( subheap, block ); return STATUS_SUCCESS; } }
From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/ntdll/heap.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-)
diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 51fdbc370f5..1093fde41ca 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -720,39 +720,35 @@ static void free_used_block( SUBHEAP *subheap, struct block *block ) heap->pending_free[heap->pending_pos] = block; heap->pending_pos = (heap->pending_pos + 1) % MAX_FREE_PENDING; block_set_type( block, ARENA_PENDING_MAGIC ); - mark_block_free( block + 1, block->size & ARENA_SIZE_MASK, heap->flags ); + mark_block_free( block + 1, block_get_size( block ) - sizeof(*block), heap->flags ); if (!(block = tmp) || !(subheap = find_subheap( heap, block, FALSE ))) return; }
- block_size = (block->size & ARENA_SIZE_MASK) + sizeof(*block); - if (block->size & ARENA_FLAG_PREV_FREE) + block_size = block_get_size( block ); + if (block_get_flags( block ) & ARENA_FLAG_PREV_FREE) { /* merge with previous block if it is free */ block = *((struct block **)block - 1); - block_size += (block->size & ARENA_SIZE_MASK) + sizeof(*entry); + block_size += block_get_size( block ); entry = (struct entry *)block; list_remove( &entry->entry ); } else entry = (struct entry *)block;
create_free_block( subheap, block, block_size ); - block_size = (block->size & ARENA_SIZE_MASK) + sizeof(*entry); - if ((char *)block + block_size < (char *)subheap->base + subheap->size) return; /* not the last block */ + if (next_block( subheap, block )) return; /* not the last block */
- if (((char *)block == (char *)subheap->base + subheap->headerSize) && - (subheap != &subheap->heap->subheap)) + if (block == first_block( subheap ) && subheap != &heap->subheap) { /* free the subheap if it's empty and not the main one */ - void *addr = subheap->base; + void *addr = subheap_base( subheap ); SIZE_T size = 0;
list_remove( &entry->entry ); list_remove( &subheap->entry ); NtFreeVirtualMemory( NtCurrentProcess(), &addr, &size, MEM_RELEASE ); - return; } - - if (!heap->shared) HEAP_Decommit( subheap, entry + 1 ); + else if (!heap->shared) HEAP_Decommit( subheap, entry + 1 ); }
From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/ntdll/heap.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 1093fde41ca..8e578d19d05 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -649,8 +649,7 @@ static inline BOOL HEAP_Decommit( SUBHEAP *subheap, void *ptr ) SIZE_T decommit_size; SIZE_T size = (char *)ptr - (char *)subheap->base;
- /* round to next block and add one full block */ - size = ((size + COMMIT_MASK) & ~COMMIT_MASK) + COMMIT_MASK + 1; + size = ((size + COMMIT_MASK) & ~COMMIT_MASK); size = max( size, subheap->min_commit ); if (size >= subheap->commitSize) return TRUE; decommit_size = subheap->commitSize - size; @@ -748,7 +747,11 @@ static void free_used_block( SUBHEAP *subheap, struct block *block ) list_remove( &subheap->entry ); NtFreeVirtualMemory( NtCurrentProcess(), &addr, &size, MEM_RELEASE ); } - else if (!heap->shared) HEAP_Decommit( subheap, entry + 1 ); + else if (!heap->shared) + { + /* keep room for a full commited block as hysteresis */ + HEAP_Decommit( subheap, (char *)(entry + 1) + (COMMIT_MASK + 1) ); + } }
From: Rémi Bernon rbernon@codeweavers.com
And rename them to subheap_commit / subheap_decommit.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/ntdll/heap.c | 81 +++++++++++++++++++++++------------------------ 1 file changed, 40 insertions(+), 41 deletions(-)
diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 8e578d19d05..40fbd379772 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -125,6 +125,7 @@ typedef struct
C_ASSERT( sizeof(ARENA_LARGE) % LARGE_ALIGNMENT == 0 );
+#define ROUND_ADDR(addr, mask) ((void *)((UINT_PTR)(addr) & ~(UINT_PTR)(mask))) #define ROUND_SIZE(size) ((((size) + ALIGNMENT - 1) & ~(ALIGNMENT-1)) + ARENA_OFFSET)
/* minimum data size (without arenas) of an allocated block */ @@ -612,56 +613,54 @@ static SUBHEAP *find_subheap( const HEAP *heap, const struct block *block, BOOL }
-/*********************************************************************** - * HEAP_Commit - * - * Make sure the heap storage is committed for a given size in the specified arena. - */ -static inline BOOL HEAP_Commit( SUBHEAP *subheap, ARENA_INUSE *pArena, SIZE_T data_size ) -{ - void *ptr = (char *)(pArena + 1) + data_size + sizeof(ARENA_FREE); - SIZE_T size = (char *)ptr - (char *)subheap->base; - size = (size + COMMIT_MASK) & ~COMMIT_MASK; - if (size > subheap->size) size = subheap->size; - if (size <= subheap->commitSize) return TRUE; - size -= subheap->commitSize; - ptr = (char *)subheap->base + subheap->commitSize; - if (NtAllocateVirtualMemory( NtCurrentProcess(), &ptr, 0, - &size, MEM_COMMIT, get_protection_type( subheap->heap->flags ) )) - { - WARN("Could not commit %08lx bytes at %p for heap %p\n", - size, ptr, subheap->heap ); +static inline BOOL subheap_commit( SUBHEAP *subheap, const struct block *block, SIZE_T data_size ) +{ + const char *end = (char *)subheap_base( subheap ) + subheap_size( subheap ), *commit_end; + HEAP *heap = subheap->heap; + ULONG flags = heap->flags; + SIZE_T size; + void *addr; + + commit_end = (char *)(block + 1) + data_size + sizeof(ARENA_FREE); + commit_end = ROUND_ADDR((char *)commit_end + COMMIT_MASK, COMMIT_MASK); + + if (commit_end > end) commit_end = end; + if (commit_end <= (char *)subheap_commit_end( subheap )) return TRUE; + + addr = (void *)subheap_commit_end( subheap ); + size = commit_end - (char *)addr; + + if (NtAllocateVirtualMemory( NtCurrentProcess(), &addr, 0, &size, MEM_COMMIT, + get_protection_type( flags ) )) + { + WARN( "Could not commit %#Ix bytes at %p for heap %p\n", size, addr, heap ); return FALSE; } - subheap->commitSize += size; + + subheap->commitSize = (char *)commit_end - (char *)subheap_base( subheap ); return TRUE; }
- -/*********************************************************************** - * HEAP_Decommit - * - * If possible, decommit the heap storage from (including) 'ptr'. - */ -static inline BOOL HEAP_Decommit( SUBHEAP *subheap, void *ptr ) +static inline BOOL subheap_decommit( SUBHEAP *subheap, const void *commit_end ) { + HEAP *heap = subheap->heap; + SIZE_T size; void *addr; - SIZE_T decommit_size; - SIZE_T size = (char *)ptr - (char *)subheap->base;
- size = ((size + COMMIT_MASK) & ~COMMIT_MASK); - size = max( size, subheap->min_commit ); - if (size >= subheap->commitSize) return TRUE; - decommit_size = subheap->commitSize - size; - addr = (char *)subheap->base + size; + commit_end = ROUND_ADDR((char *)commit_end + COMMIT_MASK, COMMIT_MASK); + commit_end = max( (char *)commit_end, (char *)subheap_base( subheap ) + subheap->min_commit ); + if (commit_end >= subheap_commit_end( subheap )) return TRUE;
- if (NtFreeVirtualMemory( NtCurrentProcess(), &addr, &decommit_size, MEM_DECOMMIT )) + size = (char *)subheap_commit_end( subheap ) - (char *)commit_end; + addr = (void *)commit_end; + + if (NtFreeVirtualMemory( NtCurrentProcess(), &addr, &size, MEM_DECOMMIT )) { - WARN("Could not decommit %08lx bytes at %p for heap %p\n", - decommit_size, (char *)subheap->base + size, subheap->heap ); + WARN( "Could not decommit %#Ix bytes at %p for heap %p\n", size, addr, heap ); return FALSE; } - subheap->commitSize -= decommit_size; + + subheap->commitSize = (char *)commit_end - (char *)subheap_base( subheap ); return TRUE; }
@@ -750,7 +749,7 @@ static void free_used_block( SUBHEAP *subheap, struct block *block ) else if (!heap->shared) { /* keep room for a full commited block as hysteresis */ - HEAP_Decommit( subheap, (char *)(entry + 1) + (COMMIT_MASK + 1) ); + subheap_decommit( subheap, (char *)(entry + 1) + (COMMIT_MASK + 1) ); } }
@@ -1032,7 +1031,7 @@ static struct block *find_free_block( HEAP *heap, SIZE_T data_size, SUBHEAP **su if (block_get_size( block ) - sizeof(*block) >= data_size) { *subheap = find_subheap( heap, block, FALSE ); - if (!HEAP_Commit( *subheap, block, data_size )) return NULL; + if (!subheap_commit( *subheap, block, data_size )) return NULL; list_remove( &entry->entry ); return block; } @@ -1609,7 +1608,7 @@ static NTSTATUS heap_reallocate( HEAP *heap, ULONG flags, void *ptr, SIZE_T size struct entry *entry = (struct entry *)next; list_remove( &entry->entry ); old_data_size += block_get_size( next ); - if (!HEAP_Commit( subheap, block, data_size )) return STATUS_NO_MEMORY; + if (!subheap_commit( subheap, block, data_size )) return STATUS_NO_MEMORY; notify_realloc( block + 1, old_size, size ); shrink_used_block( subheap, block, block_get_flags( block ), old_data_size, data_size, size ); }
From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/ntdll/heap.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 40fbd379772..540625bff27 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -271,6 +271,11 @@ static inline SIZE_T subheap_size( const SUBHEAP *subheap ) return subheap->size; }
+static inline SIZE_T subheap_overhead( const SUBHEAP *subheap ) +{ + return subheap->headerSize; +} + static inline const void *subheap_commit_end( const SUBHEAP *subheap ) { return (char *)subheap_base( subheap ) + subheap->commitSize; @@ -499,7 +504,7 @@ static void heap_dump( const HEAP *heap )
if (!check_subheap( subheap )) return;
- overhead += (char *)first_block( subheap ) - base; + overhead += subheap_overhead( subheap ); for (block = first_block( subheap ); block; block = next_block( subheap, block )) { if (block_get_flags( block ) & ARENA_FLAG_FREE) @@ -1008,7 +1013,7 @@ static SUBHEAP *HEAP_CreateSubHeap( HEAP *heap, LPVOID address, DWORD flags,
/* Create the first free block */
- create_free_block( subheap, first_block( subheap ), subheap->size - subheap->headerSize ); + create_free_block( subheap, first_block( subheap ), subheap_size( subheap ) - subheap_overhead( subheap ) );
return subheap; } @@ -1863,7 +1868,7 @@ static NTSTATUS heap_walk( const HEAP *heap, struct rtl_heap_entry *entry ) subheap = LIST_ENTRY( next, SUBHEAP, entry ); base = subheap_base( subheap ); entry->lpData = base; - entry->cbData = (char *)first_block( subheap ) - base; + entry->cbData = subheap_overhead( subheap ); entry->cbOverhead = 0; entry->iRegionIndex = 0; entry->wFlags = RTL_HEAP_ENTRY_REGION;