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