wine-staging/patches/ntdll-NtAlertThreadByThreadId/0010-ntdll-Merge-critsection.c-into-sync.c.patch

934 lines
31 KiB
Diff
Raw Normal View History

From 9e9f51741ee04bcf8123ae23241ba3c4f8c8b2cf Mon Sep 17 00:00:00 2001
From: Zebediah Figura <z.figura12@gmail.com>
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 <z.figura12@gmail.com>
---
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 <assert.h>
-#include <errno.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <time.h>
-#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