[PATCH] ntdll: Merge critsection.c into sync.c.

Zebediah Figura zfigura at codeweavers.com
Tue Oct 26 21:41:52 CDT 2021


Signed-off-by: Zebediah Figura <zfigura at codeweavers.com>
---
 dlls/ntdll/Makefile.in   |   1 -
 dlls/ntdll/critsection.c | 543 ---------------------------------------
 dlls/ntdll/sync.c        | 335 +++++++++++++++++++++++-
 3 files changed, 334 insertions(+), 545 deletions(-)
 delete mode 100644 dlls/ntdll/critsection.c

diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in
index c40e7ba8242..d3be1fad0bc 100644
--- a/dlls/ntdll/Makefile.in
+++ b/dlls/ntdll/Makefile.in
@@ -11,7 +11,6 @@ EXTRADLLFLAGS = -nodefaultlibs -Wl,--image-base,0x7bc00000
 C_SRCS = \
 	actctx.c \
 	atom.c \
-	critsection.c \
 	crypt.c \
 	debugbuffer.c \
 	env.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 f1263ae33fd..bfb30661864 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
  *
@@ -36,6 +36,8 @@
 #include "wine/debug.h"
 #include "ntdll_misc.h"
 
+WINE_DEFAULT_DEBUG_CHANNEL(sync);
+WINE_DECLARE_DEBUG_CHANNEL(relay);
 
 /******************************************************************
  *              RtlRunOnceInitialize (NTDLL.@)
@@ -133,6 +135,337 @@ DWORD WINAPI RtlRunOnceComplete( RTL_RUN_ONCE *once, ULONG flags, void *context
     }
 }
 
+
+/***********************************************************************
+ * 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;
+}
+
 /******************************************************************
  *              RtlRunOnceExecuteOnce (NTDLL.@)
  */
-- 
2.33.0




More information about the wine-devel mailing list