Alexandre Julliard : ntdll: Store reserved areas in the Unix library.

Alexandre Julliard julliard at winehq.org
Mon May 18 15:00:12 CDT 2020


Module: wine
Branch: master
Commit: aaa654abd678ce06ce34ca260425d0b79e223b2e
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=aaa654abd678ce06ce34ca260425d0b79e223b2e

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Sun May 17 11:05:02 2020 +0200

ntdll: Store reserved areas in the Unix library.

Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/ntdll/unix/loader.c  |   8 +++
 dlls/ntdll/unix/virtual.c | 160 +++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 151 insertions(+), 17 deletions(-)

diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c
index 0591c77434..c974f526a1 100644
--- a/dlls/ntdll/unix/loader.c
+++ b/dlls/ntdll/unix/loader.c
@@ -528,6 +528,13 @@ void __wine_main( int argc, char *argv[], char *envp[] )
     __wine_set_unix_funcs( NTDLL_UNIXLIB_VERSION, &unix_funcs );
 }
 
+
+static int add_area( void *base, size_t size, void *arg )
+{
+    mmap_add_reserved_area( base, size );
+    return 0;
+}
+
 /***********************************************************************
  *           __wine_init_unix_lib
  *
@@ -540,6 +547,7 @@ NTSTATUS __cdecl __wine_init_unix_lib( HMODULE module, const void *ptr_in, void
     map_so_dll( nt, module );
     fixup_ntdll_imports( &__wine_spec_nt_header, module );
     *(struct unix_funcs **)ptr_out = &unix_funcs;
+    wine_mmap_enum_reserved_areas( add_area, NULL, 0 );
     return STATUS_SUCCESS;
 }
 
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c
index 972cbfdca8..88cd1eb1cf 100644
--- a/dlls/ntdll/unix/virtual.c
+++ b/dlls/ntdll/unix/virtual.c
@@ -45,7 +45,7 @@
 #include "winnt.h"
 #include "winternl.h"
 #include "unix_private.h"
-#include "wine/library.h"
+#include "wine/list.h"
 
 struct preload_info
 {
@@ -53,6 +53,15 @@ struct preload_info
     size_t size;
 };
 
+struct reserved_area
+{
+    struct list entry;
+    void       *base;
+    size_t      size;
+};
+
+static struct list reserved_areas = LIST_INIT(reserved_areas);
+
 static const unsigned int granularity_mask = 0xffff;  /* reserved areas have 64k granularity */
 
 extern IMAGE_NT_HEADERS __wine_spec_nt_header;
@@ -202,36 +211,153 @@ static void mmap_init( const struct preload_info *preload_info )
 
 void CDECL mmap_add_reserved_area( void *addr, SIZE_T size )
 {
-    wine_mmap_add_reserved_area( addr, size );
+    struct reserved_area *area;
+    struct list *ptr;
+
+    if (!((char *)addr + size)) size--;  /* avoid wrap-around */
+
+    LIST_FOR_EACH( ptr, &reserved_areas )
+    {
+        area = LIST_ENTRY( ptr, struct reserved_area, entry );
+        if (area->base > addr)
+        {
+            /* try to merge with the next one */
+            if ((char *)addr + size == (char *)area->base)
+            {
+                area->base = addr;
+                area->size += size;
+                return;
+            }
+            break;
+        }
+        else if ((char *)area->base + area->size == (char *)addr)
+        {
+            /* merge with the previous one */
+            area->size += size;
+
+            /* try to merge with the next one too */
+            if ((ptr = list_next( &reserved_areas, ptr )))
+            {
+                struct reserved_area *next = LIST_ENTRY( ptr, struct reserved_area, entry );
+                if ((char *)addr + size == (char *)next->base)
+                {
+                    area->size += next->size;
+                    list_remove( &next->entry );
+                    free( next );
+                }
+            }
+            return;
+        }
+    }
+
+    if ((area = malloc( sizeof(*area) )))
+    {
+        area->base = addr;
+        area->size = size;
+        list_add_before( ptr, &area->entry );
+    }
 }
 
 void CDECL mmap_remove_reserved_area( void *addr, SIZE_T size )
 {
-    wine_mmap_remove_reserved_area( addr, size, 0 );
-}
+    struct reserved_area *area;
+    struct list *ptr;
 
-int CDECL mmap_is_in_reserved_area( void *addr, SIZE_T size )
-{
-    return wine_mmap_is_in_reserved_area( addr, size );
+    if (!((char *)addr + size)) size--;  /* avoid wrap-around */
+
+    ptr = list_head( &reserved_areas );
+    /* find the first area covering address */
+    while (ptr)
+    {
+        area = LIST_ENTRY( ptr, struct reserved_area, entry );
+        if ((char *)area->base >= (char *)addr + size) break;  /* outside the range */
+        if ((char *)area->base + area->size > (char *)addr)  /* overlaps range */
+        {
+            if (area->base >= addr)
+            {
+                if ((char *)area->base + area->size > (char *)addr + size)
+                {
+                    /* range overlaps beginning of area only -> shrink area */
+                    area->size -= (char *)addr + size - (char *)area->base;
+                    area->base = (char *)addr + size;
+                    break;
+                }
+                else
+                {
+                    /* range contains the whole area -> remove area completely */
+                    ptr = list_next( &reserved_areas, ptr );
+                    list_remove( &area->entry );
+                    free( area );
+                    continue;
+                }
+            }
+            else
+            {
+                if ((char *)area->base + area->size > (char *)addr + size)
+                {
+                    /* range is in the middle of area -> split area in two */
+                    struct reserved_area *new_area = malloc( sizeof(*new_area) );
+                    if (new_area)
+                    {
+                        new_area->base = (char *)addr + size;
+                        new_area->size = (char *)area->base + area->size - (char *)new_area->base;
+                        list_add_after( ptr, &new_area->entry );
+                    }
+                    else size = (char *)area->base + area->size - (char *)addr;
+                    area->size = (char *)addr - (char *)area->base;
+                    break;
+                }
+                else
+                {
+                    /* range overlaps end of area only -> shrink area */
+                    area->size = (char *)addr - (char *)area->base;
+                }
+            }
+        }
+        ptr = list_next( &reserved_areas, ptr );
+    }
 }
 
-struct enum_data
+int CDECL mmap_is_in_reserved_area( void *addr, SIZE_T size )
 {
-    int (CDECL *enum_func)( void *base, SIZE_T size, void *arg );
-    void *arg;
-};
+    struct reserved_area *area;
+    struct list *ptr;
 
-static int enum_wrapper( void *base, size_t size, void *arg )
-{
-    struct enum_data *data = arg;
-    return data->enum_func( base, size, data->arg );
+    LIST_FOR_EACH( ptr, &reserved_areas )
+    {
+        area = LIST_ENTRY( ptr, struct reserved_area, entry );
+        if (area->base > addr) break;
+        if ((char *)area->base + area->size <= (char *)addr) continue;
+        /* area must contain block completely */
+        if ((char *)area->base + area->size < (char *)addr + size) return -1;
+        return 1;
+    }
+    return 0;
 }
 
 int CDECL mmap_enum_reserved_areas( int (CDECL *enum_func)(void *base, SIZE_T size, void *arg),
                                     void *arg, int top_down )
 {
-    struct enum_data data = { enum_func, arg };
-    return wine_mmap_enum_reserved_areas( enum_wrapper, &data, top_down );
+    int ret = 0;
+    struct list *ptr;
+
+    if (top_down)
+    {
+        for (ptr = reserved_areas.prev; ptr != &reserved_areas; ptr = ptr->prev)
+        {
+            struct reserved_area *area = LIST_ENTRY( ptr, struct reserved_area, entry );
+            if ((ret = enum_func( area->base, area->size, arg ))) break;
+        }
+    }
+    else
+    {
+        for (ptr = reserved_areas.next; ptr != &reserved_areas; ptr = ptr->next)
+        {
+            struct reserved_area *area = LIST_ENTRY( ptr, struct reserved_area, entry );
+            if ((ret = enum_func( area->base, area->size, arg ))) break;
+        }
+    }
+    return ret;
 }
 
 void virtual_init(void)




More information about the wine-cvs mailing list