Moved critical section implementation to ntdll.

This commit is contained in:
Alexandre Julliard 2000-09-29 00:31:23 +00:00
parent 15bfcd0398
commit baa15566a0
7 changed files with 315 additions and 164 deletions

View File

@ -201,7 +201,7 @@ import ntdll.dll
182 stdcall DefineDosDeviceA(long str str) DefineDosDeviceA
183 stub DefineDosDeviceW
184 stdcall DeleteAtom(long) DeleteAtom
185 stdcall DeleteCriticalSection(ptr) DeleteCriticalSection
185 forward DeleteCriticalSection ntdll.RtlDeleteCriticalSection
186 stdcall DeleteFileA(str) DeleteFileA
187 stdcall DeleteFileW(wstr) DeleteFileW
188 stdcall DeviceIoControl(long long ptr long ptr long ptr ptr) DeviceIoControl
@ -211,7 +211,7 @@ import ntdll.dll
192 stdcall DuplicateHandle(long long long ptr long long long) DuplicateHandle
193 stub EndUpdateResourceA
194 stub EndUpdateResourceW
195 stdcall EnterCriticalSection(ptr) EnterCriticalSection
195 forward EnterCriticalSection ntdll.RtlEnterCriticalSection
196 stdcall EnumCalendarInfoA(ptr long long long) EnumCalendarInfoA
197 stub EnumCalendarInfoW
198 stdcall EnumDateFormatsA(ptr long long) EnumDateFormatsA
@ -510,7 +510,7 @@ import ntdll.dll
491 register K32Thk1632Prolog() K32Thk1632Prolog
492 stdcall LCMapStringA(long long str long ptr long) LCMapStringA
493 stdcall LCMapStringW(long long wstr long ptr long) LCMapStringW
494 stdcall LeaveCriticalSection(ptr) LeaveCriticalSection
494 forward LeaveCriticalSection ntdll.RtlLeaveCriticalSection
495 stdcall LoadLibraryA(str) LoadLibraryA
496 stdcall LoadLibraryExA( str long long) LoadLibraryExA
497 stdcall LoadLibraryExW(wstr long long) LoadLibraryExW
@ -914,7 +914,7 @@ import ntdll.dll
895 stub SignalObjectAndWait
896 stub SwitchToFiber
897 stub SwitchToThread
898 stdcall TryEnterCriticalSection(ptr) TryEnterCriticalSection
898 forward TryEnterCriticalSection ntdll.RtlTryEnterCriticalSection
899 stdcall VirtualAllocEx(long ptr long long long) VirtualAllocEx
900 stub VirtualFreeEx
901 stub WriteFileGather

View File

@ -8,6 +8,7 @@ MODULE = ntdll
SPEC_SRCS = ntdll.spec
C_SRCS = \
critsection.c \
exception.c \
error.c \
file.c \
@ -29,5 +30,7 @@ all: $(MODULE).o
@MAKE_RULES@
### Dependencies:
$(MODULE).o: $(OBJS) Makefile.in $(TOPSRCDIR)/Make.rules.in
$(LDCOMBINE) $(OBJS) -o $@
### Dependencies:

272
dlls/ntdll/critsection.c Normal file
View File

@ -0,0 +1,272 @@
/*
* Win32 critical sections
*
* Copyright 1998 Alexandre Julliard
*/
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <sys/types.h>
#include "winerror.h"
#include "ntddk.h"
#include "debugtools.h"
DEFAULT_DEBUG_CHANNEL(ntdll);
DECLARE_DEBUG_CHANNEL(relay);
/* Define the atomic exchange/inc/dec functions.
* These are available in kernel32.dll already,
* but we don't want to import kernel32 from ntdll.
*/
#ifdef __i386__
# ifdef __GNUC__
inline static PVOID interlocked_cmpxchg( PVOID *dest, PVOID xchg, PVOID compare )
{
PVOID ret;
__asm__ __volatile__( "lock; cmpxchgl %2,(%1)"
: "=a" (ret) : "r" (dest), "r" (xchg), "0" (compare) : "memory" );
return ret;
}
inline static LONG interlocked_inc( PLONG dest )
{
LONG ret;
__asm__ __volatile__( "lock; xaddl %0,(%1)"
: "=r" (ret) : "r" (dest), "0" (1) : "memory" );
return ret + 1;
}
inline static LONG interlocked_dec( PLONG dest )
{
LONG ret;
__asm__ __volatile__( "lock; xaddl %0,(%1)"
: "=r" (ret) : "r" (dest), "0" (-1) : "memory" );
return ret - 1;
}
# else /* __GNUC__ */
PVOID WINAPI interlocked_cmpxchg( PVOID *dest, PVOID xchg, PVOID compare );
__ASM_GLOBAL_FUNC(interlocked_cmpxchg,
"movl 12(%esp),%eax\n\t"
"movl 8(%esp),%ecx\n\t"
"movl 4(%esp),%edx\n\t"
"lock; cmpxchgl %ecx,(%edx)\n\t"
"ret $12");
LONG WINAPI interlocked_inc( PLONG dest );
__ASM_GLOBAL_FUNC(interlocked_inc,
"movl 4(%esp),%edx\n\t"
"movl $1,%eax\n\t"
"lock; xaddl %eax,(%edx)\n\t"
"incl %eax\n\t"
"ret $4");
LONG WINAPI interlocked_dec( PLONG dest );
__ASM_GLOBAL_FUNC(interlocked_dec,
"movl 4(%esp),%edx\n\t"
"movl $-1,%eax\n\t"
"lock; xaddl %eax,(%edx)\n\t"
"decl %eax\n\t"
"ret $4");
# endif /* __GNUC__ */
#elif defined(__sparc__) && defined(__sun__)
/*
* As the earlier Sparc processors lack necessary atomic instructions,
* I'm simply falling back to the library-provided _lwp_mutex routines
* to ensure mutual exclusion in a way appropriate for the current
* architecture.
*
* FIXME: If we have the compare-and-swap instruction (Sparc v9 and above)
* we could use this to speed up the Interlocked operations ...
*/
#include <synch.h>
static lwp_mutex_t interlocked_mutex = DEFAULTMUTEX;
static PVOID interlocked_cmpxchg( PVOID *dest, PVOID xchg, PVOID compare )
{
_lwp_mutex_lock( &interlocked_mutex );
if ( *dest == compare )
*dest = xchg;
else
compare = *dest;
_lwp_mutex_unlock( &interlocked_mutex );
return compare;
}
static LONG interlocked_inc( PLONG dest )
{
LONG retv;
_lwp_mutex_lock( &interlocked_mutex );
retv = ++*dest;
_lwp_mutex_unlock( &interlocked_mutex );
return retv;
}
static LONG interlocked_dec( PLONG dest )
{
LONG retv;
_lwp_mutex_lock( &interlocked_mutex );
retv = --*dest;
_lwp_mutex_unlock( &interlocked_mutex );
return retv;
}
#else
# error You must implement the interlocked* functions for your CPU
#endif
/***********************************************************************
* 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 = (HANDLE)InterlockedCompareExchange( (PVOID *)&crit->LockSemaphore,
(PVOID)sem, 0 )))
ret = sem;
else
NtClose(sem); /* somebody beat us to it */
}
return ret;
}
/***********************************************************************
* RtlInitializeCriticalSection (NTDLL.@)
*/
NTSTATUS WINAPI RtlInitializeCriticalSection( RTL_CRITICAL_SECTION *crit )
{
crit->LockCount = -1;
crit->RecursionCount = 0;
crit->OwningThread = 0;
crit->LockSemaphore = 0;
return STATUS_SUCCESS;
}
/***********************************************************************
* RtlDeleteCriticalSection (NTDLL.@)
*/
NTSTATUS WINAPI RtlDeleteCriticalSection( RTL_CRITICAL_SECTION *crit )
{
crit->LockCount = -1;
crit->RecursionCount = 0;
crit->OwningThread = 0;
if (crit->LockSemaphore) NtClose( crit->LockSemaphore );
crit->LockSemaphore = 0;
return STATUS_SUCCESS;
}
/***********************************************************************
* RtlpWaitForCriticalSection (NTDLL.@)
*/
NTSTATUS WINAPI RtlpWaitForCriticalSection( RTL_CRITICAL_SECTION *crit )
{
for (;;)
{
EXCEPTION_RECORD rec;
HANDLE sem = get_semaphore( crit );
DWORD res = WaitForSingleObject( sem, 5000L );
if ( res == WAIT_TIMEOUT )
{
ERR("Critical section %p wait timed out, retrying (60 sec)\n", crit );
res = WaitForSingleObject( sem, 60000L );
if ( res == WAIT_TIMEOUT && TRACE_ON(relay) )
{
ERR("Critical section %p wait timed out, retrying (5 min)\n", crit );
res = WaitForSingleObject( sem, 300000L );
}
}
if (res == STATUS_WAIT_0) return STATUS_SUCCESS;
rec.ExceptionCode = EXCEPTION_CRITICAL_SECTION_WAIT;
rec.ExceptionFlags = 0;
rec.ExceptionRecord = NULL;
rec.ExceptionAddress = RtlRaiseException; /* sic */
rec.NumberParameters = 1;
rec.ExceptionInformation[0] = (DWORD)crit;
RtlRaiseException( &rec );
}
}
/***********************************************************************
* RtlpUnWaitCriticalSection (NTDLL.@)
*/
NTSTATUS WINAPI RtlpUnWaitCriticalSection( RTL_CRITICAL_SECTION *crit )
{
HANDLE sem = get_semaphore( crit );
NTSTATUS res = NtReleaseSemaphore( sem, 1, NULL );
if (res) RtlRaiseStatus( res );
return res;
}
/***********************************************************************
* RtlEnterCriticalSection (NTDLL.@)
*/
NTSTATUS WINAPI RtlEnterCriticalSection( RTL_CRITICAL_SECTION *crit )
{
if (interlocked_inc( &crit->LockCount ))
{
if (crit->OwningThread == GetCurrentThreadId())
{
crit->RecursionCount++;
return STATUS_SUCCESS;
}
/* Now wait for it */
RtlpWaitForCriticalSection( crit );
}
crit->OwningThread = GetCurrentThreadId();
crit->RecursionCount = 1;
return STATUS_SUCCESS;
}
/***********************************************************************
* RtlTryEnterCriticalSection (NTDLL.@)
*/
BOOL WINAPI RtlTryEnterCriticalSection( RTL_CRITICAL_SECTION *crit )
{
BOOL ret = FALSE;
if (interlocked_cmpxchg( (PVOID *)&crit->LockCount, (PVOID)0L, (PVOID)-1L ) == (PVOID)-1L)
{
crit->OwningThread = GetCurrentThreadId();
crit->RecursionCount = 1;
ret = TRUE;
}
else if (crit->OwningThread == GetCurrentThreadId())
{
interlocked_inc( &crit->LockCount );
crit->RecursionCount++;
ret = TRUE;
}
return ret;
}
/***********************************************************************
* RtlLeaveCriticalSection (NTDLL.@)
*/
NTSTATUS WINAPI RtlLeaveCriticalSection( RTL_CRITICAL_SECTION *crit )
{
if (--crit->RecursionCount) interlocked_dec( &crit->LockCount );
else
{
crit->OwningThread = 0;
if (interlocked_dec( &crit->LockCount ) >= 0)
{
/* someone is waiting */
RtlpUnWaitCriticalSection( crit );
}
}
return STATUS_SUCCESS;
}

View File

@ -331,7 +331,7 @@ type win32
@ stub RtlDecompressFragment
@ stub RtlDelete
@ stub RtlDeleteAce
@ stdcall RtlDeleteCriticalSection(ptr) DeleteCriticalSection
@ stdcall RtlDeleteCriticalSection(ptr) RtlDeleteCriticalSection
@ stub RtlDeleteElementGenericTable
@ stub RtlDeleteRegistryValue
@ stdcall RtlDeleteResource(ptr) RtlDeleteResource
@ -348,7 +348,7 @@ type win32
@ stub RtlEnlargedIntegerMultiply
@ stub RtlEnlargedUnsignedDivide
@ stub RtlEnlargedUnsignedMultiply
@ stdcall RtlEnterCriticalSection(ptr) EnterCriticalSection
@ stdcall RtlEnterCriticalSection(ptr) RtlEnterCriticalSection
@ stub RtlEnumProcessHeaps
@ stub RtlEnumerateGenericTable
@ stub RtlEnumerateGenericTableWithoutSplaying
@ -410,7 +410,7 @@ type win32
@ stdcall RtlInitUnicodeString(ptr wstr) RtlInitUnicodeString
@ stdcall RtlInitializeBitMap(long long long) RtlInitializeBitMap
@ stub RtlInitializeContext
@ stdcall RtlInitializeCriticalSection(ptr) InitializeCriticalSection
@ stdcall RtlInitializeCriticalSection(ptr) RtlInitializeCriticalSection
@ stdcall RtlInitializeGenericTable() RtlInitializeGenericTable
@ stub RtlInitializeRXact
@ stdcall RtlInitializeResource(ptr) RtlInitializeResource
@ -430,7 +430,7 @@ type win32
@ stub RtlLargeIntegerShiftRight
@ stub RtlLargeIntegerSubtract
@ stub RtlLargeIntegerToChar
@ stdcall RtlLeaveCriticalSection(ptr) LeaveCriticalSection
@ stdcall RtlLeaveCriticalSection(ptr) RtlLeaveCriticalSection
@ stdcall RtlLengthRequiredSid(long) RtlLengthRequiredSid
@ stdcall RtlLengthSecurityDescriptor(ptr) RtlLengthSecurityDescriptor
@ stdcall RtlLengthSid(ptr) RtlLengthSid
@ -973,7 +973,7 @@ type win32
@ stub RtlIsValidHandle
@ stub RtlLookupAtomInAtomTable
@ stub RtlQueryAtomInAtomTable
@ stdcall RtlTryEnterCriticalSection(ptr) TryEnterCriticalSection
@ stdcall RtlTryEnterCriticalSection(ptr) RtlTryEnterCriticalSection
@ stub RtlEnumerateProperties
@ stub RtlSetPropertyClassId
@ stub RtlSetPropertyNames

View File

@ -918,6 +918,13 @@ NTSTATUS WINAPI NtReleaseSemaphore( IN HANDLE SemaphoreHandle,
IN ULONG ReleaseCount,
IN PULONG PreviousCount);
NTSTATUS WINAPI RtlInitializeCriticalSection( RTL_CRITICAL_SECTION *crit );
NTSTATUS WINAPI RtlDeleteCriticalSection( RTL_CRITICAL_SECTION *crit );
NTSTATUS WINAPI RtlpWaitForCriticalSection( RTL_CRITICAL_SECTION *crit );
NTSTATUS WINAPI RtlpUnWaitCriticalSection( RTL_CRITICAL_SECTION *crit );
NTSTATUS WINAPI RtlEnterCriticalSection( RTL_CRITICAL_SECTION *crit );
BOOL WINAPI RtlTryEnterCriticalSection( RTL_CRITICAL_SECTION *crit );
NTSTATUS WINAPI RtlLeaveCriticalSection( RTL_CRITICAL_SECTION *crit );
/* string functions */
extern LPSTR _strlwr( LPSTR str );

View File

@ -1206,13 +1206,25 @@ BOOL WINAPI GetVersionExW(OSVERSIONINFOW*);
/*int WinMain(HINSTANCE, HINSTANCE prev, char *cmd, int show);*/
LONG WINAPI RtlEnterCriticalSection( CRITICAL_SECTION *crit );
LONG WINAPI RtlLeaveCriticalSection( CRITICAL_SECTION *crit );
LONG WINAPI RtlDeleteCriticalSection( CRITICAL_SECTION *crit );
BOOL WINAPI RtlTryEnterCriticalSection( CRITICAL_SECTION *crit );
/* FIXME: need to use defines because we don't have proper imports yet */
#define EnterCriticalSection(crit) RtlEnterCriticalSection(crit)
#define LeaveCriticalSection(crit) RtlLeaveCriticalSection(crit)
#define DeleteCriticalSection(crit) RtlDeleteCriticalSection(crit)
#define TryEnterCriticalSection(crit) RtlTryEnterCriticalSection(crit)
#if 0
void WINAPI DeleteCriticalSection(CRITICAL_SECTION *lpCrit);
void WINAPI EnterCriticalSection(CRITICAL_SECTION *lpCrit);
BOOL WINAPI TryEnterCriticalSection(CRITICAL_SECTION *lpCrit);
void WINAPI InitializeCriticalSection(CRITICAL_SECTION *lpCrit);
void WINAPI LeaveCriticalSection(CRITICAL_SECTION *lpCrit);
#endif
void WINAPI InitializeCriticalSection(CRITICAL_SECTION *lpCrit);
void WINAPI MakeCriticalSectionGlobal(CRITICAL_SECTION *lpCrit);
BOOL WINAPI GetProcessWorkingSetSize(HANDLE,LPDWORD,LPDWORD);
BOOL WINAPI GetProcessWorkingSetSize(HANDLE,LPDWORD,LPDWORD);
DWORD WINAPI QueueUserAPC(PAPCFUNC,HANDLE,ULONG_PTR);
void WINAPI RaiseException(DWORD,DWORD,DWORD,const LPDWORD);
BOOL WINAPI SetProcessWorkingSetSize(HANDLE,DWORD,DWORD);

View File

@ -19,166 +19,23 @@ DEFAULT_DEBUG_CHANNEL(win32);
DECLARE_DEBUG_CHANNEL(relay);
/***********************************************************************
* get_semaphore
*/
static inline HANDLE get_semaphore( CRITICAL_SECTION *crit )
{
HANDLE ret = crit->LockSemaphore;
if (!ret)
{
HANDLE sem = CreateSemaphoreA( NULL, 0, 1, NULL );
if (!(ret = (HANDLE)InterlockedCompareExchange( (PVOID *)&crit->LockSemaphore,
(PVOID)sem, 0 )))
ret = sem;
else
CloseHandle(sem); /* somebody beat us to it */
}
return ret;
}
/***********************************************************************
* InitializeCriticalSection (KERNEL32.472) (NTDLL.406)
* InitializeCriticalSection (KERNEL32.472)
*/
void WINAPI InitializeCriticalSection( CRITICAL_SECTION *crit )
{
crit->LockCount = -1;
crit->RecursionCount = 0;
crit->OwningThread = 0;
crit->LockSemaphore = 0;
NTSTATUS ret = RtlInitializeCriticalSection( crit );
if (ret) RtlRaiseStatus( ret );
}
/***********************************************************************
* DeleteCriticalSection (KERNEL32.185) (NTDLL.327)
*/
void WINAPI DeleteCriticalSection( CRITICAL_SECTION *crit )
{
if (crit->RecursionCount && crit->OwningThread != GetCurrentThreadId())
ERR("Deleting owned critical section (%p)\n", crit );
crit->LockCount = -1;
crit->RecursionCount = 0;
crit->OwningThread = 0;
if (crit->LockSemaphore) CloseHandle( crit->LockSemaphore );
crit->LockSemaphore = 0;
}
/***********************************************************************
* RtlpWaitForCriticalSection (NTDLL.@)
*/
void WINAPI RtlpWaitForCriticalSection( CRITICAL_SECTION *crit )
{
for (;;)
{
EXCEPTION_RECORD rec;
HANDLE sem = get_semaphore( crit );
DWORD res = WaitForSingleObject( sem, 5000L );
if ( res == WAIT_TIMEOUT )
{
ERR("Critical section %p wait timed out, retrying (60 sec)\n", crit );
res = WaitForSingleObject( sem, 60000L );
if ( res == WAIT_TIMEOUT && TRACE_ON(relay) )
{
ERR("Critical section %p wait timed out, retrying (5 min)\n", crit );
res = WaitForSingleObject( sem, 300000L );
}
}
if (res == STATUS_WAIT_0) break;
rec.ExceptionCode = EXCEPTION_CRITICAL_SECTION_WAIT;
rec.ExceptionFlags = 0;
rec.ExceptionRecord = NULL;
rec.ExceptionAddress = RtlRaiseException; /* sic */
rec.NumberParameters = 1;
rec.ExceptionInformation[0] = (DWORD)crit;
RtlRaiseException( &rec );
}
}
/***********************************************************************
* RtlpUnWaitCriticalSection (NTDLL.@)
*/
void WINAPI RtlpUnWaitCriticalSection( CRITICAL_SECTION *crit )
{
HANDLE sem = get_semaphore( crit );
ReleaseSemaphore( sem, 1, NULL );
}
/***********************************************************************
* EnterCriticalSection (KERNEL32.195) (NTDLL.344)
*/
void WINAPI EnterCriticalSection( CRITICAL_SECTION *crit )
{
if (InterlockedIncrement( &crit->LockCount ))
{
if (crit->OwningThread == GetCurrentThreadId())
{
crit->RecursionCount++;
return;
}
/* Now wait for it */
RtlpWaitForCriticalSection( crit );
}
crit->OwningThread = GetCurrentThreadId();
crit->RecursionCount = 1;
}
/***********************************************************************
* TryEnterCriticalSection (KERNEL32.898) (NTDLL.969)
*/
BOOL WINAPI TryEnterCriticalSection( CRITICAL_SECTION *crit )
{
BOOL ret = FALSE;
if (InterlockedCompareExchange( (PVOID *)&crit->LockCount,
(PVOID)0L, (PVOID)-1L ) == (PVOID)-1L)
{
crit->OwningThread = GetCurrentThreadId();
crit->RecursionCount = 1;
ret = TRUE;
}
else if (crit->OwningThread == GetCurrentThreadId())
{
InterlockedIncrement( &crit->LockCount );
crit->RecursionCount++;
ret = TRUE;
}
return ret;
}
/***********************************************************************
* LeaveCriticalSection (KERNEL32.494) (NTDLL.426)
*/
void WINAPI LeaveCriticalSection( CRITICAL_SECTION *crit )
{
if (crit->OwningThread != GetCurrentThreadId()) return;
if (--crit->RecursionCount)
{
InterlockedDecrement( &crit->LockCount );
return;
}
crit->OwningThread = 0;
if (InterlockedDecrement( &crit->LockCount ) >= 0)
{
/* Someone is waiting */
RtlpUnWaitCriticalSection( crit );
}
}
/***********************************************************************
* MakeCriticalSectionGlobal (KERNEL32.515)
*/
void WINAPI MakeCriticalSectionGlobal( CRITICAL_SECTION *crit )
{
crit->LockSemaphore = ConvertToGlobalHandle( get_semaphore( crit ) );
/* let's assume that only one thread at a time will try to do this */
HANDLE sem = crit->LockSemaphore;
if (!sem) sem = CreateSemaphoreA( NULL, 0, 1, NULL );
crit->LockSemaphore = ConvertToGlobalHandle( sem );
}
@ -188,7 +45,7 @@ void WINAPI MakeCriticalSectionGlobal( CRITICAL_SECTION *crit )
void WINAPI ReinitializeCriticalSection( CRITICAL_SECTION *crit )
{
if ( !crit->LockSemaphore )
InitializeCriticalSection( crit );
RtlInitializeCriticalSection( crit );
}
@ -197,7 +54,7 @@ void WINAPI ReinitializeCriticalSection( CRITICAL_SECTION *crit )
*/
void WINAPI UninitializeCriticalSection( CRITICAL_SECTION *crit )
{
DeleteCriticalSection( crit );
RtlDeleteCriticalSection( crit );
}
#ifdef __i386__