diff --git a/dlls/ntdll/critsection.c b/dlls/ntdll/critsection.c index bfb7761d286..e4c7b2324a0 100644 --- a/dlls/ntdll/critsection.c +++ b/dlls/ntdll/critsection.c @@ -26,9 +26,6 @@ #include #include #include -#ifdef HAVE_SYS_SYSCALL_H -#include -#endif #include #include "ntstatus.h" #define WIN32_NO_STATUS @@ -56,187 +53,6 @@ static BOOL crit_section_has_debuginfo(const RTL_CRITICAL_SECTION *crit) return crit->DebugInfo != NULL && crit->DebugInfo != no_debug_info_marker; } -#ifdef __linux__ - -static int wait_op = 128; /*FUTEX_WAIT|FUTEX_PRIVATE_FLAG*/ -static int wake_op = 129; /*FUTEX_WAKE|FUTEX_PRIVATE_FLAG*/ - -static inline int futex_wait( int *addr, int val, struct timespec *timeout ) -{ - return syscall( __NR_futex, addr, wait_op, val, timeout, 0, 0 ); -} - -static inline int futex_wake( int *addr, int val ) -{ - return syscall( __NR_futex, addr, wake_op, val, NULL, 0, 0 ); -} - -static inline int use_futexes(void) -{ - static int supported = -1; - - if (supported == -1) - { - futex_wait( &supported, 10, NULL ); - if (errno == ENOSYS) - { - wait_op = 0; /*FUTEX_WAIT*/ - wake_op = 1; /*FUTEX_WAKE*/ - futex_wait( &supported, 10, NULL ); - } - supported = (errno != ENOSYS); - } - return supported; -} - -static inline NTSTATUS fast_wait( RTL_CRITICAL_SECTION *crit, int timeout ) -{ - int val; - struct timespec timespec; - - if (!use_futexes()) return STATUS_NOT_IMPLEMENTED; - - timespec.tv_sec = timeout; - timespec.tv_nsec = 0; - while ((val = InterlockedCompareExchange( (int *)&crit->LockSemaphore, 0, 1 )) != 1) - { - /* note: this may wait longer than specified in case of signals or */ - /* multiple wake-ups, but that shouldn't be a problem */ - if (futex_wait( (int *)&crit->LockSemaphore, val, ×pec ) == -1 && errno == ETIMEDOUT) - return STATUS_TIMEOUT; - } - return STATUS_WAIT_0; -} - -static inline NTSTATUS fast_wake( RTL_CRITICAL_SECTION *crit ) -{ - if (!use_futexes()) return STATUS_NOT_IMPLEMENTED; - - *(int *)&crit->LockSemaphore = 1; - futex_wake( (int *)&crit->LockSemaphore, 1 ); - return STATUS_SUCCESS; -} - -static inline void close_semaphore( RTL_CRITICAL_SECTION *crit ) -{ - if (!use_futexes()) NtClose( crit->LockSemaphore ); -} - -#elif defined(__APPLE__) - -#include -#include -#include - -static inline semaphore_t get_mach_semaphore( RTL_CRITICAL_SECTION *crit ) -{ - semaphore_t ret = *(int *)&crit->LockSemaphore; - if (!ret) - { - semaphore_t sem; - if (semaphore_create( mach_task_self(), &sem, SYNC_POLICY_FIFO, 0 )) return 0; - if (!(ret = InterlockedCompareExchange( (int *)&crit->LockSemaphore, sem, 0 ))) - ret = sem; - else - semaphore_destroy( mach_task_self(), sem ); /* somebody beat us to it */ - } - return ret; -} - -static inline NTSTATUS fast_wait( RTL_CRITICAL_SECTION *crit, int timeout ) -{ - mach_timespec_t timespec; - semaphore_t sem = get_mach_semaphore( crit ); - - timespec.tv_sec = timeout; - timespec.tv_nsec = 0; - for (;;) - { - switch( semaphore_timedwait( sem, timespec )) - { - case KERN_SUCCESS: - return STATUS_WAIT_0; - case KERN_ABORTED: - continue; /* got a signal, restart */ - case KERN_OPERATION_TIMED_OUT: - return STATUS_TIMEOUT; - default: - return STATUS_INVALID_HANDLE; - } - } -} - -static inline NTSTATUS fast_wake( RTL_CRITICAL_SECTION *crit ) -{ - semaphore_t sem = get_mach_semaphore( crit ); - semaphore_signal( sem ); - return STATUS_SUCCESS; -} - -static inline void close_semaphore( RTL_CRITICAL_SECTION *crit ) -{ - semaphore_destroy( mach_task_self(), *(int *)&crit->LockSemaphore ); -} - -#else /* __APPLE__ */ - -static inline NTSTATUS fast_wait( RTL_CRITICAL_SECTION *crit, int timeout ) -{ - return STATUS_NOT_IMPLEMENTED; -} - -static inline NTSTATUS fast_wake( RTL_CRITICAL_SECTION *crit ) -{ - return STATUS_NOT_IMPLEMENTED; -} - -static inline void close_semaphore( RTL_CRITICAL_SECTION *crit ) -{ - NtClose( crit->LockSemaphore ); -} - -#endif - -/*********************************************************************** - * get_semaphore - */ -static inline HANDLE get_semaphore( RTL_CRITICAL_SECTION *crit ) -{ - HANDLE ret = crit->LockSemaphore; - if (!ret) - { - HANDLE sem; - if (NtCreateSemaphore( &sem, SEMAPHORE_ALL_ACCESS, NULL, 0, 1 )) return 0; - if (!(ret = InterlockedCompareExchangePointer( &crit->LockSemaphore, sem, 0 ))) - ret = sem; - else - NtClose(sem); /* somebody beat us to it */ - } - return ret; -} - -/*********************************************************************** - * wait_semaphore - */ -static inline NTSTATUS wait_semaphore( RTL_CRITICAL_SECTION *crit, int timeout ) -{ - NTSTATUS ret; - - /* debug info is cleared by MakeCriticalSectionGlobal */ - if (!crit_section_has_debuginfo( crit ) || ((ret = fast_wait( crit, timeout )) == STATUS_NOT_IMPLEMENTED)) - { - HANDLE sem = get_semaphore( crit ); - LARGE_INTEGER time; - select_op_t select_op; - - time.QuadPart = timeout * (LONGLONG)-10000000; - select_op.wait.op = SELECT_WAIT; - select_op.wait.handles[0] = wine_server_obj_handle( sem ); - ret = unix_funcs->server_wait( &select_op, offsetof( select_op_t, wait.handles[1] ), 0, &time ); - } - return ret; -} - /*********************************************************************** * RtlInitializeCriticalSection (NTDLL.@) * @@ -402,7 +218,8 @@ NTSTATUS WINAPI RtlDeleteCriticalSection( RTL_CRITICAL_SECTION *crit ) RtlFreeHeap( GetProcessHeap(), 0, crit->DebugInfo ); crit->DebugInfo = NULL; } - close_semaphore( crit ); + if (unix_funcs->fast_RtlDeleteCriticalSection( crit ) == STATUS_NOT_IMPLEMENTED) + NtClose( crit->LockSemaphore ); } else NtClose( crit->LockSemaphore ); crit->LockSemaphore = 0; @@ -446,7 +263,7 @@ NTSTATUS WINAPI RtlpWaitForCriticalSection( RTL_CRITICAL_SECTION *crit ) for (;;) { EXCEPTION_RECORD rec; - NTSTATUS status = wait_semaphore( crit, 5 ); + NTSTATUS status = unix_funcs->fast_RtlpWaitForCriticalSection( crit, 5 ); timeout -= 5; if ( status == STATUS_TIMEOUT ) @@ -456,14 +273,14 @@ NTSTATUS WINAPI RtlpWaitForCriticalSection( RTL_CRITICAL_SECTION *crit ) if (!name) name = "?"; ERR( "section %p %s wait timed out in thread %04x, blocked by %04x, retrying (60 sec)\n", crit, debugstr_a(name), GetCurrentThreadId(), HandleToULong(crit->OwningThread) ); - status = wait_semaphore( crit, 60 ); + status = unix_funcs->fast_RtlpWaitForCriticalSection( crit, 60 ); timeout -= 60; if ( status == STATUS_TIMEOUT && TRACE_ON(relay) ) { ERR( "section %p %s wait timed out in thread %04x, blocked by %04x, retrying (5 min)\n", crit, debugstr_a(name), GetCurrentThreadId(), HandleToULong(crit->OwningThread) ); - status = wait_semaphore( crit, 300 ); + status = unix_funcs->fast_RtlpWaitForCriticalSection( crit, 300 ); timeout -= 300; } } @@ -513,14 +330,8 @@ NTSTATUS WINAPI RtlpWaitForCriticalSection( RTL_CRITICAL_SECTION *crit ) */ NTSTATUS WINAPI RtlpUnWaitCriticalSection( RTL_CRITICAL_SECTION *crit ) { - NTSTATUS ret; + NTSTATUS ret = unix_funcs->fast_RtlpUnWaitCriticalSection( crit ); - /* debug info is cleared by MakeCriticalSectionGlobal */ - if (!crit_section_has_debuginfo( crit ) || ((ret = fast_wake( crit )) == STATUS_NOT_IMPLEMENTED)) - { - HANDLE sem = get_semaphore( crit ); - ret = NtReleaseSemaphore( sem, 1, NULL ); - } if (ret) RtlRaiseStatus( ret ); return ret; } diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 5b49490ee69..eac43ba42c4 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -1049,6 +1049,9 @@ static struct unix_funcs unix_funcs = RtlWaitOnAddress, RtlWakeAddressAll, RtlWakeAddressSingle, + fast_RtlpWaitForCriticalSection, + fast_RtlpUnWaitCriticalSection, + fast_RtlDeleteCriticalSection, fast_RtlTryAcquireSRWLockExclusive, fast_RtlAcquireSRWLockExclusive, fast_RtlTryAcquireSRWLockShared, @@ -1085,7 +1088,6 @@ static struct unix_funcs unix_funcs = exit_process, get_thread_ldt_entry, wine_server_call, - server_wait, server_send_fd, server_get_unix_fd, server_fd_to_handle, diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c index 7f5c474cdeb..cf6f6c3832c 100644 --- a/dlls/ntdll/unix/server.c +++ b/dlls/ntdll/unix/server.c @@ -681,8 +681,8 @@ unsigned int server_select( const select_op_t *select_op, data_size_t size, UINT /*********************************************************************** * server_wait */ -unsigned int CDECL server_wait( const select_op_t *select_op, data_size_t size, UINT flags, - const LARGE_INTEGER *timeout ) +unsigned int server_wait( const select_op_t *select_op, data_size_t size, UINT flags, + const LARGE_INTEGER *timeout ) { timeout_t abs_timeout = timeout ? timeout->QuadPart : TIMEOUT_INFINITE; BOOL user_apc = FALSE; diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index e7afbe1eb54..636dccf1a1b 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -55,6 +55,11 @@ #include #include #include +#ifdef __APPLE__ +# include +# include +# include +#endif #include "ntstatus.h" #define WIN32_NO_STATUS @@ -1055,6 +1060,172 @@ NTSTATUS WINAPI NtOpenSection( HANDLE *handle, ACCESS_MASK access, const OBJECT_ } +static void *no_debug_info_marker = (void *)(ULONG_PTR)-1; + +static BOOL crit_section_has_debuginfo(const RTL_CRITICAL_SECTION *crit) +{ + return crit->DebugInfo != NULL && crit->DebugInfo != no_debug_info_marker; +} + +#ifdef __linux__ + +static inline NTSTATUS fast_critsection_wait( RTL_CRITICAL_SECTION *crit, int timeout ) +{ + int val; + struct timespec timespec; + + if (!use_futexes()) return STATUS_NOT_IMPLEMENTED; + + timespec.tv_sec = timeout; + timespec.tv_nsec = 0; + while ((val = InterlockedCompareExchange( (int *)&crit->LockSemaphore, 0, 1 )) != 1) + { + /* note: this may wait longer than specified in case of signals or */ + /* multiple wake-ups, but that shouldn't be a problem */ + if (futex_wait( (int *)&crit->LockSemaphore, val, ×pec ) == -1 && errno == ETIMEDOUT) + return STATUS_TIMEOUT; + } + return STATUS_WAIT_0; +} + +static inline NTSTATUS fast_critsection_wake( RTL_CRITICAL_SECTION *crit ) +{ + if (!use_futexes()) return STATUS_NOT_IMPLEMENTED; + + *(int *)&crit->LockSemaphore = 1; + futex_wake( (int *)&crit->LockSemaphore, 1 ); + return STATUS_SUCCESS; +} + +NTSTATUS CDECL fast_RtlDeleteCriticalSection( RTL_CRITICAL_SECTION *crit ) +{ + if (!use_futexes()) return STATUS_NOT_IMPLEMENTED; + return STATUS_SUCCESS; +} + +#elif defined(__APPLE__) + +static inline semaphore_t get_mach_semaphore( RTL_CRITICAL_SECTION *crit ) +{ + semaphore_t ret = *(int *)&crit->LockSemaphore; + if (!ret) + { + semaphore_t sem; + if (semaphore_create( mach_task_self(), &sem, SYNC_POLICY_FIFO, 0 )) return 0; + if (!(ret = InterlockedCompareExchange( (int *)&crit->LockSemaphore, sem, 0 ))) + ret = sem; + else + semaphore_destroy( mach_task_self(), sem ); /* somebody beat us to it */ + } + return ret; +} + +static inline NTSTATUS fast_critsection_wait( RTL_CRITICAL_SECTION *crit, int timeout ) +{ + mach_timespec_t timespec; + semaphore_t sem = get_mach_semaphore( crit ); + + timespec.tv_sec = timeout; + timespec.tv_nsec = 0; + for (;;) + { + switch( semaphore_timedwait( sem, timespec )) + { + case KERN_SUCCESS: + return STATUS_WAIT_0; + case KERN_ABORTED: + continue; /* got a signal, restart */ + case KERN_OPERATION_TIMED_OUT: + return STATUS_TIMEOUT; + default: + return STATUS_INVALID_HANDLE; + } + } +} + +static inline NTSTATUS fast_critsection_wake( RTL_CRITICAL_SECTION *crit ) +{ + semaphore_t sem = get_mach_semaphore( crit ); + semaphore_signal( sem ); + return STATUS_SUCCESS; +} + +NTSTATUS CDECL fast_RtlDeleteCriticalSection( RTL_CRITICAL_SECTION *crit ) +{ + semaphore_destroy( mach_task_self(), *(int *)&crit->LockSemaphore ); + return STATUS_SUCCESS; +} + +#else /* __APPLE__ */ + +static inline NTSTATUS fast_critsection_wait( RTL_CRITICAL_SECTION *crit, int timeout ) +{ + return STATUS_NOT_IMPLEMENTED; +} + +static inline NTSTATUS fast_critsection_wake( RTL_CRITICAL_SECTION *crit ) +{ + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS CDECL fast_RtlDeleteCriticalSection( RTL_CRITICAL_SECTION *crit ) +{ + return STATUS_NOT_IMPLEMENTED; +} + +#endif + +static inline HANDLE get_critsection_semaphore( RTL_CRITICAL_SECTION *crit ) +{ + HANDLE ret = crit->LockSemaphore; + if (!ret) + { + HANDLE sem; + if (NtCreateSemaphore( &sem, SEMAPHORE_ALL_ACCESS, NULL, 0, 1 )) return 0; + if (!(ret = InterlockedCompareExchangePointer( &crit->LockSemaphore, sem, 0 ))) + ret = sem; + else + NtClose( sem ); /* somebody beat us to it */ + } + return ret; +} + +NTSTATUS CDECL fast_RtlpWaitForCriticalSection( RTL_CRITICAL_SECTION *crit, int timeout ) +{ + NTSTATUS ret; + + /* debug info is cleared by MakeCriticalSectionGlobal */ + if (!crit_section_has_debuginfo( crit ) || + ((ret = fast_critsection_wait( crit, timeout )) == STATUS_NOT_IMPLEMENTED)) + { + HANDLE sem = get_critsection_semaphore( crit ); + LARGE_INTEGER time; + select_op_t select_op; + + time.QuadPart = timeout * (LONGLONG)-10000000; + select_op.wait.op = SELECT_WAIT; + select_op.wait.handles[0] = wine_server_obj_handle( sem ); + ret = server_wait( &select_op, offsetof( select_op_t, wait.handles[1] ), 0, &time ); + } + return ret; +} + +NTSTATUS CDECL fast_RtlpUnWaitCriticalSection( RTL_CRITICAL_SECTION *crit ) +{ + NTSTATUS ret; + + /* debug info is cleared by MakeCriticalSectionGlobal */ + if (!crit_section_has_debuginfo( crit ) || + ((ret = fast_critsection_wake( crit )) == STATUS_NOT_IMPLEMENTED)) + { + HANDLE sem = get_critsection_semaphore( crit ); + ret = NtReleaseSemaphore( sem, 1, NULL ); + } + return ret; +} + + + #ifdef __linux__ /* Futex-based SRW lock implementation: diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index b6fc1a07b8e..3e61111cba5 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -57,6 +57,9 @@ static inline struct ntdll_thread_data *ntdll_get_thread_data(void) NTSTATUS WINAPI KiUserExceptionDispatcher(EXCEPTION_RECORD*,CONTEXT*); void WINAPI LdrInitializeThunk(CONTEXT*,void**,ULONG_PTR,ULONG_PTR); +extern NTSTATUS CDECL fast_RtlpWaitForCriticalSection( RTL_CRITICAL_SECTION *crit, int timeout ) DECLSPEC_HIDDEN; +extern NTSTATUS CDECL fast_RtlpUnWaitCriticalSection( RTL_CRITICAL_SECTION *crit ) DECLSPEC_HIDDEN; +extern NTSTATUS CDECL fast_RtlDeleteCriticalSection( RTL_CRITICAL_SECTION *crit ) DECLSPEC_HIDDEN; extern NTSTATUS CDECL fast_RtlTryAcquireSRWLockExclusive( RTL_SRWLOCK *lock ) DECLSPEC_HIDDEN; extern NTSTATUS CDECL fast_RtlAcquireSRWLockExclusive( RTL_SRWLOCK *lock ) DECLSPEC_HIDDEN; extern NTSTATUS CDECL fast_RtlTryAcquireSRWLockShared( RTL_SRWLOCK *lock ) DECLSPEC_HIDDEN; @@ -91,8 +94,6 @@ extern void CDECL virtual_set_force_exec( BOOL enable ) DECLSPEC_HIDDEN; extern void CDECL virtual_release_address_space(void) DECLSPEC_HIDDEN; extern void CDECL virtual_set_large_address_space(void) DECLSPEC_HIDDEN; -extern unsigned int CDECL server_wait( const select_op_t *select_op, data_size_t size, UINT flags, - const LARGE_INTEGER *timeout ) DECLSPEC_HIDDEN; extern void CDECL server_send_fd( int fd ) DECLSPEC_HIDDEN; extern int CDECL server_get_unix_fd( HANDLE handle, unsigned int wanted_access, int *unix_fd, int *needs_close, enum server_fd_type *type, @@ -128,6 +129,8 @@ extern void start_server( BOOL debug ) DECLSPEC_HIDDEN; extern unsigned int server_select( const select_op_t *select_op, data_size_t size, UINT flags, timeout_t abs_timeout, CONTEXT *context, RTL_CRITICAL_SECTION *cs, user_apc_t *user_apc ) DECLSPEC_HIDDEN; +extern unsigned int server_wait( const select_op_t *select_op, data_size_t size, UINT flags, + const LARGE_INTEGER *timeout ) DECLSPEC_HIDDEN; extern unsigned int server_queue_process_apc( HANDLE process, const apc_call_t *call, apc_result_t *result ) DECLSPEC_HIDDEN; extern void server_init_process(void) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/unixlib.h b/dlls/ntdll/unixlib.h index d0d8c97fe7c..80d3ce27601 100644 --- a/dlls/ntdll/unixlib.h +++ b/dlls/ntdll/unixlib.h @@ -28,7 +28,7 @@ struct ldt_copy; struct msghdr; /* increment this when you change the function table */ -#define NTDLL_UNIXLIB_VERSION 36 +#define NTDLL_UNIXLIB_VERSION 37 struct unix_funcs { @@ -149,6 +149,9 @@ struct unix_funcs void (WINAPI *RtlWakeAddressSingle)( const void *addr ); /* fast locks */ + NTSTATUS (CDECL *fast_RtlpWaitForCriticalSection)( RTL_CRITICAL_SECTION *crit, int timeout ); + NTSTATUS (CDECL *fast_RtlpUnWaitCriticalSection)( RTL_CRITICAL_SECTION *crit ); + NTSTATUS (CDECL *fast_RtlDeleteCriticalSection)( RTL_CRITICAL_SECTION *crit ); NTSTATUS (CDECL *fast_RtlTryAcquireSRWLockExclusive)( RTL_SRWLOCK *lock ); NTSTATUS (CDECL *fast_RtlAcquireSRWLockExclusive)( RTL_SRWLOCK *lock ); NTSTATUS (CDECL *fast_RtlTryAcquireSRWLockShared)( RTL_SRWLOCK *lock ); @@ -203,8 +206,6 @@ struct unix_funcs /* server functions */ unsigned int (CDECL *server_call)( void *req_ptr ); - unsigned int (CDECL *server_wait)( const select_op_t *select_op, data_size_t size, UINT flags, - const LARGE_INTEGER *timeout ); void (CDECL *server_send_fd)( int fd ); int (CDECL *server_get_unix_fd)( HANDLE handle, unsigned int wanted_access, int *unix_fd, int *needs_close, enum server_fd_type *type, unsigned int *options );