ntdll: Reduce stack usage of virtual memory functions by storing sigset in static memory.

Sebastian Lackner sebastian at fds-team.de
Sat Sep 26 17:07:48 CDT 2015


From: Michael Müller <michael at fds-team.de>

For https://bugs.winehq.org/show_bug.cgi?id=34558

Depending on the compiler optimization flags there is still no guarantee that
everything will fit into the available stack space, no matter if its declared
as static or not.

Signed-off-by: Michael Müller <michael at fds-team.de>
Signed-off-by: Sebastian Lackner <sebastian at fds-team.de>
---
 dlls/ntdll/virtual.c |  129 +++++++++++++++++++++++++--------------------------
 1 file changed, 65 insertions(+), 64 deletions(-)

diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c
index 4d4bc3b..cf789e8 100644
--- a/dlls/ntdll/virtual.c
+++ b/dlls/ntdll/virtual.c
@@ -148,6 +148,27 @@ static void *preload_reserve_start;
 static void *preload_reserve_end;
 static BOOL use_locks;
 static BOOL force_exec_prot;  /* whether to force PROT_EXEC on all PROT_READ mmaps */
+static sigset_t virtual_sigset;
+
+static void virtual_lock(void)
+{
+    sigset_t sigset;
+
+    pthread_sigmask( SIG_BLOCK, &server_block_set, &sigset );
+    RtlEnterCriticalSection( &csVirtual );
+    if (csVirtual.RecursionCount == 1) virtual_sigset = sigset;
+}
+
+static void virtual_unlock(void)
+{
+    if (csVirtual.RecursionCount == 1)
+    {
+        sigset_t sigset = virtual_sigset;
+        RtlLeaveCriticalSection( &csVirtual );
+        pthread_sigmask( SIG_SETMASK, &sigset, NULL );
+    }
+    else RtlLeaveCriticalSection( &csVirtual );
+}
 
 
 /***********************************************************************
@@ -227,16 +248,15 @@ static void VIRTUAL_DumpView( struct file_view *view )
 #ifdef WINE_VM_DEBUG
 static void VIRTUAL_Dump(void)
 {
-    sigset_t sigset;
     struct file_view *view;
 
     TRACE( "Dump of all virtual memory views:\n" );
-    server_enter_uninterrupted_section( &csVirtual, &sigset );
+    virtual_lock();
     LIST_FOR_EACH_ENTRY( view, &views_list, struct file_view, entry )
     {
         VIRTUAL_DumpView( view );
     }
-    server_leave_uninterrupted_section( &csVirtual, &sigset );
+    virtual_unlock();
 }
 #endif
 
@@ -1069,14 +1089,13 @@ 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, *header_start;
 
     /* zero-map the whole range */
 
-    server_enter_uninterrupted_section( &csVirtual, &sigset );
+    virtual_lock();
 
     if (base >= (char *)address_space_start)  /* make sure the DOS area remains free */
         status = map_view( &view, base, total_size, mask, FALSE,
@@ -1267,7 +1286,7 @@ static NTSTATUS map_image( HANDLE hmapping, int fd, char *base, SIZE_T total_siz
  done:
     view->mapping = dup_mapping;
     view->map_protect = map_vprot;
-    server_leave_uninterrupted_section( &csVirtual, &sigset );
+    virtual_unlock();
 
     *addr_ptr = ptr;
 #ifdef VALGRIND_LOAD_PDB_DEBUGINFO
@@ -1278,7 +1297,7 @@ static NTSTATUS map_image( HANDLE hmapping, int fd, char *base, SIZE_T total_siz
 
  error:
     if (view) delete_view( view );
-    server_leave_uninterrupted_section( &csVirtual, &sigset );
+    virtual_unlock();
     if (dup_mapping) NtClose( dup_mapping );
     return status;
 }
@@ -1376,7 +1395,6 @@ void virtual_get_system_info( SYSTEM_BASIC_INFORMATION *info )
 NTSTATUS virtual_create_builtin_view( void *module )
 {
     NTSTATUS status;
-    sigset_t sigset;
     IMAGE_NT_HEADERS *nt = RtlImageNtHeader( module );
     SIZE_T size = nt->OptionalHeader.SizeOfImage;
     IMAGE_SECTION_HEADER *sec;
@@ -1386,11 +1404,11 @@ NTSTATUS virtual_create_builtin_view( void *module )
 
     size = ROUND_SIZE( module, size );
     base = ROUND_ADDR( module, page_mask );
-    server_enter_uninterrupted_section( &csVirtual, &sigset );
+    virtual_lock();
     status = create_view( &view, base, size, VPROT_SYSTEM | VPROT_IMAGE |
                           VPROT_COMMITTED | VPROT_READ | VPROT_WRITECOPY | VPROT_EXEC );
     if (!status) TRACE( "created %p-%p\n", base, (char *)base + size );
-    server_leave_uninterrupted_section( &csVirtual, &sigset );
+    virtual_unlock();
 
     if (status) return status;
 
@@ -1420,7 +1438,6 @@ NTSTATUS virtual_alloc_thread_stack( TEB *teb, SIZE_T reserve_size, SIZE_T commi
 {
     struct file_view *view;
     NTSTATUS status;
-    sigset_t sigset;
     SIZE_T size;
 
     if (!reserve_size || !commit_size)
@@ -1434,7 +1451,7 @@ NTSTATUS virtual_alloc_thread_stack( TEB *teb, SIZE_T reserve_size, SIZE_T commi
     if (size < 1024 * 1024) size = 1024 * 1024;  /* Xlib needs a large stack */
     size = (size + 0xffff) & ~0xffff;  /* round to 64K boundary */
 
-    server_enter_uninterrupted_section( &csVirtual, &sigset );
+    virtual_lock();
 
     if ((status = map_view( &view, NULL, size, 0xffff, 0,
                             VPROT_READ | VPROT_WRITE | VPROT_COMMITTED | VPROT_VALLOC )) != STATUS_SUCCESS)
@@ -1454,7 +1471,7 @@ NTSTATUS virtual_alloc_thread_stack( TEB *teb, SIZE_T reserve_size, SIZE_T commi
     teb->Tib.StackBase     = (char *)view->base + view->size;
     teb->Tib.StackLimit    = (char *)view->base + 2 * page_size;
 done:
-    server_leave_uninterrupted_section( &csVirtual, &sigset );
+    virtual_unlock();
     return status;
 }
 
@@ -1481,9 +1498,8 @@ NTSTATUS virtual_handle_fault( LPCVOID addr, DWORD err, BOOL on_signal_stack )
 {
     struct file_view *view;
     NTSTATUS ret = STATUS_ACCESS_VIOLATION;
-    sigset_t sigset;
 
-    server_enter_uninterrupted_section( &csVirtual, &sigset );
+    virtual_lock();
     if ((view = VIRTUAL_FindView( addr, 0 )))
     {
         void *page = ROUND_ADDR( addr, page_mask );
@@ -1504,7 +1520,7 @@ NTSTATUS virtual_handle_fault( LPCVOID addr, DWORD err, BOOL on_signal_stack )
             ret = STATUS_GUARD_PAGE_VIOLATION;
         }
     }
-    server_leave_uninterrupted_section( &csVirtual, &sigset );
+    virtual_unlock();
     return ret;
 }
 
@@ -1517,12 +1533,11 @@ BOOL virtual_is_valid_code_address( const void *addr, SIZE_T size )
 {
     struct file_view *view;
     BOOL ret = FALSE;
-    sigset_t sigset;
 
-    server_enter_uninterrupted_section( &csVirtual, &sigset );
+    virtual_lock();
     if ((view = VIRTUAL_FindView( addr, size )))
         ret = !(view->protect & VPROT_SYSTEM);  /* system views are not visible to the app */
-    server_leave_uninterrupted_section( &csVirtual, &sigset );
+    virtual_unlock();
     return ret;
 }
 
@@ -1637,12 +1652,11 @@ BOOL virtual_check_buffer_for_write( void *ptr, SIZE_T size )
 SIZE_T virtual_uninterrupted_read_memory( const void *addr, void *buffer, SIZE_T size )
 {
     struct file_view *view;
-    sigset_t sigset;
     SIZE_T bytes_read = 0;
 
     if (!size) return 0;
 
-    server_enter_uninterrupted_section( &csVirtual, &sigset );
+    virtual_lock();
     if ((view = VIRTUAL_FindView( addr, size )))
     {
         if (!(view->protect & VPROT_SYSTEM))
@@ -1661,7 +1675,7 @@ SIZE_T virtual_uninterrupted_read_memory( const void *addr, void *buffer, SIZE_T
             }
         }
     }
-    server_leave_uninterrupted_section( &csVirtual, &sigset );
+    virtual_unlock();
     return bytes_read;
 }
 
@@ -1676,12 +1690,11 @@ SIZE_T virtual_uninterrupted_read_memory( const void *addr, void *buffer, SIZE_T
 SIZE_T virtual_uninterrupted_write_memory( void *addr, const void *buffer, SIZE_T size )
 {
     struct file_view *view;
-    sigset_t sigset;
     SIZE_T bytes_written = 0;
 
     if (!size) return 0;
 
-    server_enter_uninterrupted_section( &csVirtual, &sigset );
+    virtual_lock();
     if ((view = VIRTUAL_FindView( addr, size )))
     {
         if (!(view->protect & VPROT_SYSTEM))
@@ -1719,7 +1732,7 @@ SIZE_T virtual_uninterrupted_write_memory( void *addr, const void *buffer, SIZE_
             }
         }
     }
-    server_leave_uninterrupted_section( &csVirtual, &sigset );
+    virtual_unlock();
     return bytes_written;
 }
 
@@ -1732,9 +1745,8 @@ SIZE_T virtual_uninterrupted_write_memory( void *addr, const void *buffer, SIZE_
 void VIRTUAL_SetForceExec( BOOL enable )
 {
     struct file_view *view;
-    sigset_t sigset;
 
-    server_enter_uninterrupted_section( &csVirtual, &sigset );
+    virtual_lock();
     if (!force_exec_prot != !enable)  /* change all existing views */
     {
         force_exec_prot = enable;
@@ -1776,7 +1788,7 @@ void VIRTUAL_SetForceExec( BOOL enable )
             }
         }
     }
-    server_leave_uninterrupted_section( &csVirtual, &sigset );
+    virtual_unlock();
 }
 
 struct free_range
@@ -1810,11 +1822,10 @@ static int free_reserved_memory( void *base, size_t size, void *arg )
 void virtual_release_address_space(void)
 {
     struct free_range range;
-    sigset_t sigset;
 
     if (is_win64) return;
 
-    server_enter_uninterrupted_section( &csVirtual, &sigset );
+    virtual_lock();
 
     range.base  = (char *)0x82000000;
     range.limit = user_space_limit;
@@ -1832,7 +1843,7 @@ void virtual_release_address_space(void)
 #endif
     }
 
-    server_leave_uninterrupted_section( &csVirtual, &sigset );
+    virtual_unlock();
 }
 
 
@@ -1866,7 +1877,6 @@ 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 );
 
@@ -1916,14 +1926,14 @@ NTSTATUS WINAPI NtAllocateVirtualMemory( HANDLE process, PVOID *ret, ULONG zero_
         /* address 1 is magic to mean DOS area */
         if (!base && *ret == (void *)1 && size == 0x110000)
         {
-            server_enter_uninterrupted_section( &csVirtual, &sigset );
+            virtual_lock();
             status = allocate_dos_memory( &view, vprot );
             if (status == STATUS_SUCCESS)
             {
                 *ret = view->base;
                 *size_ptr = view->size;
             }
-            server_leave_uninterrupted_section( &csVirtual, &sigset );
+            virtual_unlock();
             return status;
         }
 
@@ -1950,7 +1960,7 @@ NTSTATUS WINAPI NtAllocateVirtualMemory( HANDLE process, PVOID *ret, ULONG zero_
 
     /* Reserve the memory */
 
-    if (use_locks) server_enter_uninterrupted_section( &csVirtual, &sigset );
+    if (use_locks) virtual_lock();
 
     if ((type & MEM_RESERVE) || !base)
     {
@@ -1981,7 +1991,7 @@ NTSTATUS WINAPI NtAllocateVirtualMemory( HANDLE process, PVOID *ret, ULONG zero_
         }
     }
 
-    if (use_locks) server_leave_uninterrupted_section( &csVirtual, &sigset );
+    if (use_locks) virtual_unlock();
 
     if (status == STATUS_SUCCESS)
     {
@@ -2000,7 +2010,6 @@ NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *si
 {
     struct file_view *view;
     char *base;
-    sigset_t sigset;
     NTSTATUS status = STATUS_SUCCESS;
     LPVOID addr = *addr_ptr;
     SIZE_T size = *size_ptr;
@@ -2037,7 +2046,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) return STATUS_INVALID_PARAMETER;
 
-    server_enter_uninterrupted_section( &csVirtual, &sigset );
+    virtual_lock();
 
     if (!(view = VIRTUAL_FindView( base, size )) || !(view->protect & VPROT_VALLOC))
     {
@@ -2070,7 +2079,7 @@ NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *si
         status = STATUS_INVALID_PARAMETER;
     }
 
-    server_leave_uninterrupted_section( &csVirtual, &sigset );
+    virtual_unlock();
     return status;
 }
 
@@ -2111,7 +2120,6 @@ NTSTATUS WINAPI NtProtectVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T
                                         ULONG new_prot, ULONG *old_prot )
 {
     struct file_view *view;
-    sigset_t sigset;
     NTSTATUS status = STATUS_SUCCESS;
     char *base;
     BYTE vprot;
@@ -2152,7 +2160,7 @@ NTSTATUS WINAPI NtProtectVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T
     size = ROUND_SIZE( addr, size );
     base = ROUND_ADDR( addr, page_mask );
 
-    server_enter_uninterrupted_section( &csVirtual, &sigset );
+    virtual_lock();
 
     if ((view = VIRTUAL_FindView( base, size )))
     {
@@ -2179,7 +2187,7 @@ NTSTATUS WINAPI NtProtectVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T
     }
     else status = STATUS_INVALID_PARAMETER;
 
-    server_leave_uninterrupted_section( &csVirtual, &sigset );
+    virtual_unlock();
 
     if (status == STATUS_SUCCESS)
     {
@@ -2244,7 +2252,6 @@ 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)
     {
@@ -2296,7 +2303,7 @@ NTSTATUS WINAPI NtQueryVirtualMemory( HANDLE process, LPCVOID addr,
 
     /* Find the view containing the address */
 
-    server_enter_uninterrupted_section( &csVirtual, &sigset );
+    virtual_lock();
     ptr = list_head( &views_list );
     for (;;)
     {
@@ -2369,7 +2376,7 @@ NTSTATUS WINAPI NtQueryVirtualMemory( HANDLE process, LPCVOID addr,
             if ((view->prot[size >> page_shift] ^ vprot) & ~VPROT_WRITEWATCH) break;
         info->RegionSize = size - (base - alloc_base);
     }
-    server_leave_uninterrupted_section( &csVirtual, &sigset );
+    virtual_unlock();
 
     if (res_len) *res_len = sizeof(*info);
     return STATUS_SUCCESS;
@@ -2549,7 +2556,6 @@ NTSTATUS WINAPI NtMapViewOfSection( HANDLE handle, HANDLE process, PVOID *addr_p
     DWORD header_size;
     HANDLE dup_mapping, shared_file;
     LARGE_INTEGER offset;
-    sigset_t sigset;
 
     offset.QuadPart = offset_ptr ? offset_ptr->QuadPart : 0;
 
@@ -2687,14 +2693,14 @@ NTSTATUS WINAPI NtMapViewOfSection( HANDLE handle, HANDLE process, PVOID *addr_p
 
     /* Reserve a properly aligned area */
 
-    server_enter_uninterrupted_section( &csVirtual, &sigset );
+    virtual_lock();
 
     get_vprot_flags( protect, &vprot, map_vprot & VPROT_IMAGE );
     vprot |= (map_vprot & VPROT_COMMITTED);
     res = map_view( &view, *addr_ptr, size, mask, FALSE, vprot );
     if (res)
     {
-        server_leave_uninterrupted_section( &csVirtual, &sigset );
+        virtual_unlock();
         goto done;
     }
 
@@ -2719,7 +2725,7 @@ NTSTATUS WINAPI NtMapViewOfSection( HANDLE handle, HANDLE process, PVOID *addr_p
         delete_view( view );
     }
 
-    server_leave_uninterrupted_section( &csVirtual, &sigset );
+    virtual_unlock();
 
 done:
     if (dup_mapping) NtClose( dup_mapping );
@@ -2736,7 +2742,6 @@ NTSTATUS WINAPI NtUnmapViewOfSection( HANDLE process, PVOID addr )
 {
     struct file_view *view;
     NTSTATUS status = STATUS_NOT_MAPPED_VIEW;
-    sigset_t sigset;
     void *base = ROUND_ADDR( addr, page_mask );
 
     if (process != NtCurrentProcess())
@@ -2753,13 +2758,13 @@ NTSTATUS WINAPI NtUnmapViewOfSection( HANDLE process, PVOID addr )
         return status;
     }
 
-    server_enter_uninterrupted_section( &csVirtual, &sigset );
+    virtual_lock();
     if ((view = VIRTUAL_FindView( base, 0 )) && (base == view->base) && !(view->protect & VPROT_VALLOC))
     {
         delete_view( view );
         status = STATUS_SUCCESS;
     }
-    server_leave_uninterrupted_section( &csVirtual, &sigset );
+    virtual_unlock();
     return status;
 }
 
@@ -2773,7 +2778,6 @@ NTSTATUS WINAPI NtFlushVirtualMemory( HANDLE process, LPCVOID *addr_ptr,
 {
     struct file_view *view;
     NTSTATUS status = STATUS_SUCCESS;
-    sigset_t sigset;
     void *addr = ROUND_ADDR( *addr_ptr, page_mask );
 
     if (process != NtCurrentProcess())
@@ -2797,7 +2801,7 @@ NTSTATUS WINAPI NtFlushVirtualMemory( HANDLE process, LPCVOID *addr_ptr,
         return result.virtual_flush.status;
     }
 
-    server_enter_uninterrupted_section( &csVirtual, &sigset );
+    virtual_lock();
     if (!(view = VIRTUAL_FindView( addr, *size_ptr ))) status = STATUS_INVALID_PARAMETER;
     else
     {
@@ -2807,7 +2811,7 @@ NTSTATUS WINAPI NtFlushVirtualMemory( HANDLE process, LPCVOID *addr_ptr,
         if (msync( addr, *size_ptr, MS_ASYNC )) status = STATUS_NOT_MAPPED_DATA;
 #endif
     }
-    server_leave_uninterrupted_section( &csVirtual, &sigset );
+    virtual_unlock();
     return status;
 }
 
@@ -2821,7 +2825,6 @@ NTSTATUS WINAPI NtGetWriteWatch( HANDLE process, ULONG flags, PVOID base, SIZE_T
 {
     struct file_view *view;
     NTSTATUS status = STATUS_SUCCESS;
-    sigset_t sigset;
 
     size = ROUND_SIZE( base, size );
     base = ROUND_ADDR( base, page_mask );
@@ -2835,7 +2838,7 @@ NTSTATUS WINAPI NtGetWriteWatch( HANDLE process, ULONG flags, PVOID base, SIZE_T
     TRACE( "%p %x %p-%p %p %lu\n", process, flags, base, (char *)base + size,
            addresses, *count );
 
-    server_enter_uninterrupted_section( &csVirtual, &sigset );
+    virtual_lock();
 
     if ((view = VIRTUAL_FindView( base, size )) && (view->protect & VPROT_WRITEWATCH))
     {
@@ -2855,7 +2858,7 @@ NTSTATUS WINAPI NtGetWriteWatch( HANDLE process, ULONG flags, PVOID base, SIZE_T
     }
     else status = STATUS_INVALID_PARAMETER;
 
-    server_leave_uninterrupted_section( &csVirtual, &sigset );
+    virtual_unlock();
     return status;
 }
 
@@ -2868,7 +2871,6 @@ NTSTATUS WINAPI NtResetWriteWatch( HANDLE process, PVOID base, SIZE_T size )
 {
     struct file_view *view;
     NTSTATUS status = STATUS_SUCCESS;
-    sigset_t sigset;
 
     size = ROUND_SIZE( base, size );
     base = ROUND_ADDR( base, page_mask );
@@ -2877,14 +2879,14 @@ NTSTATUS WINAPI NtResetWriteWatch( HANDLE process, PVOID base, SIZE_T size )
 
     if (!size) return STATUS_INVALID_PARAMETER;
 
-    server_enter_uninterrupted_section( &csVirtual, &sigset );
+    virtual_lock();
 
     if ((view = VIRTUAL_FindView( base, size )) && (view->protect & VPROT_WRITEWATCH))
         reset_write_watches( view, base, size );
     else
         status = STATUS_INVALID_PARAMETER;
 
-    server_leave_uninterrupted_section( &csVirtual, &sigset );
+    virtual_unlock();
     return status;
 }
 
@@ -2958,11 +2960,10 @@ NTSTATUS WINAPI NtAreMappedFilesTheSame(PVOID addr1, PVOID addr2)
     struct file_view *view1, *view2;
     struct stat st1, st2;
     NTSTATUS status;
-    sigset_t sigset;
 
     TRACE("%p %p\n", addr1, addr2);
 
-    server_enter_uninterrupted_section( &csVirtual, &sigset );
+    virtual_lock();
 
     view1 = VIRTUAL_FindView( addr1, 0 );
     view2 = VIRTUAL_FindView( addr2, 0 );
@@ -2981,6 +2982,6 @@ NTSTATUS WINAPI NtAreMappedFilesTheSame(PVOID addr1, PVOID addr2)
     else
         status = STATUS_NOT_SAME_DEVICE;
 
-    server_leave_uninterrupted_section( &csVirtual, &sigset );
+    virtual_unlock();
     return status;
 }
-- 
2.5.1



More information about the wine-patches mailing list