Alexandre Julliard : ntdll:
Support memory allocations inside reserved areas.
Alexandre Julliard
julliard at wine.codeweavers.com
Mon Jul 24 13:15:05 CDT 2006
Module: wine
Branch: refs/heads/master
Commit: cc297050f9e8b1f247991a0ef56b51c1fe4a5df2
URL: http://source.winehq.org/git/?p=wine.git;a=commit;h=cc297050f9e8b1f247991a0ef56b51c1fe4a5df2
Author: Alexandre Julliard <julliard at winehq.org>
Date: Mon Jul 24 14:00:19 2006 +0200
ntdll: Support memory allocations inside reserved areas.
---
dlls/ntdll/virtual.c | 169 ++++++++++++++++++++++++++++++++++++--------------
1 files changed, 123 insertions(+), 46 deletions(-)
diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c
index 20a94b9..96aca43 100644
--- a/dlls/ntdll/virtual.c
+++ b/dlls/ntdll/virtual.c
@@ -140,6 +140,8 @@ #define VIRTUAL_DEBUG_DUMP_VIEW(view) \
do { if (TRACE_ON(virtual)) VIRTUAL_DumpView(view); } while (0)
static void *user_space_limit = USER_SPACE_LIMIT;
+static void *preload_reserve_start;
+static void *preload_reserve_end;
/***********************************************************************
@@ -267,6 +269,53 @@ static struct file_view *find_view_range
/***********************************************************************
+ * find_free_area
+ *
+ * Find a free area between views inside the specified range.
+ * The csVirtual section must be held by caller.
+ */
+static void *find_free_area( void *base, void *end, size_t size, size_t mask, int top_down )
+{
+ struct list *ptr;
+ void *start;
+
+ if (top_down)
+ {
+ start = ROUND_ADDR( (char *)end - size, mask );
+ if (start >= end || start < base) return NULL;
+
+ for (ptr = views_list.prev; ptr != &views_list; ptr = ptr->prev)
+ {
+ struct file_view *view = LIST_ENTRY( ptr, struct file_view, entry );
+
+ if ((char *)view->base + view->size <= (char *)start) break;
+ if ((char *)view->base >= (char *)start + size) continue;
+ start = ROUND_ADDR( (char *)view->base - size, mask );
+ /* stop if remaining space is not large enough */
+ if (!start || start >= end || start < base) return NULL;
+ }
+ }
+ else
+ {
+ start = ROUND_ADDR( (char *)base + mask, mask );
+ if (start >= end || (char *)end - (char *)start < size) return NULL;
+
+ for (ptr = views_list.next; ptr != &views_list; ptr = ptr->next)
+ {
+ struct file_view *view = LIST_ENTRY( ptr, struct file_view, entry );
+
+ if ((char *)view->base >= (char *)start + size) break;
+ if ((char *)view->base + view->size <= (char *)start) continue;
+ start = ROUND_ADDR( (char *)view->base + view->size + mask, mask );
+ /* stop if remaining space is not large enough */
+ if (!start || start >= end || (char *)end - (char *)start < size) return NULL;
+ }
+ }
+ return start;
+}
+
+
+/***********************************************************************
* add_reserved_area
*
* Add a reserved area to the list maintained by libwine.
@@ -291,46 +340,6 @@ static void add_reserved_area( void *add
/***********************************************************************
- * remove_reserved_area
- *
- * Remove a reserved area from the list maintained by libwine.
- * The csVirtual section must be held by caller.
- */
-static void remove_reserved_area( void *addr, size_t size )
-{
- struct file_view *view;
-
- LIST_FOR_EACH_ENTRY( view, &views_list, struct file_view, entry )
- {
- if ((char *)view->base >= (char *)addr + size) break;
- if ((char *)view->base + view->size <= (char *)addr) continue;
- /* now we have an overlapping view */
- if (view->base > addr)
- {
- wine_mmap_remove_reserved_area( addr, (char *)view->base - (char *)addr, TRUE );
- size -= (char *)view->base - (char *)addr;
- addr = view->base;
- }
- if ((char *)view->base + view->size >= (char *)addr + size)
- {
- /* view covers all the remaining area */
- wine_mmap_remove_reserved_area( addr, size, FALSE );
- size = 0;
- break;
- }
- else /* view covers only part of the area */
- {
- wine_mmap_remove_reserved_area( addr, (char *)view->base + view->size - (char *)addr, FALSE );
- size -= (char *)view->base + view->size - (char *)addr;
- addr = (char *)view->base + view->size;
- }
- }
- /* remove remaining space */
- if (size) wine_mmap_remove_reserved_area( addr, size, TRUE );
-}
-
-
-/***********************************************************************
* is_beyond_limit
*
* Check if an address range goes beyond a given limit.
@@ -578,6 +587,55 @@ static inline void *unmap_extra_space( v
}
+struct alloc_area
+{
+ size_t size;
+ size_t mask;
+ int top_down;
+ void *result;
+};
+
+/***********************************************************************
+ * alloc_reserved_area_callback
+ *
+ * Try to map some space inside a reserved area. Callback for wine_mmap_enum_reserved_areas.
+ */
+static int alloc_reserved_area_callback( void *start, size_t size, void *arg )
+{
+ static void * const address_space_start = (void *)0x110000;
+ struct alloc_area *alloc = arg;
+ void *end = (char *)start + size;
+
+ if (start < address_space_start) start = address_space_start;
+ if (user_space_limit && end > user_space_limit) end = user_space_limit;
+ if (start >= end) return 0;
+
+ /* make sure we don't touch the preloader reserved range */
+ if (preload_reserve_end >= start)
+ {
+ if (preload_reserve_end >= end)
+ {
+ if (preload_reserve_start <= start) return 0; /* no space in that area */
+ if (preload_reserve_start < end) end = preload_reserve_start;
+ }
+ else if (preload_reserve_start <= start) start = preload_reserve_end;
+ else
+ {
+ /* range is split in two by the preloader reservation, try first part */
+ if ((alloc->result = find_free_area( start, preload_reserve_start, alloc->size,
+ alloc->mask, alloc->top_down )))
+ return 1;
+ /* then fall through to try second part */
+ start = preload_reserve_end;
+ }
+ }
+ if ((alloc->result = find_free_area( start, end, alloc->size, alloc->mask, alloc->top_down )))
+ return 1;
+
+ return 0;
+}
+
+
/***********************************************************************
* map_view
*
@@ -627,6 +685,19 @@ static NTSTATUS map_view( struct file_vi
else
{
size_t view_size = size + mask + 1;
+ struct alloc_area alloc;
+
+ alloc.size = size;
+ alloc.mask = mask;
+ alloc.top_down = top_down;
+ if (wine_mmap_enum_reserved_areas( alloc_reserved_area_callback, &alloc, top_down ))
+ {
+ ptr = alloc.result;
+ TRACE( "got mem in reserved area %p-%p\n", ptr, (char *)ptr + size );
+ if (wine_anon_mmap( ptr, size, VIRTUAL_GetUnixProt(vprot), MAP_FIXED ) != ptr)
+ return STATUS_INVALID_PARAMETER;
+ goto done;
+ }
for (;;)
{
@@ -635,13 +706,14 @@ static NTSTATUS map_view( struct file_vi
if (errno == ENOMEM) return STATUS_NO_MEMORY;
return STATUS_INVALID_PARAMETER;
}
+ TRACE( "got mem with anon mmap %p-%p\n", ptr, (char *)ptr + size );
/* if we got something beyond the user limit, unmap it and retry */
if (is_beyond_limit( ptr, view_size, user_space_limit )) add_reserved_area( ptr, view_size );
else break;
}
ptr = unmap_extra_space( ptr, view_size, size, mask );
}
-
+done:
status = create_view( view_ret, ptr, size, vprot );
if (status != STATUS_SUCCESS) unmap_area( ptr, size );
return status;
@@ -1135,6 +1207,7 @@ BOOL is_current_process( HANDLE handle )
*/
static inline void virtual_init(void)
{
+ const char *preload;
#ifndef page_mask
page_size = getpagesize();
page_mask = page_size - 1;
@@ -1143,6 +1216,15 @@ #ifndef page_mask
page_shift = 0;
while ((1 << page_shift) != page_size) page_shift++;
#endif /* page_mask */
+ if ((preload = getenv("WINEPRELOADRESERVE")))
+ {
+ unsigned long start, end;
+ if (sscanf( preload, "%lx-%lx", &start, &end ) == 2)
+ {
+ preload_reserve_start = (void *)start;
+ preload_reserve_end = (void *)end;
+ }
+ }
}
@@ -1217,14 +1299,9 @@ BOOL VIRTUAL_HasMapping( LPCVOID addr )
*/
void VIRTUAL_UseLargeAddressSpace(void)
{
- if (user_space_limit >= ADDRESS_SPACE_LIMIT) return;
/* no large address space on win9x */
if (NtCurrentTeb()->Peb->OSPlatformId != VER_PLATFORM_WIN32_NT) return;
-
- RtlEnterCriticalSection( &csVirtual );
- remove_reserved_area( user_space_limit, (char *)ADDRESS_SPACE_LIMIT - (char *)user_space_limit );
user_space_limit = ADDRESS_SPACE_LIMIT;
- RtlLeaveCriticalSection( &csVirtual );
}
More information about the wine-cvs
mailing list