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