Alexandre Julliard : ntdll:
Faster critical sections on MacOS using Mach semaphores.
Alexandre Julliard
julliard at wine.codeweavers.com
Tue Jun 27 15:49:09 CDT 2006
Module: wine
Branch: refs/heads/master
Commit: 27c6c83e1ef3aad395ee2421b5241990dc194010
URL: http://source.winehq.org/git/?p=wine.git;a=commit;h=27c6c83e1ef3aad395ee2421b5241990dc194010
Author: Alexandre Julliard <julliard at winehq.org>
Date: Tue Jun 27 17:39:50 2006 +0200
ntdll: Faster critical sections on MacOS using Mach semaphores.
---
dlls/ntdll/critsection.c | 152 ++++++++++++++++++++++++++++++++++++----------
1 files changed, 119 insertions(+), 33 deletions(-)
diff --git a/dlls/ntdll/critsection.c b/dlls/ntdll/critsection.c
index 2739129..581875f 100644
--- a/dlls/ntdll/critsection.c
+++ b/dlls/ntdll/critsection.c
@@ -90,11 +90,111 @@ static inline int use_futexes(void)
return supported;
}
-#else /* linux */
+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 = interlocked_cmpxchg( (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 ) == -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 <mach/mach.h>
+#include <mach/task.h>
+#include <mach/semaphore.h>
+
+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 = interlocked_cmpxchg( (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 int futex_wait( int *addr, int val, struct timespec *timeout ) { return -ENOSYS; }
-static inline int futex_wake( int *addr, int val ) { return -ENOSYS; }
-static inline int use_futexes(void) { return 0; }
+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
@@ -122,30 +222,18 @@ static inline HANDLE get_semaphore( RTL_
*/
static inline NTSTATUS wait_semaphore( RTL_CRITICAL_SECTION *crit, int timeout )
{
- if (use_futexes() && crit->DebugInfo) /* debug info is cleared by MakeCriticalSectionGlobal */
- {
- int val;
- struct timespec timespec;
+ NTSTATUS ret;
- timespec.tv_sec = timeout;
- timespec.tv_nsec = 0;
- while ((val = interlocked_cmpxchg( (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 ) == -ETIMEDOUT)
- return STATUS_TIMEOUT;
- }
- return STATUS_WAIT_0;
- }
- else
+ /* debug info is cleared by MakeCriticalSectionGlobal */
+ if (!crit->DebugInfo || ((ret = fast_wait( crit, timeout )) == STATUS_NOT_IMPLEMENTED))
{
HANDLE sem = get_semaphore( crit );
LARGE_INTEGER time;
time.QuadPart = timeout * (LONGLONG)-10000000;
- return NtWaitForSingleObject( sem, FALSE, &time );
+ ret = NtWaitForSingleObject( sem, FALSE, &time );
}
+ return ret;
}
/***********************************************************************
@@ -261,8 +349,6 @@ NTSTATUS WINAPI RtlDeleteCriticalSection
crit->LockCount = -1;
crit->RecursionCount = 0;
crit->OwningThread = 0;
- if (crit->LockSemaphore) NtClose( crit->LockSemaphore );
- crit->LockSemaphore = 0;
if (crit->DebugInfo)
{
/* only free the ones we made in here */
@@ -271,7 +357,10 @@ NTSTATUS WINAPI RtlDeleteCriticalSection
RtlFreeHeap( GetProcessHeap(), 0, crit->DebugInfo );
crit->DebugInfo = NULL;
}
+ close_semaphore( crit );
}
+ else NtClose( crit->LockSemaphore );
+ crit->LockSemaphore = 0;
return STATUS_SUCCESS;
}
@@ -360,19 +449,16 @@ NTSTATUS WINAPI RtlpWaitForCriticalSecti
*/
NTSTATUS WINAPI RtlpUnWaitCriticalSection( RTL_CRITICAL_SECTION *crit )
{
- if (use_futexes() && crit->DebugInfo) /* debug info is cleared by MakeCriticalSectionGlobal */
- {
- *(int *)&crit->LockSemaphore = 1;
- futex_wake( (int *)&crit->LockSemaphore, 1 );
- return STATUS_SUCCESS;
- }
- else
+ NTSTATUS ret;
+
+ /* debug info is cleared by MakeCriticalSectionGlobal */
+ if (!crit->DebugInfo || ((ret = fast_wake( crit )) == STATUS_NOT_IMPLEMENTED))
{
HANDLE sem = get_semaphore( crit );
- NTSTATUS res = NtReleaseSemaphore( sem, 1, NULL );
- if (res) RtlRaiseStatus( res );
- return res;
+ ret = NtReleaseSemaphore( sem, 1, NULL );
}
+ if (ret) RtlRaiseStatus( ret );
+ return ret;
}
More information about the wine-cvs
mailing list