ntdll: Make the virtual.c critical section uninterruptible by signals.

Based on a patch by Thomas Kho.
This commit is contained in:
Alexandre Julliard 2007-01-12 20:15:52 +01:00
parent 3c55f78f52
commit 146fb0de02
3 changed files with 59 additions and 25 deletions

View File

@ -20,6 +20,7 @@
#define __WINE_NTDLL_MISC_H
#include <stdarg.h>
#include <signal.h>
#include "windef.h"
#include "winnt.h"
@ -61,6 +62,8 @@ extern void DECLSPEC_NORETURN server_protocol_error( const char *err, ... );
extern void DECLSPEC_NORETURN server_protocol_perror( const char *err );
extern void DECLSPEC_NORETURN server_exit_thread( int status );
extern void DECLSPEC_NORETURN server_abort_thread( int status );
void server_enter_uninterrupted_section( RTL_CRITICAL_SECTION *cs, sigset_t *sigset );
void server_leave_uninterrupted_section( RTL_CRITICAL_SECTION *cs, sigset_t *sigset );
extern int server_remove_fd_from_cache( obj_handle_t handle );
extern int server_get_unix_fd( obj_handle_t handle, unsigned int access, int *unix_fd,
int *needs_close, enum server_fd_type *type, int *flags );

View File

@ -326,6 +326,26 @@ unsigned int wine_server_call( void *req_ptr )
}
/***********************************************************************
* server_enter_uninterrupted_section
*/
void server_enter_uninterrupted_section( RTL_CRITICAL_SECTION *cs, sigset_t *sigset )
{
pthread_functions.sigprocmask( SIG_BLOCK, &block_set, sigset );
RtlEnterCriticalSection( cs );
}
/***********************************************************************
* server_leave_uninterrupted_section
*/
void server_leave_uninterrupted_section( RTL_CRITICAL_SECTION *cs, sigset_t *sigset )
{
RtlLeaveCriticalSection( cs );
pthread_functions.sigprocmask( SIG_SETMASK, sigset, NULL );
}
/***********************************************************************
* wine_server_send_fd (NTDLL.@)
*

View File

@ -222,15 +222,16 @@ static void VIRTUAL_DumpView( FILE_VIEW *view )
#if WINE_VM_DEBUG
static void VIRTUAL_Dump(void)
{
sigset_t sigset;
struct file_view *view;
TRACE( "Dump of all virtual memory views:\n" );
RtlEnterCriticalSection(&csVirtual);
server_enter_uninterrupted_section( &csVirtual, &sigset );
LIST_FOR_EACH_ENTRY( view, &views_list, FILE_VIEW, entry )
{
VIRTUAL_DumpView( view );
}
RtlLeaveCriticalSection(&csVirtual);
server_leave_uninterrupted_section( &csVirtual, &sigset );
}
#endif
@ -943,13 +944,14 @@ static NTSTATUS map_image( HANDLE hmapping, int fd, char *base, SIZE_T total_siz
NTSTATUS status = STATUS_CONFLICTING_ADDRESSES;
int i;
off_t pos;
sigset_t sigset;
struct stat st;
struct file_view *view = NULL;
char *ptr, *header_end;
/* zero-map the whole range */
RtlEnterCriticalSection( &csVirtual );
server_enter_uninterrupted_section( &csVirtual, &sigset );
if (base >= (char *)0x110000) /* make sure the DOS area remains free */
status = map_view( &view, base, total_size, mask, FALSE,
@ -1196,14 +1198,14 @@ static NTSTATUS map_image( HANDLE hmapping, int fd, char *base, SIZE_T total_siz
done:
view->mapping = dup_mapping;
RtlLeaveCriticalSection( &csVirtual );
server_leave_uninterrupted_section( &csVirtual, &sigset );
*addr_ptr = ptr;
return STATUS_SUCCESS;
error:
if (view) delete_view( view );
RtlLeaveCriticalSection( &csVirtual );
server_leave_uninterrupted_section( &csVirtual, &sigset );
if (dup_mapping) NtClose( dup_mapping );
return status;
}
@ -1272,8 +1274,9 @@ NTSTATUS VIRTUAL_HandleFault( LPCVOID addr )
{
FILE_VIEW *view;
NTSTATUS ret = STATUS_ACCESS_VIOLATION;
sigset_t sigset;
RtlEnterCriticalSection( &csVirtual );
server_enter_uninterrupted_section( &csVirtual, &sigset );
if ((view = VIRTUAL_FindView( addr )))
{
void *page = ROUND_ADDR( addr, page_mask );
@ -1284,7 +1287,7 @@ NTSTATUS VIRTUAL_HandleFault( LPCVOID addr )
ret = STATUS_GUARD_PAGE_VIOLATION;
}
}
RtlLeaveCriticalSection( &csVirtual );
server_leave_uninterrupted_section( &csVirtual, &sigset );
return ret;
}
@ -1297,8 +1300,9 @@ NTSTATUS VIRTUAL_HandleFault( LPCVOID addr )
void VIRTUAL_SetForceExec( BOOL enable )
{
struct file_view *view;
sigset_t sigset;
RtlEnterCriticalSection( &csVirtual );
server_enter_uninterrupted_section( &csVirtual, &sigset );
if (!force_exec_prot != !enable) /* change all existing views */
{
force_exec_prot = enable;
@ -1340,7 +1344,7 @@ void VIRTUAL_SetForceExec( BOOL enable )
}
}
}
RtlLeaveCriticalSection( &csVirtual );
server_leave_uninterrupted_section( &csVirtual, &sigset );
}
@ -1370,6 +1374,7 @@ NTSTATUS WINAPI NtAllocateVirtualMemory( HANDLE process, PVOID *ret, ULONG zero_
SIZE_T mask = get_mask( zero_bits );
NTSTATUS status = STATUS_SUCCESS;
struct file_view *view;
sigset_t sigset;
TRACE("%p %p %08lx %x %08x\n", process, *ret, size, type, protect );
@ -1426,7 +1431,7 @@ NTSTATUS WINAPI NtAllocateVirtualMemory( HANDLE process, PVOID *ret, ULONG zero_
/* Reserve the memory */
if (use_locks) RtlEnterCriticalSection( &csVirtual );
if (use_locks) server_enter_uninterrupted_section( &csVirtual, &sigset );
if (type & MEM_SYSTEM)
{
@ -1454,7 +1459,7 @@ NTSTATUS WINAPI NtAllocateVirtualMemory( HANDLE process, PVOID *ret, ULONG zero_
else if (!VIRTUAL_SetProt( view, base, size, vprot )) status = STATUS_ACCESS_DENIED;
}
if (use_locks) RtlLeaveCriticalSection( &csVirtual );
if (use_locks) server_leave_uninterrupted_section( &csVirtual, &sigset );
if (status == STATUS_SUCCESS)
{
@ -1473,6 +1478,7 @@ NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *si
{
FILE_VIEW *view;
char *base;
sigset_t sigset;
NTSTATUS status = STATUS_SUCCESS;
LPVOID addr = *addr_ptr;
SIZE_T size = *size_ptr;
@ -1493,7 +1499,7 @@ NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *si
/* avoid freeing the DOS area when a broken app passes a NULL pointer */
if (!base && !(type & MEM_SYSTEM)) return STATUS_INVALID_PARAMETER;
RtlEnterCriticalSection(&csVirtual);
server_enter_uninterrupted_section( &csVirtual, &sigset );
if (!(view = VIRTUAL_FindView( base )) ||
(base + size > (char *)view->base + view->size) ||
@ -1537,7 +1543,7 @@ NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *si
status = STATUS_INVALID_PARAMETER;
}
RtlLeaveCriticalSection(&csVirtual);
server_leave_uninterrupted_section( &csVirtual, &sigset );
return status;
}
@ -1550,6 +1556,7 @@ NTSTATUS WINAPI NtProtectVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T
ULONG new_prot, ULONG *old_prot )
{
FILE_VIEW *view;
sigset_t sigset;
NTSTATUS status = STATUS_SUCCESS;
char *base;
UINT i;
@ -1571,7 +1578,7 @@ NTSTATUS WINAPI NtProtectVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T
size = ROUND_SIZE( addr, size );
base = ROUND_ADDR( addr, page_mask );
RtlEnterCriticalSection( &csVirtual );
server_enter_uninterrupted_section( &csVirtual, &sigset );
if (!(view = VIRTUAL_FindView( base )) || (base + size > (char *)view->base + view->size))
{
@ -1598,7 +1605,7 @@ NTSTATUS WINAPI NtProtectVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T
if (!VIRTUAL_SetProt( view, base, size, vprot )) status = STATUS_ACCESS_DENIED;
}
}
RtlLeaveCriticalSection( &csVirtual );
server_leave_uninterrupted_section( &csVirtual, &sigset );
if (status == STATUS_SUCCESS)
{
@ -1626,6 +1633,7 @@ NTSTATUS WINAPI NtQueryVirtualMemory( HANDLE process, LPCVOID addr,
struct list *ptr;
SIZE_T size = 0;
MEMORY_BASIC_INFORMATION *info = buffer;
sigset_t sigset;
if (info_class != MemoryBasicInformation)
{
@ -1654,7 +1662,7 @@ NTSTATUS WINAPI NtQueryVirtualMemory( HANDLE process, LPCVOID addr,
/* Find the view containing the address */
RtlEnterCriticalSection(&csVirtual);
server_enter_uninterrupted_section( &csVirtual, &sigset );
ptr = list_head( &views_list );
for (;;)
{
@ -1666,7 +1674,7 @@ NTSTATUS WINAPI NtQueryVirtualMemory( HANDLE process, LPCVOID addr,
{
if (user_space_limit && base >= (char *)user_space_limit)
{
RtlLeaveCriticalSection( &csVirtual );
server_leave_uninterrupted_section( &csVirtual, &sigset );
return STATUS_WORKING_SET_LIMIT_RANGE;
}
size = (char *)user_space_limit - alloc_base;
@ -1715,7 +1723,7 @@ NTSTATUS WINAPI NtQueryVirtualMemory( HANDLE process, LPCVOID addr,
for (size = base - alloc_base; size < view->size; size += page_size)
if (view->prot[size >> page_shift] != vprot) break;
}
RtlLeaveCriticalSection(&csVirtual);
server_leave_uninterrupted_section( &csVirtual, &sigset );
info->BaseAddress = base;
info->RegionSize = size - (base - alloc_base);
@ -1841,6 +1849,7 @@ NTSTATUS WINAPI NtMapViewOfSection( HANDLE handle, HANDLE process, PVOID *addr_p
DWORD size_low, size_high, header_size, shared_size;
HANDLE dup_mapping, shared_file;
LARGE_INTEGER offset;
sigset_t sigset;
offset.QuadPart = offset_ptr ? offset_ptr->QuadPart : 0;
@ -1945,12 +1954,12 @@ NTSTATUS WINAPI NtMapViewOfSection( HANDLE handle, HANDLE process, PVOID *addr_p
/* Reserve a properly aligned area */
RtlEnterCriticalSection( &csVirtual );
server_enter_uninterrupted_section( &csVirtual, &sigset );
res = map_view( &view, *addr_ptr, size, mask, FALSE, prot );
if (res)
{
RtlLeaveCriticalSection( &csVirtual );
server_leave_uninterrupted_section( &csVirtual, &sigset );
goto done;
}
@ -1974,7 +1983,7 @@ NTSTATUS WINAPI NtMapViewOfSection( HANDLE handle, HANDLE process, PVOID *addr_p
delete_view( view );
}
RtlLeaveCriticalSection( &csVirtual );
server_leave_uninterrupted_section( &csVirtual, &sigset );
done:
if (dup_mapping) NtClose( dup_mapping );
@ -1991,6 +2000,7 @@ NTSTATUS WINAPI NtUnmapViewOfSection( HANDLE process, PVOID addr )
{
FILE_VIEW *view;
NTSTATUS status = STATUS_INVALID_PARAMETER;
sigset_t sigset;
void *base = ROUND_ADDR( addr, page_mask );
if (!is_current_process( process ))
@ -1998,13 +2008,13 @@ NTSTATUS WINAPI NtUnmapViewOfSection( HANDLE process, PVOID addr )
ERR("Unsupported on other process\n");
return STATUS_ACCESS_DENIED;
}
RtlEnterCriticalSection( &csVirtual );
server_enter_uninterrupted_section( &csVirtual, &sigset );
if ((view = VIRTUAL_FindView( base )) && (base == view->base))
{
delete_view( view );
status = STATUS_SUCCESS;
}
RtlLeaveCriticalSection( &csVirtual );
server_leave_uninterrupted_section( &csVirtual, &sigset );
return status;
}
@ -2018,6 +2028,7 @@ NTSTATUS WINAPI NtFlushVirtualMemory( HANDLE process, LPCVOID *addr_ptr,
{
FILE_VIEW *view;
NTSTATUS status = STATUS_SUCCESS;
sigset_t sigset;
void *addr = ROUND_ADDR( *addr_ptr, page_mask );
if (!is_current_process( process ))
@ -2025,7 +2036,7 @@ NTSTATUS WINAPI NtFlushVirtualMemory( HANDLE process, LPCVOID *addr_ptr,
ERR("Unsupported on other process\n");
return STATUS_ACCESS_DENIED;
}
RtlEnterCriticalSection( &csVirtual );
server_enter_uninterrupted_section( &csVirtual, &sigset );
if (!(view = VIRTUAL_FindView( addr ))) status = STATUS_INVALID_PARAMETER;
else
{
@ -2033,7 +2044,7 @@ NTSTATUS WINAPI NtFlushVirtualMemory( HANDLE process, LPCVOID *addr_ptr,
*addr_ptr = addr;
if (msync( addr, *size_ptr, MS_SYNC )) status = STATUS_NOT_MAPPED_DATA;
}
RtlLeaveCriticalSection( &csVirtual );
server_leave_uninterrupted_section( &csVirtual, &sigset );
return status;
}