ntdll: Allow map_view() to allocate fixed memory between reserved area and non-reserved area.
Signed-off-by: Akihiro Sagawa <sagawa.aki@gmail.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
b3a698e501
commit
74b7fcfbdb
|
@ -404,6 +404,42 @@ static void remove_reserved_area( void *addr, size_t size )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct area_boundary
|
||||||
|
{
|
||||||
|
void *base;
|
||||||
|
size_t size;
|
||||||
|
void *boundary;
|
||||||
|
};
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* get_area_boundary_callback
|
||||||
|
*
|
||||||
|
* Get lowest boundary address between reserved area and non-reserved area
|
||||||
|
* in the specified region. If no boundaries are found, result is NULL.
|
||||||
|
* The csVirtual section must be held by caller.
|
||||||
|
*/
|
||||||
|
static int get_area_boundary_callback( void *start, size_t size, void *arg )
|
||||||
|
{
|
||||||
|
struct area_boundary *area = arg;
|
||||||
|
void *end = (char *)start + size;
|
||||||
|
|
||||||
|
area->boundary = NULL;
|
||||||
|
if (area->base >= end) return 0;
|
||||||
|
if ((char *)start >= (char *)area->base + area->size) return 1;
|
||||||
|
if (area->base >= start)
|
||||||
|
{
|
||||||
|
if ((char *)area->base + area->size > (char *)end)
|
||||||
|
{
|
||||||
|
area->boundary = end;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
area->boundary = start;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* is_beyond_limit
|
* is_beyond_limit
|
||||||
*
|
*
|
||||||
|
@ -423,12 +459,32 @@ static inline BOOL is_beyond_limit( const void *addr, size_t size, const void *l
|
||||||
*/
|
*/
|
||||||
static inline void unmap_area( void *addr, size_t size )
|
static inline void unmap_area( void *addr, size_t size )
|
||||||
{
|
{
|
||||||
if (wine_mmap_is_in_reserved_area( addr, size ))
|
switch (wine_mmap_is_in_reserved_area( addr, size ))
|
||||||
|
{
|
||||||
|
case -1: /* partially in a reserved area */
|
||||||
|
{
|
||||||
|
struct area_boundary area;
|
||||||
|
size_t lower_size;
|
||||||
|
area.base = addr;
|
||||||
|
area.size = size;
|
||||||
|
wine_mmap_enum_reserved_areas( get_area_boundary_callback, &area, 0 );
|
||||||
|
assert( area.boundary );
|
||||||
|
lower_size = (char *)area.boundary - (char *)addr;
|
||||||
|
unmap_area( addr, lower_size );
|
||||||
|
unmap_area( area.boundary, size - lower_size );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 1: /* in a reserved area */
|
||||||
wine_anon_mmap( addr, size, PROT_NONE, MAP_NORESERVE | MAP_FIXED );
|
wine_anon_mmap( addr, size, PROT_NONE, MAP_NORESERVE | MAP_FIXED );
|
||||||
else if (is_beyond_limit( addr, size, user_space_limit ))
|
break;
|
||||||
add_reserved_area( addr, size );
|
default:
|
||||||
else
|
case 0: /* not in a reserved area */
|
||||||
munmap( addr, size );
|
if (is_beyond_limit( addr, size, user_space_limit ))
|
||||||
|
add_reserved_area( addr, size );
|
||||||
|
else
|
||||||
|
munmap( addr, size );
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -773,6 +829,62 @@ static int alloc_reserved_area_callback( void *start, size_t size, void *arg )
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* map_fixed_area
|
||||||
|
*
|
||||||
|
* mmap the fixed memory area.
|
||||||
|
* The csVirtual section must be held by caller.
|
||||||
|
*/
|
||||||
|
static NTSTATUS map_fixed_area( void *base, size_t size, unsigned int vprot )
|
||||||
|
{
|
||||||
|
void *ptr;
|
||||||
|
|
||||||
|
switch (wine_mmap_is_in_reserved_area( base, size ))
|
||||||
|
{
|
||||||
|
case -1: /* partially in a reserved area */
|
||||||
|
{
|
||||||
|
NTSTATUS status;
|
||||||
|
struct area_boundary area;
|
||||||
|
size_t lower_size;
|
||||||
|
area.base = base;
|
||||||
|
area.size = size;
|
||||||
|
wine_mmap_enum_reserved_areas( get_area_boundary_callback, &area, 0 );
|
||||||
|
assert( area.boundary );
|
||||||
|
lower_size = (char *)area.boundary - (char *)base;
|
||||||
|
status = map_fixed_area( base, lower_size, vprot );
|
||||||
|
if (status == STATUS_SUCCESS)
|
||||||
|
{
|
||||||
|
status = map_fixed_area( area.boundary, size - lower_size, vprot);
|
||||||
|
if (status != STATUS_SUCCESS) unmap_area( base, lower_size );
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
case 0: /* not in a reserved area, do a normal allocation */
|
||||||
|
if ((ptr = wine_anon_mmap( base, size, VIRTUAL_GetUnixProt(vprot), 0 )) == (void *)-1)
|
||||||
|
{
|
||||||
|
if (errno == ENOMEM) return STATUS_NO_MEMORY;
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
if (ptr != base)
|
||||||
|
{
|
||||||
|
/* We couldn't get the address we wanted */
|
||||||
|
if (is_beyond_limit( ptr, size, user_space_limit )) add_reserved_area( ptr, size );
|
||||||
|
else munmap( ptr, size );
|
||||||
|
return STATUS_CONFLICTING_ADDRESSES;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
case 1: /* in a reserved area, make sure the address is available */
|
||||||
|
if (find_view_range( base, size )) return STATUS_CONFLICTING_ADDRESSES;
|
||||||
|
/* replace the reserved area by our mapping */
|
||||||
|
if ((ptr = wine_anon_mmap( base, size, VIRTUAL_GetUnixProt(vprot), MAP_FIXED )) != base)
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (is_beyond_limit( ptr, size, working_set_limit )) working_set_limit = address_space_limit;
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* map_view
|
* map_view
|
||||||
|
@ -790,36 +902,9 @@ static NTSTATUS map_view( struct file_view **view_ret, void *base, size_t size,
|
||||||
{
|
{
|
||||||
if (is_beyond_limit( base, size, address_space_limit ))
|
if (is_beyond_limit( base, size, address_space_limit ))
|
||||||
return STATUS_WORKING_SET_LIMIT_RANGE;
|
return STATUS_WORKING_SET_LIMIT_RANGE;
|
||||||
|
status = map_fixed_area( base, size, vprot );
|
||||||
switch (wine_mmap_is_in_reserved_area( base, size ))
|
if (status != STATUS_SUCCESS) return status;
|
||||||
{
|
ptr = base;
|
||||||
case -1: /* partially in a reserved area */
|
|
||||||
return STATUS_CONFLICTING_ADDRESSES;
|
|
||||||
|
|
||||||
case 0: /* not in a reserved area, do a normal allocation */
|
|
||||||
if ((ptr = wine_anon_mmap( base, size, VIRTUAL_GetUnixProt(vprot), 0 )) == (void *)-1)
|
|
||||||
{
|
|
||||||
if (errno == ENOMEM) return STATUS_NO_MEMORY;
|
|
||||||
return STATUS_INVALID_PARAMETER;
|
|
||||||
}
|
|
||||||
if (ptr != base)
|
|
||||||
{
|
|
||||||
/* We couldn't get the address we wanted */
|
|
||||||
if (is_beyond_limit( ptr, size, user_space_limit )) add_reserved_area( ptr, size );
|
|
||||||
else munmap( ptr, size );
|
|
||||||
return STATUS_CONFLICTING_ADDRESSES;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
case 1: /* in a reserved area, make sure the address is available */
|
|
||||||
if (find_view_range( base, size )) return STATUS_CONFLICTING_ADDRESSES;
|
|
||||||
/* replace the reserved area by our mapping */
|
|
||||||
if ((ptr = wine_anon_mmap( base, size, VIRTUAL_GetUnixProt(vprot), MAP_FIXED )) != base)
|
|
||||||
return STATUS_INVALID_PARAMETER;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (is_beyond_limit( ptr, size, working_set_limit )) working_set_limit = address_space_limit;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue