--- trunk/reactos/include/ntdll/rtl.h 2005-01-03 14:47:11 UTC (rev 12756)
+++ trunk/reactos/include/ntdll/rtl.h 2005-01-03 14:58:44 UTC (rev 12757)
@@ -1,4 +1,4 @@
-/* $Id: rtl.h,v 1.53 2004/11/29 00:05:31 gdalsnes Exp $
+/* $Id$
*
*/
@@ -100,7 +100,7 @@
ULONG EntryCount;
ULONG ContentionCount;
ULONG Depth;
- PVOID OwnerBackTrace[ 5 ];
+ PVOID Spare[ 2 ];
} CRITICAL_SECTION_DEBUG, *PCRITICAL_SECTION_DEBUG;
@@ -190,13 +190,13 @@
IN BOOLEAN Success,
IN BOOLEAN Failure);
-VOID STDCALL
+NTSTATUS STDCALL
RtlDeleteCriticalSection (PCRITICAL_SECTION CriticalSection);
WCHAR STDCALL
RtlDowncaseUnicodeChar(IN WCHAR Source);
-VOID STDCALL
+NTSTATUS STDCALL
RtlEnterCriticalSection (PCRITICAL_SECTION CriticalSection);
NTSTATUS STDCALL
@@ -211,7 +211,7 @@
IN ULONG Base,
PUNICODE_STRING String);
-VOID STDCALL
+NTSTATUS STDCALL
RtlLeaveCriticalSection (PCRITICAL_SECTION CriticalSection);
BOOLEAN STDCALL
@@ -744,12 +744,12 @@
LONG Value
);
-PVOID
+LONG
STDCALL
InterlockedCompareExchange (
- PVOID *Destination,
- PVOID Exchange,
- PVOID Comperand
+ PLONG Destination,
+ LONG Exchange,
+ LONG Comperand
);
LONG
@@ -759,6 +759,26 @@
LONG Increment
);
+#ifndef InterlockedExchangePointer
+ #ifdef _WIN64
+ #define InterlockedExchangePointer(Target, Value) \
+ (PVOID)InterlockedExchange64((PLONGLONG)(Target), (LONGLONG)(Value))
+ #else
+ #define InterlockedExchangePointer(Target, Value) \
+ (PVOID)InterlockedExchange((PLONG)(Target), (LONG)(Value))
+ #endif
+#endif
+
+#ifndef InterlockedCompareExchangePointer
+ #ifdef _WIN64
+ #define InterlockedCompareExchangePointer(Target, Exchange, Comperand) \
+ (PVOID)InterlockedCompareExchange64((PLONGLONG)(Target), (LONGLONG)(Exchange), (LONGLONG)(Comperand))
+ #else
+ #define InterlockedCompareExchangePointer(Target, Exchange, Comperand) \
+ (PVOID)InterlockedCompareExchange((PLONG)Target, (LONG)Exchange, (LONG)Comperand)
+ #endif
+#endif
+
#endif /* __INTERLOCKED_DECLARED */
#endif /* __NTDRIVER__ */
--- trunk/reactos/lib/ntdll/rtl/critical.c 2005-01-03 14:47:11 UTC (rev 12756)
+++ trunk/reactos/lib/ntdll/rtl/critical.c 2005-01-03 14:58:44 UTC (rev 12757)
@@ -1,4 +1,4 @@
-/* $Id: critical.c,v 1.20 2004/03/24 23:43:52 gdalsnes Exp $
+/* $Id$
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries
@@ -19,160 +19,391 @@
/* FUNCTIONS *****************************************************************/
-/*
- * @implemented
- */
-VOID STDCALL
-RtlDeleteCriticalSection(PCRITICAL_SECTION CriticalSection)
+inline static HANDLE RtlGetCurrentThreadId()
{
- NtClose(CriticalSection->LockSemaphore);
- CriticalSection->LockCount = -1;
+ return (HANDLE)NtCurrentTeb()->Cid.UniqueThread;
}
-/*
- * @implemented
- */
-DWORD STDCALL
-RtlSetCriticalSectionSpinCount(
- LPCRITICAL_SECTION CriticalSection,
- DWORD SpinCount
- )
+inline static void small_pause(void)
{
-
-#ifdef MP
- DWORD PrevSpinCount = CriticalSection->SpinCount;
- CriticalSection->SpinCount = SpinCount;
- return PrevSpinCount;
+#ifdef __i386__
+ __asm__ __volatile__( "rep;nop" : : : "memory" );
#else
- return 0;
+ __asm__ __volatile__( "" : : : "memory" );
#endif
+}
+/***********************************************************************
+ * get_semaphore
+ */
+static inline HANDLE get_semaphore( PCRITICAL_SECTION crit )
+{
+ HANDLE ret = crit->LockSemaphore;
+ if (!ret)
+ {
+ HANDLE sem;
+ if (!NT_SUCCESS(NtCreateSemaphore( &sem, SEMAPHORE_ALL_ACCESS, NULL, 0, 1 ))) return 0;
+ if (!(ret = (HANDLE)InterlockedCompareExchangePointer( (PVOID *)&crit->LockSemaphore,
+ (PVOID)sem, 0 )))
+ ret = sem;
+ else
+ NtClose(sem); /* somebody beat us to it */
+ }
+ return ret;
}
+/***********************************************************************
+ * RtlInitializeCriticalSection (NTDLL.@)
+ *
+ * Initialises a new critical section.
+ *
+ * PARAMS
+ * crit [O] Critical section to initialise
+ *
+ * RETURNS
+ * STATUS_SUCCESS.
+ *
+ * SEE
+ * RtlInitializeCriticalSectionAndSpinCount(), RtlDeleteCriticalSection(),
+ * RtlEnterCriticalSection(), RtlLeaveCriticalSection(),
+ * RtlTryEnterCriticalSection(), RtlSetCriticalSectionSpinCount()
+ */
+NTSTATUS STDCALL RtlInitializeCriticalSection( PCRITICAL_SECTION crit )
+{
+ return RtlInitializeCriticalSectionAndSpinCount( crit, 0 );
+}
-/*
- * @implemented
+/***********************************************************************
+ * 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
+ * RtlInitializeCriticalSection(), RtlDeleteCriticalSection(),
+ * RtlEnterCriticalSection(), RtlLeaveCriticalSection(),
+ * RtlTryEnterCriticalSection(), RtlSetCriticalSectionSpinCount()
*/
-VOID STDCALL
-RtlEnterCriticalSection(PCRITICAL_SECTION CriticalSection)
+NTSTATUS STDCALL RtlInitializeCriticalSectionAndSpinCount( PCRITICAL_SECTION crit, ULONG spincount )
{
- HANDLE Thread = (HANDLE)NtCurrentTeb()->Cid.UniqueThread;
-
- if (InterlockedIncrement(&CriticalSection->LockCount))
- {
- NTSTATUS Status;
-
- if (CriticalSection->OwningThread == Thread)
- {
- CriticalSection->RecursionCount++;
- return;
- }
-
- DPRINT("Entering wait for critical section\n");
- Status = NtWaitForSingleObject(CriticalSection->LockSemaphore,
- 0, FALSE);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("RtlEnterCriticalSection: Failed to wait (Status %x)\n",
- Status);
- }
- DPRINT("Left wait for critical section\n");
- }
- CriticalSection->OwningThread = Thread;
- CriticalSection->RecursionCount = 1;
+ /* Does ROS need this, or is this special to Wine? And if ros need it, should
+ it be enabled in the release build? -Gunnar */
+ if (RtlGetProcessHeap()) crit->DebugInfo = NULL;
+ else
+ {
+ crit->DebugInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(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;
+ crit->DebugInfo->Spare[0] = 0;
+ crit->DebugInfo->Spare[1] = 0;
+ }
+ }
+ crit->LockCount = -1;
+ crit->RecursionCount = 0;
+ crit->OwningThread = 0;
+ crit->LockSemaphore = 0;
+ crit->SpinCount = (NtCurrentPeb()->NumberOfProcessors > 1) ? spincount : 0;
+ 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
+ * RtlInitializeCriticalSection(), RtlInitializeCriticalSectionAndSpinCount(),
+ * RtlDeleteCriticalSection(), RtlEnterCriticalSection(),
+ * RtlLeaveCriticalSection(), RtlTryEnterCriticalSection()
+ */
+ULONG STDCALL RtlSetCriticalSectionSpinCount( PCRITICAL_SECTION crit, ULONG spincount )
+{
+ ULONG oldspincount = crit->SpinCount;
+ crit->SpinCount = (NtCurrentPeb()->NumberOfProcessors > 1) ? spincount : 0;
+ return oldspincount;
+}
-/*
- * @implemented
+/***********************************************************************
+ * RtlDeleteCriticalSection (NTDLL.@)
+ *
+ * Frees the resources used by a critical section.
+ *
+ * PARAMS
+ * crit [I/O] Critical section to free
+ *
+ * RETURNS
+ * STATUS_SUCCESS.
+ *
+ * SEE
+ * RtlInitializeCriticalSection(), RtlInitializeCriticalSectionAndSpinCount(),
+ * RtlDeleteCriticalSection(), RtlEnterCriticalSection(),
+ * RtlLeaveCriticalSection(), RtlTryEnterCriticalSection()
*/
-NTSTATUS STDCALL
-RtlInitializeCriticalSection(PCRITICAL_SECTION CriticalSection)
+NTSTATUS STDCALL RtlDeleteCriticalSection( PCRITICAL_SECTION crit )
{
- return RtlInitializeCriticalSectionAndSpinCount (CriticalSection,
- 0);
+ crit->LockCount = -1;
+ crit->RecursionCount = 0;
+ crit->OwningThread = (HANDLE)0;
+ if (crit->LockSemaphore)
+ NtClose( crit->LockSemaphore );
+ crit->LockSemaphore = 0;
+ if (crit->DebugInfo)
+ {
+ /* only free the ones we made in here */
+ if (!crit->DebugInfo->Spare[1])
+ {
+ RtlFreeHeap( RtlGetProcessHeap(), 0, crit->DebugInfo );
+ crit->DebugInfo = NULL;
+ }
+ }
+ return STATUS_SUCCESS;
}
-/*
- * @implemented
+/***********************************************************************
+ * 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
+ * RtlInitializeCriticalSection(), RtlInitializeCriticalSectionAndSpinCount(),
+ * RtlDeleteCriticalSection(), RtlEnterCriticalSection(),
+ * RtlLeaveCriticalSection(), RtlTryEnterCriticalSection()
*/
-VOID STDCALL
-RtlLeaveCriticalSection(PCRITICAL_SECTION CriticalSection)
+NTSTATUS STDCALL RtlpWaitForCriticalSection( PCRITICAL_SECTION crit )
{
- HANDLE Thread = (HANDLE)NtCurrentTeb()->Cid.UniqueThread;
-
- if (CriticalSection->OwningThread != Thread)
- {
- DPRINT1("Freeing critical section not owned\n");
- }
-
- CriticalSection->RecursionCount--;
- if (CriticalSection->RecursionCount > 0)
- {
- InterlockedDecrement(&CriticalSection->LockCount);
- return;
- }
- CriticalSection->OwningThread = 0;
- if (InterlockedDecrement(&CriticalSection->LockCount) >= 0)
- {
- NTSTATUS Status;
-
- Status = NtReleaseSemaphore(CriticalSection->LockSemaphore, 1, NULL);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("Failed to release semaphore (Status %x)\n",
- Status);
- }
- }
+ for (;;)
+ {
+ EXCEPTION_RECORD rec;
+ HANDLE sem = get_semaphore( crit );
+ LARGE_INTEGER time;
+ NTSTATUS status;
+
+ time.QuadPart = -5000 * 10000; /* 5 seconds */
+ status = NtWaitForSingleObject( sem, FALSE, &time );
+ if ( status == STATUS_TIMEOUT )
+ {
+ const char *name = NULL;
+ if (crit->DebugInfo) name = (char *)crit->DebugInfo->Spare[1];
+ if (!name) name = "?";
+ DPRINT1( "section %p %s wait timed out in thread %04lx, blocked by %04lx, retrying (60 sec)\n",
+ crit, name, RtlGetCurrentThreadId(), (DWORD)crit->OwningThread );
+ time.QuadPart = -60000 * 10000;
+ status = NtWaitForSingleObject( sem, FALSE, &time );
+ if ( status == STATUS_TIMEOUT /*&& TRACE_ON(relay)*/ )
+ {
+ DPRINT1( "section %p %s wait timed out in thread %04lx, blocked by %04lx, retrying (5 min)\n",
+ crit, name, RtlGetCurrentThreadId(), (DWORD) crit->OwningThread );
+ time.QuadPart = -300000 * (ULONGLONG)10000;
+ status = NtWaitForSingleObject( sem, FALSE, &time );
+ }
+ }
+ if (status == STATUS_WAIT_0) return STATUS_SUCCESS;
+
+ /* Throw exception only for Wine internal locks */
+ if ((!crit->DebugInfo) || (!crit->DebugInfo->Spare[1])) continue;
+
+ rec.ExceptionCode = STATUS_POSSIBLE_DEADLOCK;
+ rec.ExceptionFlags = 0;
+ rec.ExceptionRecord = NULL;
+ rec.ExceptionAddress = RtlRaiseException; /* sic */
+ rec.NumberParameters = 1;
+ rec.ExceptionInformation[0] = (DWORD)crit;
+ RtlRaiseException( &rec );
+ }
}
-/*
- * @implemented
+
+/***********************************************************************
+ * 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
+ * RtlInitializeCriticalSection(), RtlInitializeCriticalSectionAndSpinCount(),
+ * RtlDeleteCriticalSection(), RtlEnterCriticalSection(),
+ * RtlLeaveCriticalSection(), RtlTryEnterCriticalSection()
*/
-BOOLEAN STDCALL
-RtlTryEnterCriticalSection(PCRITICAL_SECTION CriticalSection)
+NTSTATUS STDCALL RtlpUnWaitCriticalSection( PCRITICAL_SECTION crit )
{
- if (InterlockedCompareExchange((PVOID*)&CriticalSection->LockCount,
- (PVOID)0, (PVOID)-1 ) == (PVOID)-1)
- {
- CriticalSection->OwningThread =
- (HANDLE) NtCurrentTeb()->Cid.UniqueThread;
- CriticalSection->RecursionCount = 1;
- return TRUE;
- }
- if (CriticalSection->OwningThread ==
- (HANDLE)NtCurrentTeb()->Cid.UniqueThread)
- {
- InterlockedIncrement(&CriticalSection->LockCount);
- CriticalSection->RecursionCount++;
- return TRUE;
- }
- return FALSE;
+ HANDLE sem = get_semaphore( crit );
+ NTSTATUS res = NtReleaseSemaphore( sem, 1, NULL );
+ if (!NT_SUCCESS(res)) RtlRaiseStatus( res );
+ return res;
}
-/*
- * @implemented
+/***********************************************************************
+ * 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
+ * RtlInitializeCriticalSection(), RtlInitializeCriticalSectionAndSpinCount(),
+ * RtlDeleteCriticalSection(), RtlSetCriticalSectionSpinCount(),
+ * RtlLeaveCriticalSection(), RtlTryEnterCriticalSection()
*/
-NTSTATUS STDCALL
-RtlInitializeCriticalSectionAndSpinCount (PCRITICAL_SECTION CriticalSection,
- ULONG SpinCount)
+NTSTATUS STDCALL RtlEnterCriticalSection( PCRITICAL_SECTION crit )
{
- CriticalSection->LockCount = -1;
- CriticalSection->RecursionCount = 0;
- CriticalSection->OwningThread = (HANDLE)0;
-#ifdef MP
- CriticalSection->SpinCount = SpinCount;
-#else
- CriticalSection->SpinCount = 0;
-#endif
+ if (crit->SpinCount)
+ {
+ ULONG count;
- return NtCreateSemaphore (&CriticalSection->LockSemaphore,
- SEMAPHORE_ALL_ACCESS,
- NULL,
- 0,
- 1);
+ 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 == (HANDLE)RtlGetCurrentThreadId())
+ {
+ crit->RecursionCount++;
+ return STATUS_SUCCESS;
+ }
+
+ /* Now wait for it */
+ RtlpWaitForCriticalSection( crit );
+ }
+done:
+ crit->OwningThread = (HANDLE)RtlGetCurrentThreadId();
+ 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
+ * RtlInitializeCriticalSection(), RtlInitializeCriticalSectionAndSpinCount(),
+ * RtlDeleteCriticalSection(), RtlEnterCriticalSection(),
+ * RtlLeaveCriticalSection(), RtlSetCriticalSectionSpinCount()
+ */
+BOOLEAN STDCALL RtlTryEnterCriticalSection( PCRITICAL_SECTION crit )
+{
+ BOOL ret = FALSE;
+ if (InterlockedCompareExchange(&crit->LockCount, 0L, -1 ) == -1)
+ {
+ crit->OwningThread = (HANDLE)RtlGetCurrentThreadId();
+ crit->RecursionCount = 1;
+ ret = TRUE;
+ }
+ else if (crit->OwningThread == (HANDLE)RtlGetCurrentThreadId())
+ {
+ InterlockedIncrement( &crit->LockCount );
+ crit->RecursionCount++;
+ ret = TRUE;
+ }
+ return ret;
+}
+
+
+/***********************************************************************
+ * RtlLeaveCriticalSection (NTDLL.@)
+ *
+ * Leaves a critical section.
+ *
+ * PARAMS
+ * crit [I/O] Critical section to leave.
+ *
+ * RETURNS
+ * STATUS_SUCCESS.
+ *
+ * SEE
+ * RtlInitializeCriticalSection(), RtlInitializeCriticalSectionAndSpinCount(),
+ * RtlDeleteCriticalSection(), RtlEnterCriticalSection(),
+ * RtlSetCriticalSectionSpinCount(), RtlTryEnterCriticalSection()
+ */
+NTSTATUS STDCALL RtlLeaveCriticalSection( PCRITICAL_SECTION crit )
+{
+ if (crit->OwningThread != RtlGetCurrentThreadId())
+ {
+ DPRINT1("Freeing critical section not owned\n");
+ }
+
+ if (--crit->RecursionCount) InterlockedDecrement( &crit->LockCount );
+ else
+ {
+ crit->OwningThread = 0;
+ if (InterlockedDecrement( &crit->LockCount ) >= 0)
+ {
+ /* someone is waiting */
+ RtlpUnWaitCriticalSection( crit );
+ }
+ }
+ return STATUS_SUCCESS;
+}
+
+
/* EOF */