From 9e9f51741ee04bcf8123ae23241ba3c4f8c8b2cf Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 31 Aug 2020 23:30:52 -0500 Subject: [PATCH 10/13] ntdll: Merge critsection.c into sync.c. Signed-off-by: Zebediah Figura --- dlls/ntdll/Makefile.in | 1 - dlls/ntdll/critsection.c | 543 --------------------------------------- dlls/ntdll/sync.c | 334 +++++++++++++++++++++++- 3 files changed, 333 insertions(+), 545 deletions(-) delete mode 100644 dlls/ntdll/critsection.c diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in index b2f63d9f63a..5ef28d2f722 100644 --- a/dlls/ntdll/Makefile.in +++ b/dlls/ntdll/Makefile.in @@ -9,7 +9,6 @@ EXTRADLLFLAGS = -mno-cygwin -nodefaultlibs -Wl,--image-base,0x7bc00000 C_SRCS = \ actctx.c \ atom.c \ - critsection.c \ crypt.c \ debugbuffer.c \ directory.c \ diff --git a/dlls/ntdll/critsection.c b/dlls/ntdll/critsection.c deleted file mode 100644 index fe7d933c0fa..00000000000 --- a/dlls/ntdll/critsection.c +++ /dev/null @@ -1,543 +0,0 @@ -/* - * Win32 critical sections - * - * Copyright 1998 Alexandre Julliard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include -#include -#include -#include -#include -#include -#include "ntstatus.h" -#define WIN32_NO_STATUS -#include "windef.h" -#include "winternl.h" -#include "wine/debug.h" -#include "ntdll_misc.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ntdll); -WINE_DECLARE_DEBUG_CHANNEL(relay); - -static inline void small_pause(void) -{ -#ifdef __i386__ - __asm__ __volatile__( "rep;nop" : : : "memory" ); -#else - __asm__ __volatile__( "" : : : "memory" ); -#endif -} - -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; -} - -/*********************************************************************** - * 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 = unix_funcs->fast_RtlpWaitForCriticalSection( crit, timeout )) == STATUS_NOT_IMPLEMENTED)) - { - HANDLE sem = get_semaphore( crit ); - LARGE_INTEGER time; - - time.QuadPart = timeout * (LONGLONG)-10000000; - ret = NtWaitForSingleObject( sem, FALSE, &time ); - } - return ret; -} - -/*********************************************************************** - * RtlInitializeCriticalSection (NTDLL.@) - * - * Initialises a new critical section. - * - * PARAMS - * crit [O] Critical section to initialise - * - * RETURNS - * STATUS_SUCCESS. - * - * SEE - * RtlInitializeCriticalSectionEx(), - * RtlInitializeCriticalSectionAndSpinCount(), RtlDeleteCriticalSection(), - * RtlEnterCriticalSection(), RtlLeaveCriticalSection(), - * RtlTryEnterCriticalSection(), RtlSetCriticalSectionSpinCount() - */ -NTSTATUS WINAPI RtlInitializeCriticalSection( RTL_CRITICAL_SECTION *crit ) -{ - return RtlInitializeCriticalSectionEx( crit, 0, 0 ); -} - -/*********************************************************************** - * RtlInitializeCriticalSectionAndSpinCount (NTDLL.@) - * - * Initialises a new critical section with a given spin count. - * - * PARAMS - * crit [O] Critical section to initialise - * spincount [I] Spin count for crit - * - * RETURNS - * STATUS_SUCCESS. - * - * NOTES - * Available on NT4 SP3 or later. - * - * SEE - * RtlInitializeCriticalSectionEx(), - * RtlInitializeCriticalSection(), RtlDeleteCriticalSection(), - * RtlEnterCriticalSection(), RtlLeaveCriticalSection(), - * RtlTryEnterCriticalSection(), RtlSetCriticalSectionSpinCount() - */ -NTSTATUS WINAPI RtlInitializeCriticalSectionAndSpinCount( RTL_CRITICAL_SECTION *crit, ULONG spincount ) -{ - return RtlInitializeCriticalSectionEx( crit, spincount, 0 ); -} - -/*********************************************************************** - * RtlInitializeCriticalSectionEx (NTDLL.@) - * - * Initialises a new critical section with a given spin count and flags. - * - * PARAMS - * crit [O] Critical section to initialise. - * spincount [I] Number of times to spin upon contention. - * flags [I] RTL_CRITICAL_SECTION_FLAG_ flags from winnt.h. - * - * RETURNS - * STATUS_SUCCESS. - * - * NOTES - * Available on Vista or later. - * - * SEE - * RtlInitializeCriticalSection(), RtlDeleteCriticalSection(), - * RtlEnterCriticalSection(), RtlLeaveCriticalSection(), - * RtlTryEnterCriticalSection(), RtlSetCriticalSectionSpinCount() - */ -NTSTATUS WINAPI RtlInitializeCriticalSectionEx( RTL_CRITICAL_SECTION *crit, ULONG spincount, ULONG flags ) -{ - if (flags & (RTL_CRITICAL_SECTION_FLAG_DYNAMIC_SPIN|RTL_CRITICAL_SECTION_FLAG_STATIC_INIT)) - FIXME("(%p,%u,0x%08x) semi-stub\n", crit, spincount, flags); - - /* FIXME: if RTL_CRITICAL_SECTION_FLAG_STATIC_INIT is given, we should use - * memory from a static pool to hold the debug info. Then heap.c could pass - * this flag rather than initialising the process heap CS by hand. If this - * is done, then debug info should be managed through Rtlp[Allocate|Free]DebugInfo - * so (e.g.) MakeCriticalSectionGlobal() doesn't free it using HeapFree(). - */ - if (flags & RTL_CRITICAL_SECTION_FLAG_NO_DEBUG_INFO) - crit->DebugInfo = no_debug_info_marker; - else - { - crit->DebugInfo = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(RTL_CRITICAL_SECTION_DEBUG)); - if (crit->DebugInfo) - { - crit->DebugInfo->Type = 0; - crit->DebugInfo->CreatorBackTraceIndex = 0; - crit->DebugInfo->CriticalSection = crit; - crit->DebugInfo->ProcessLocksList.Blink = &(crit->DebugInfo->ProcessLocksList); - crit->DebugInfo->ProcessLocksList.Flink = &(crit->DebugInfo->ProcessLocksList); - crit->DebugInfo->EntryCount = 0; - crit->DebugInfo->ContentionCount = 0; - memset( crit->DebugInfo->Spare, 0, sizeof(crit->DebugInfo->Spare) ); - } - } - crit->LockCount = -1; - crit->RecursionCount = 0; - crit->OwningThread = 0; - crit->LockSemaphore = 0; - if (NtCurrentTeb()->Peb->NumberOfProcessors <= 1) spincount = 0; - crit->SpinCount = spincount & ~0x80000000; - return STATUS_SUCCESS; -} - -/*********************************************************************** - * RtlSetCriticalSectionSpinCount (NTDLL.@) - * - * Sets the spin count of a critical section. - * - * PARAMS - * crit [I/O] Critical section - * spincount [I] Spin count for crit - * - * RETURNS - * The previous spin count. - * - * NOTES - * If the system is not SMP, spincount is ignored and set to 0. - * - * SEE - * RtlInitializeCriticalSectionEx(), - * RtlInitializeCriticalSection(), RtlInitializeCriticalSectionAndSpinCount(), - * RtlDeleteCriticalSection(), RtlEnterCriticalSection(), - * RtlLeaveCriticalSection(), RtlTryEnterCriticalSection() - */ -ULONG WINAPI RtlSetCriticalSectionSpinCount( RTL_CRITICAL_SECTION *crit, ULONG spincount ) -{ - ULONG oldspincount = crit->SpinCount; - if (NtCurrentTeb()->Peb->NumberOfProcessors <= 1) spincount = 0; - crit->SpinCount = spincount; - return oldspincount; -} - -/*********************************************************************** - * RtlDeleteCriticalSection (NTDLL.@) - * - * Frees the resources used by a critical section. - * - * PARAMS - * crit [I/O] Critical section to free - * - * RETURNS - * STATUS_SUCCESS. - * - * SEE - * RtlInitializeCriticalSectionEx(), - * RtlInitializeCriticalSection(), RtlInitializeCriticalSectionAndSpinCount(), - * RtlDeleteCriticalSection(), RtlEnterCriticalSection(), - * RtlLeaveCriticalSection(), RtlTryEnterCriticalSection() - */ -NTSTATUS WINAPI RtlDeleteCriticalSection( RTL_CRITICAL_SECTION *crit ) -{ - crit->LockCount = -1; - crit->RecursionCount = 0; - crit->OwningThread = 0; - if (crit_section_has_debuginfo( crit )) - { - /* only free the ones we made in here */ - if (!crit->DebugInfo->Spare[0]) - { - RtlFreeHeap( GetProcessHeap(), 0, crit->DebugInfo ); - crit->DebugInfo = NULL; - } - if (unix_funcs->fast_RtlDeleteCriticalSection( crit ) == STATUS_NOT_IMPLEMENTED) - NtClose( crit->LockSemaphore ); - } - else NtClose( crit->LockSemaphore ); - crit->LockSemaphore = 0; - return STATUS_SUCCESS; -} - - -/*********************************************************************** - * RtlpWaitForCriticalSection (NTDLL.@) - * - * Waits for a busy critical section to become free. - * - * PARAMS - * crit [I/O] Critical section to wait for - * - * RETURNS - * STATUS_SUCCESS. - * - * NOTES - * Use RtlEnterCriticalSection() instead of this function as it is often much - * faster. - * - * SEE - * RtlInitializeCriticalSectionEx(), - * RtlInitializeCriticalSection(), RtlInitializeCriticalSectionAndSpinCount(), - * RtlDeleteCriticalSection(), RtlEnterCriticalSection(), - * RtlLeaveCriticalSection(), RtlTryEnterCriticalSection() - */ -NTSTATUS WINAPI RtlpWaitForCriticalSection( RTL_CRITICAL_SECTION *crit ) -{ - LONGLONG timeout = NtCurrentTeb()->Peb->CriticalSectionTimeout.QuadPart / -10000000; - - /* Don't allow blocking on a critical section during process termination */ - if (RtlDllShutdownInProgress()) - { - WARN( "process %s is shutting down, returning STATUS_SUCCESS\n", - debugstr_w(NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer) ); - return STATUS_SUCCESS; - } - - for (;;) - { - EXCEPTION_RECORD rec; - NTSTATUS status = wait_semaphore( crit, 5 ); - timeout -= 5; - - if ( status == STATUS_TIMEOUT ) - { - const char *name = NULL; - if (crit_section_has_debuginfo( crit )) name = (char *)crit->DebugInfo->Spare[0]; - 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 ); - 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 ); - timeout -= 300; - } - } - if (status == STATUS_WAIT_0) break; - - /* Throw exception only for Wine internal locks */ - if (!crit_section_has_debuginfo( crit ) || !crit->DebugInfo->Spare[0]) continue; - - /* only throw deadlock exception if configured timeout is reached */ - if (timeout > 0) continue; - - rec.ExceptionCode = STATUS_POSSIBLE_DEADLOCK; - rec.ExceptionFlags = 0; - rec.ExceptionRecord = NULL; - rec.ExceptionAddress = RtlRaiseException; /* sic */ - rec.NumberParameters = 1; - rec.ExceptionInformation[0] = (ULONG_PTR)crit; - RtlRaiseException( &rec ); - } - if (crit_section_has_debuginfo( crit )) crit->DebugInfo->ContentionCount++; - return STATUS_SUCCESS; -} - - -/*********************************************************************** - * RtlpUnWaitCriticalSection (NTDLL.@) - * - * Notifies other threads waiting on the busy critical section that it has - * become free. - * - * PARAMS - * crit [I/O] Critical section - * - * RETURNS - * Success: STATUS_SUCCESS. - * Failure: Any error returned by NtReleaseSemaphore() - * - * NOTES - * Use RtlLeaveCriticalSection() instead of this function as it is often much - * faster. - * - * SEE - * RtlInitializeCriticalSectionEx(), - * RtlInitializeCriticalSection(), RtlInitializeCriticalSectionAndSpinCount(), - * RtlDeleteCriticalSection(), RtlEnterCriticalSection(), - * RtlLeaveCriticalSection(), RtlTryEnterCriticalSection() - */ -NTSTATUS WINAPI RtlpUnWaitCriticalSection( RTL_CRITICAL_SECTION *crit ) -{ - NTSTATUS ret; - - /* debug info is cleared by MakeCriticalSectionGlobal */ - if (!crit_section_has_debuginfo( crit ) || - ((ret = unix_funcs->fast_RtlpUnWaitCriticalSection( crit )) == STATUS_NOT_IMPLEMENTED)) - { - HANDLE sem = get_semaphore( crit ); - ret = NtReleaseSemaphore( sem, 1, NULL ); - } - if (ret) RtlRaiseStatus( ret ); - return ret; -} - - -/*********************************************************************** - * RtlEnterCriticalSection (NTDLL.@) - * - * Enters a critical section, waiting for it to become available if necessary. - * - * PARAMS - * crit [I/O] Critical section to enter - * - * RETURNS - * STATUS_SUCCESS. The critical section is held by the caller. - * - * SEE - * RtlInitializeCriticalSectionEx(), - * RtlInitializeCriticalSection(), RtlInitializeCriticalSectionAndSpinCount(), - * RtlDeleteCriticalSection(), RtlSetCriticalSectionSpinCount(), - * RtlLeaveCriticalSection(), RtlTryEnterCriticalSection() - */ -NTSTATUS WINAPI RtlEnterCriticalSection( RTL_CRITICAL_SECTION *crit ) -{ - if (crit->SpinCount) - { - ULONG count; - - if (RtlTryEnterCriticalSection( crit )) return STATUS_SUCCESS; - for (count = crit->SpinCount; count > 0; count--) - { - if (crit->LockCount > 0) break; /* more than one waiter, don't bother spinning */ - if (crit->LockCount == -1) /* try again */ - { - if (InterlockedCompareExchange( &crit->LockCount, 0, -1 ) == -1) goto done; - } - small_pause(); - } - } - - if (InterlockedIncrement( &crit->LockCount )) - { - if (crit->OwningThread == ULongToHandle(GetCurrentThreadId())) - { - crit->RecursionCount++; - return STATUS_SUCCESS; - } - - /* Now wait for it */ - RtlpWaitForCriticalSection( crit ); - } -done: - crit->OwningThread = ULongToHandle(GetCurrentThreadId()); - crit->RecursionCount = 1; - return STATUS_SUCCESS; -} - - -/*********************************************************************** - * RtlTryEnterCriticalSection (NTDLL.@) - * - * Tries to enter a critical section without waiting. - * - * PARAMS - * crit [I/O] Critical section to enter - * - * RETURNS - * Success: TRUE. The critical section is held by the caller. - * Failure: FALSE. The critical section is currently held by another thread. - * - * SEE - * RtlInitializeCriticalSectionEx(), - * RtlInitializeCriticalSection(), RtlInitializeCriticalSectionAndSpinCount(), - * RtlDeleteCriticalSection(), RtlEnterCriticalSection(), - * RtlLeaveCriticalSection(), RtlSetCriticalSectionSpinCount() - */ -BOOL WINAPI RtlTryEnterCriticalSection( RTL_CRITICAL_SECTION *crit ) -{ - BOOL ret = FALSE; - if (InterlockedCompareExchange( &crit->LockCount, 0, -1 ) == -1) - { - crit->OwningThread = ULongToHandle(GetCurrentThreadId()); - crit->RecursionCount = 1; - ret = TRUE; - } - else if (crit->OwningThread == ULongToHandle(GetCurrentThreadId())) - { - InterlockedIncrement( &crit->LockCount ); - crit->RecursionCount++; - ret = TRUE; - } - return ret; -} - - -/*********************************************************************** - * RtlIsCriticalSectionLocked (NTDLL.@) - * - * Checks if the critical section is locked by any thread. - * - * PARAMS - * crit [I/O] Critical section to check. - * - * RETURNS - * Success: TRUE. The critical section is locked. - * Failure: FALSE. The critical section is not locked. - */ -BOOL WINAPI RtlIsCriticalSectionLocked( RTL_CRITICAL_SECTION *crit ) -{ - return crit->RecursionCount != 0; -} - - -/*********************************************************************** - * RtlIsCriticalSectionLockedByThread (NTDLL.@) - * - * Checks if the critical section is locked by the current thread. - * - * PARAMS - * crit [I/O] Critical section to check. - * - * RETURNS - * Success: TRUE. The critical section is locked. - * Failure: FALSE. The critical section is not locked. - */ -BOOL WINAPI RtlIsCriticalSectionLockedByThread( RTL_CRITICAL_SECTION *crit ) -{ - return crit->OwningThread == ULongToHandle(GetCurrentThreadId()) && - crit->RecursionCount; -} - - -/*********************************************************************** - * RtlLeaveCriticalSection (NTDLL.@) - * - * Leaves a critical section. - * - * PARAMS - * crit [I/O] Critical section to leave. - * - * RETURNS - * STATUS_SUCCESS. - * - * SEE - * RtlInitializeCriticalSectionEx(), - * RtlInitializeCriticalSection(), RtlInitializeCriticalSectionAndSpinCount(), - * RtlDeleteCriticalSection(), RtlEnterCriticalSection(), - * RtlSetCriticalSectionSpinCount(), RtlTryEnterCriticalSection() - */ -NTSTATUS WINAPI RtlLeaveCriticalSection( RTL_CRITICAL_SECTION *crit ) -{ - if (--crit->RecursionCount) - { - if (crit->RecursionCount > 0) InterlockedDecrement( &crit->LockCount ); - else ERR( "section %p is not acquired\n", crit ); - } - else - { - crit->OwningThread = 0; - if (InterlockedDecrement( &crit->LockCount ) >= 0) - { - /* someone is waiting */ - RtlpUnWaitCriticalSection( crit ); - } - } - return STATUS_SUCCESS; -} diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c index 05bccf698b6..ea327172b86 100644 --- a/dlls/ntdll/sync.c +++ b/dlls/ntdll/sync.c @@ -2,7 +2,7 @@ * Process synchronisation * * Copyright 1996, 1997, 1998 Marcus Meissner - * Copyright 1997, 1999 Alexandre Julliard + * Copyright 1997, 1998, 1999 Alexandre Julliard * Copyright 1999, 2000 Juergen Schmied * Copyright 2003 Eric Pouech * @@ -38,6 +38,7 @@ #include "ntdll_misc.h" WINE_DEFAULT_DEBUG_CHANNEL(sync); +WINE_DECLARE_DEBUG_CHANNEL(relay); static const char *debugstr_timeout( const LARGE_INTEGER *timeout ) { @@ -626,3 +627,334 @@ void WINAPI RtlWakeAddressSingle( const void *addr ) } teb_list_rdunlock(); } + + +/*********************************************************************** + * Critical sections + ***********************************************************************/ + + +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; +} + +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; +} + +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 = unix_funcs->fast_RtlpWaitForCriticalSection( crit, timeout )) == STATUS_NOT_IMPLEMENTED)) + { + HANDLE sem = get_semaphore( crit ); + LARGE_INTEGER time; + + time.QuadPart = timeout * (LONGLONG)-10000000; + ret = NtWaitForSingleObject( sem, FALSE, &time ); + } + return ret; +} + +/****************************************************************************** + * RtlInitializeCriticalSection (NTDLL.@) + */ +NTSTATUS WINAPI RtlInitializeCriticalSection( RTL_CRITICAL_SECTION *crit ) +{ + return RtlInitializeCriticalSectionEx( crit, 0, 0 ); +} + + +/****************************************************************************** + * RtlInitializeCriticalSectionAndSpinCount (NTDLL.@) + */ +NTSTATUS WINAPI RtlInitializeCriticalSectionAndSpinCount( RTL_CRITICAL_SECTION *crit, ULONG spincount ) +{ + return RtlInitializeCriticalSectionEx( crit, spincount, 0 ); +} + + +/****************************************************************************** + * RtlInitializeCriticalSectionEx (NTDLL.@) + */ +NTSTATUS WINAPI RtlInitializeCriticalSectionEx( RTL_CRITICAL_SECTION *crit, ULONG spincount, ULONG flags ) +{ + if (flags & (RTL_CRITICAL_SECTION_FLAG_DYNAMIC_SPIN|RTL_CRITICAL_SECTION_FLAG_STATIC_INIT)) + FIXME("(%p,%u,0x%08x) semi-stub\n", crit, spincount, flags); + + /* FIXME: if RTL_CRITICAL_SECTION_FLAG_STATIC_INIT is given, we should use + * memory from a static pool to hold the debug info. Then heap.c could pass + * this flag rather than initialising the process heap CS by hand. If this + * is done, then debug info should be managed through Rtlp[Allocate|Free]DebugInfo + * so (e.g.) MakeCriticalSectionGlobal() doesn't free it using HeapFree(). + */ + if (flags & RTL_CRITICAL_SECTION_FLAG_NO_DEBUG_INFO) + crit->DebugInfo = no_debug_info_marker; + else + { + crit->DebugInfo = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(RTL_CRITICAL_SECTION_DEBUG )); + if (crit->DebugInfo) + { + crit->DebugInfo->Type = 0; + crit->DebugInfo->CreatorBackTraceIndex = 0; + crit->DebugInfo->CriticalSection = crit; + crit->DebugInfo->ProcessLocksList.Blink = &crit->DebugInfo->ProcessLocksList; + crit->DebugInfo->ProcessLocksList.Flink = &crit->DebugInfo->ProcessLocksList; + crit->DebugInfo->EntryCount = 0; + crit->DebugInfo->ContentionCount = 0; + memset( crit->DebugInfo->Spare, 0, sizeof(crit->DebugInfo->Spare) ); + } + } + crit->LockCount = -1; + crit->RecursionCount = 0; + crit->OwningThread = 0; + crit->LockSemaphore = 0; + if (NtCurrentTeb()->Peb->NumberOfProcessors <= 1) spincount = 0; + crit->SpinCount = spincount & ~0x80000000; + return STATUS_SUCCESS; +} + + +/****************************************************************************** + * RtlSetCriticalSectionSpinCount (NTDLL.@) + */ +ULONG WINAPI RtlSetCriticalSectionSpinCount( RTL_CRITICAL_SECTION *crit, ULONG spincount ) +{ + ULONG oldspincount = crit->SpinCount; + if (NtCurrentTeb()->Peb->NumberOfProcessors <= 1) spincount = 0; + crit->SpinCount = spincount; + return oldspincount; +} + + +/****************************************************************************** + * RtlDeleteCriticalSection (NTDLL.@) + */ +NTSTATUS WINAPI RtlDeleteCriticalSection( RTL_CRITICAL_SECTION *crit ) +{ + crit->LockCount = -1; + crit->RecursionCount = 0; + crit->OwningThread = 0; + if (crit_section_has_debuginfo( crit )) + { + /* only free the ones we made in here */ + if (!crit->DebugInfo->Spare[0]) + { + RtlFreeHeap( GetProcessHeap(), 0, crit->DebugInfo ); + crit->DebugInfo = NULL; + } + if (unix_funcs->fast_RtlDeleteCriticalSection( crit ) == STATUS_NOT_IMPLEMENTED) + NtClose( crit->LockSemaphore ); + } + else NtClose( crit->LockSemaphore ); + crit->LockSemaphore = 0; + return STATUS_SUCCESS; +} + + +/****************************************************************************** + * RtlpWaitForCriticalSection (NTDLL.@) + */ +NTSTATUS WINAPI RtlpWaitForCriticalSection( RTL_CRITICAL_SECTION *crit ) +{ + LONGLONG timeout = NtCurrentTeb()->Peb->CriticalSectionTimeout.QuadPart / -10000000; + + /* Don't allow blocking on a critical section during process termination */ + if (RtlDllShutdownInProgress()) + { + WARN( "process %s is shutting down, returning STATUS_SUCCESS\n", + debugstr_w(NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer) ); + return STATUS_SUCCESS; + } + + for (;;) + { + EXCEPTION_RECORD rec; + NTSTATUS status = wait_semaphore( crit, 5 ); + timeout -= 5; + + if ( status == STATUS_TIMEOUT ) + { + const char *name = NULL; + if (crit_section_has_debuginfo( crit )) name = (char *)crit->DebugInfo->Spare[0]; + 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 ); + 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 ); + timeout -= 300; + } + } + if (status == STATUS_WAIT_0) break; + + /* Throw exception only for Wine internal locks */ + if (!crit_section_has_debuginfo( crit ) || !crit->DebugInfo->Spare[0]) continue; + + /* only throw deadlock exception if configured timeout is reached */ + if (timeout > 0) continue; + + rec.ExceptionCode = STATUS_POSSIBLE_DEADLOCK; + rec.ExceptionFlags = 0; + rec.ExceptionRecord = NULL; + rec.ExceptionAddress = RtlRaiseException; /* sic */ + rec.NumberParameters = 1; + rec.ExceptionInformation[0] = (ULONG_PTR)crit; + RtlRaiseException( &rec ); + } + if (crit_section_has_debuginfo( crit )) crit->DebugInfo->ContentionCount++; + return STATUS_SUCCESS; +} + + +/****************************************************************************** + * RtlpUnWaitCriticalSection (NTDLL.@) + */ +NTSTATUS WINAPI RtlpUnWaitCriticalSection( RTL_CRITICAL_SECTION *crit ) +{ + NTSTATUS ret; + + /* debug info is cleared by MakeCriticalSectionGlobal */ + if (!crit_section_has_debuginfo( crit ) || + ((ret = unix_funcs->fast_RtlpUnWaitCriticalSection( crit )) == STATUS_NOT_IMPLEMENTED)) + { + HANDLE sem = get_semaphore( crit ); + ret = NtReleaseSemaphore( sem, 1, NULL ); + } + if (ret) RtlRaiseStatus( ret ); + return ret; +} + + +static inline void small_pause(void) +{ +#ifdef __i386__ + __asm__ __volatile__( "rep;nop" : : : "memory" ); +#else + __asm__ __volatile__( "" : : : "memory" ); +#endif +} + +/****************************************************************************** + * RtlEnterCriticalSection (NTDLL.@) + */ +NTSTATUS WINAPI RtlEnterCriticalSection( RTL_CRITICAL_SECTION *crit ) +{ + if (crit->SpinCount) + { + ULONG count; + + if (RtlTryEnterCriticalSection( crit )) return STATUS_SUCCESS; + for (count = crit->SpinCount; count > 0; count--) + { + if (crit->LockCount > 0) break; /* more than one waiter, don't bother spinning */ + if (crit->LockCount == -1) /* try again */ + { + if (InterlockedCompareExchange( &crit->LockCount, 0, -1 ) == -1) goto done; + } + small_pause(); + } + } + + if (InterlockedIncrement( &crit->LockCount )) + { + if (crit->OwningThread == ULongToHandle(GetCurrentThreadId())) + { + crit->RecursionCount++; + return STATUS_SUCCESS; + } + + /* Now wait for it */ + RtlpWaitForCriticalSection( crit ); + } +done: + crit->OwningThread = ULongToHandle(GetCurrentThreadId()); + crit->RecursionCount = 1; + return STATUS_SUCCESS; +} + + +/****************************************************************************** + * RtlTryEnterCriticalSection (NTDLL.@) + */ +BOOL WINAPI RtlTryEnterCriticalSection( RTL_CRITICAL_SECTION *crit ) +{ + BOOL ret = FALSE; + if (InterlockedCompareExchange( &crit->LockCount, 0, -1 ) == -1) + { + crit->OwningThread = ULongToHandle(GetCurrentThreadId()); + crit->RecursionCount = 1; + ret = TRUE; + } + else if (crit->OwningThread == ULongToHandle(GetCurrentThreadId())) + { + InterlockedIncrement( &crit->LockCount ); + crit->RecursionCount++; + ret = TRUE; + } + return ret; +} + + +/****************************************************************************** + * RtlIsCriticalSectionLocked (NTDLL.@) + */ +BOOL WINAPI RtlIsCriticalSectionLocked( RTL_CRITICAL_SECTION *crit ) +{ + return crit->RecursionCount != 0; +} + + +/****************************************************************************** + * RtlIsCriticalSectionLockedByThread (NTDLL.@) + */ +BOOL WINAPI RtlIsCriticalSectionLockedByThread( RTL_CRITICAL_SECTION *crit ) +{ + return crit->OwningThread == ULongToHandle(GetCurrentThreadId()) && + crit->RecursionCount; +} + + +/****************************************************************************** + * RtlLeaveCriticalSection (NTDLL.@) + */ +NTSTATUS WINAPI RtlLeaveCriticalSection( RTL_CRITICAL_SECTION *crit ) +{ + if (--crit->RecursionCount) + { + if (crit->RecursionCount > 0) InterlockedDecrement( &crit->LockCount ); + else ERR( "section %p is not acquired\n", crit ); + } + else + { + crit->OwningThread = 0; + if (InterlockedDecrement( &crit->LockCount ) >= 0) + { + /* someone is waiting */ + RtlpUnWaitCriticalSection( crit ); + } + } + return STATUS_SUCCESS; +} -- 2.29.2