Implemented resource (multiple-reader-single-writer) lock

svn path=/trunk/; revision=1913
This commit is contained in:
Eric Kohl 2001-05-24 11:28:54 +00:00
parent 56ab538abe
commit ca61cc2444
5 changed files with 400 additions and 21 deletions

View file

@ -1,4 +1,4 @@
/* $Id: rtl.h,v 1.25 2001/05/07 22:03:26 chorns Exp $
/* $Id: rtl.h,v 1.26 2001/05/24 11:27:10 ekohl Exp $
*
*/
@ -37,6 +37,18 @@ typedef struct _RTL_PROCESS_INFO
SECTION_IMAGE_INFORMATION ImageInfo;
} RTL_PROCESS_INFO, *PRTL_PROCESS_INFO;
typedef struct _RTL_RESOURCE
{
CRITICAL_SECTION Lock;
HANDLE SharedSemaphore;
ULONG SharedWaiters;
HANDLE ExclusiveSemaphore;
ULONG ExclusiveWaiters;
LONG NumberActive;
HANDLE OwningThread;
ULONG TimeoutBoost; /* ?? */
PVOID DebugInfo; /* ?? */
} RTL_RESOURCE, *PRTL_RESOURCE;
#define HEAP_BASE (0xa0000000)
@ -335,6 +347,59 @@ RtlRaiseStatus (
IN NTSTATUS Status
);
/* resource functions */
BOOLEAN
STDCALL
RtlAcquireResourceExclusive (
IN PRTL_RESOURCE Resource,
IN BOOLEAN Wait
);
BOOLEAN
STDCALL
RtlAcquireResourceShared (
IN PRTL_RESOURCE Resource,
IN BOOLEAN Wait
);
VOID
STDCALL
RtlConvertExclusiveToShared (
IN PRTL_RESOURCE Resource
);
VOID
STDCALL
RtlConvertSharedToExclusive (
IN PRTL_RESOURCE Resource
);
VOID
STDCALL
RtlDeleteResource (
IN PRTL_RESOURCE Resource
);
VOID
STDCALL
RtlDumpResource (
IN PRTL_RESOURCE Resource
);
VOID
STDCALL
RtlInitializeResource (
IN PRTL_RESOURCE Resource
);
VOID
STDCALL
RtlReleaseResource (
IN PRTL_RESOURCE Resource
);
#endif /* __INCLUDE_NTDLL_RTL_H */
/* EOF */

View file

@ -1,4 +1,4 @@
; $Id: ntdll.def,v 1.70 2001/05/02 22:23:47 ekohl Exp $
; $Id: ntdll.def,v 1.71 2001/05/24 11:28:18 ekohl Exp $
;
; ReactOS Operating System
;
@ -271,8 +271,8 @@ NtYieldExecution@0
;RtlAbortRXact
RtlAbsoluteToSelfRelativeSD@12
RtlAcquirePebLock@0
;RtlAcqureResourceExclusive
;RtlAcqureResourceShared
RtlAcquireResourceExclusive@8
RtlAcquireResourceShared@8
RtlAddAccessAllowedAce@16
RtlAddAccessDeniedAce@16
RtlAddAce@20
@ -312,9 +312,9 @@ RtlCompareString@12
RtlCompareUnicodeString@12
;RtlCompressBuffer
;RtlConsoleMultiByteToUnicodeN
;RtlConvertExclusiveToShared
RtlConvertExclusiveToShared@4
RtlConvertLongToLargeInteger@4
;RtlConvertSharedToExclusive
RtlConvertSharedToExclusive@4
RtlConvertSidToUnicodeString@12
;RtlConvertUiListToApiList
RtlConvertUlongToLargeInteger@4
@ -353,7 +353,7 @@ RtlDeleteCriticalSection@4
;RtlDeleteElementGenericTable
;RtlDeleteNoSplay
RtlDeleteRegistryValue@12
;RtlDeleteResource
RtlDeleteResource@4
;RtlDeleteSecurityObject
;RtlDestroyAtomTable
RtlDestroyEnvironment@4
@ -366,7 +366,7 @@ RtlDoesFileExists_U@4
RtlDosPathNameToNtPathName_U@16
RtlDosSearchPath_U@24
RtlDowncaseUnicodeString@12
;RtlDumpResource
RtlDumpResource@4
;RtlEmptyAtomTable
RtlEnlargedIntegerMultiply@8
RtlEnlargedUnsignedDivide@16
@ -446,7 +446,7 @@ RtlInitializeCriticalSection@4
;RtlInitializeGenericTable
;RtlInitializeHandleTable
;RtlInitializeRXact
;RtlInitializeResource
RtlInitializeResource@4
RtlInitializeSid@12
;RtlInsertElementGenericTable
RtlIntegerToChar@16
@ -518,7 +518,7 @@ RtlReAllocateHeap@16
;RtlRealPredecessor
;RtlRealSuccessor
RtlReleasePebLock@0
;RtlReleaseResource
RtlReleaseResource@4
;RtlRemoteCall
;RtlResetRtlTranslations
;RtlRunDecodeUnicodeString

View file

@ -1,4 +1,4 @@
; $Id: ntdll.edf,v 1.59 2001/05/02 22:23:47 ekohl Exp $
; $Id: ntdll.edf,v 1.60 2001/05/24 11:28:18 ekohl Exp $
;
; ReactOS Operating System
;
@ -271,8 +271,8 @@ NtYieldExecution=NtYieldExecution@0
;RtlAbortRXact
RtlAbsoluteToSelfRelativeSD=RtlAbsoluteToSelfRelativeSD@12
RtlAcquirePebLock=RtlAcquirePebLock@0
;RtlAcqureResourceExclusive
;RtlAcqureResourceShared
RtlAcquireResourceExclusive=RtlAcquireResourceExclusive@8
RtlAcquireResourceShared=RtlAcquireResourceShared@8
RtlAddAccessAllowedAce=RtlAddAccessAllowedAce@16
RtlAddAccessDeniedAce=RtlAddAccessDeniedAce@16
RtlAddAce=RtlAddAce@20
@ -312,9 +312,9 @@ RtlCompareString=RtlCompareString@12
RtlCompareUnicodeString=RtlCompareUnicodeString@12
;RtlCompressBuffer
;RtlConsoleMultiByteToUnicodeN
;RtlConvertExclusiveToShared
RtlConvertExclusiveToShared=RtlConvertExclusiveToShared@4
RtlConvertLongToLargeInteger=RtlConvertLongToLargeInteger@4
;RtlConvertSharedToExclusive
RtlConvertSharedToExclusive=RtlConvertSharedToExclusive@4
RtlConvertSidToUnicodeString=RtlConvertSidToUnicodeString@12
;RtlConvertUiListToApiList
RtlConvertUlongToLargeInteger=RtlConvertUlongToLargeInteger@4
@ -353,7 +353,7 @@ RtlDeleteCriticalSection=RtlDeleteCriticalSection@4
;RtlDeleteElementGenericTable
;RtlDeleteNoSplay
RtlDeleteRegistryValue=RtlDeleteRegistryValue@12
;RtlDeleteResource
RtlDeleteResource=RtlDeleteResource@4
;RtlDeleteSecurityObject
;RtlDestroyAtomTable
RtlDestroyEnvironment=RtlDestroyEnvironment@4
@ -366,7 +366,7 @@ RtlDoesFileExists_U=RtlDoesFileExists_U@4
RtlDosPathNameToNtPathName_U=RtlDosPathNameToNtPathName_U@16
RtlDosSearchPath_U=RtlDosSearchPath_U@24
RtlDowncaseUnicodeString=RtlDowncaseUnicodeString@12
;RtlDumpResource
RtlDumpResource=RtlDumpResource@4
;RtlEmptyAtomTable
RtlEnlargedIntegerMultiply=RtlEnlargedIntegerMultiply@8
RtlEnlargedUnsignedDivide=RtlEnlargedUnsignedDivide@16
@ -445,7 +445,7 @@ RtlInitializeCriticalSection=RtlInitializeCriticalSection@4
;RtlInitializeGenericTable
;RtlInitializeHandleTable
;RtlInitializeRXact
;RtlInitializeResource
RtlInitializeResource=RtlInitializeResource@4
RtlInitializeSid=RtlInitializeSid@12
;RtlInsertElementGenericTable
RtlIntegerToChar=RtlIntegerToChar@16
@ -517,7 +517,7 @@ RtlReAllocateHeap=RtlReAllocateHeap@16
;RtlRealPredecessor
;RtlRealSuccessor
RtlReleasePebLock=RtlReleasePebLock@0
;RtlReleaseResource
RtlReleaseResource=RtlReleaseResource@4
;RtlRemoteCall
;RtlResetRtlTranslations
;RtlRunDecodeUnicodeString
@ -822,7 +822,18 @@ __isascii
__iscsym
__iscsymf
__toascii
;_alldiv
;_allmul
;_alloca_probe
;_allrem
;_allshl
;_allshr
_atoi64
;_aulldiv
;_aullrem
;_aullshr
;_chkstk
;_fltused
_ftol
_i64toa
_i64tow
@ -886,6 +897,7 @@ qsort
sin
sprintf
sqrt
;sscanf
strcat
strchr
strcmp

View file

@ -1,4 +1,4 @@
# $Id: makefile,v 1.58 2001/01/21 00:07:51 phreak Exp $
# $Id: makefile,v 1.59 2001/05/24 11:28:54 ekohl Exp $
#
# ReactOS Operating System
#
@ -24,7 +24,7 @@ RTL_OBJECTS = rtl/critical.o rtl/error.o rtl/heap.o rtl/largeint.o \
rtl/thread.o rtl/unicode.o rtl/env.o rtl/path.o rtl/ppb.o \
rtl/bitmap.o rtl/time.o rtl/acl.o rtl/sid.o rtl/image.o \
rtl/access.o rtl/apc.o rtl/callback.o rtl/luid.o rtl/misc.o \
rtl/registry.o rtl/exception.o rtl/intrlck.o
rtl/registry.o rtl/exception.o rtl/intrlck.o rtl/resource.o
STDIO_OBJECTS = stdio/sprintf.o stdio/swprintf.o

View file

@ -0,0 +1,302 @@
/* $Id: resource.c,v 1.1 2001/05/24 11:28:00 ekohl Exp $
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries
* FILE: lib/ntdll/rtl/resource.c
* PURPOSE: Resource (multiple-reader-single-writer lock) functions
* PROGRAMMER:
* UPDATE HISTORY:
* Created 24/05/2001
*
* NOTES: Partially take from Wine:
* Copyright 1996-1998 Marcus Meissner
* 1999 Alex Korobka
*/
/*
* xxxResource() functions implement multiple-reader-single-writer lock.
* The code is based on information published in WDJ January 1999 issue.
*/
#include <ddk/ntddk.h>
#include <ntdll/rtl.h>
#include <ntos/synch.h>
#define NDEBUG
#include <ntdll/ntdll.h>
/* FUNCTIONS ****************************************************************/
VOID STDCALL
RtlInitializeResource(PRTL_RESOURCE Resource)
{
NTSTATUS Status;
Status = RtlInitializeCriticalSection(&Resource->Lock);
if (!NT_SUCCESS(Status))
{
RtlRaiseStatus(Status);
}
Status = NtCreateSemaphore(&Resource->SharedSemaphore,
SEMAPHORE_ALL_ACCESS,
NULL,
0,
65535);
if (!NT_SUCCESS(Status))
{
RtlRaiseStatus(Status);
}
Resource->SharedWaiters = 0;
Status = NtCreateSemaphore(&Resource->ExclusiveSemaphore,
SEMAPHORE_ALL_ACCESS,
NULL,
0,
65535);
if (!NT_SUCCESS(Status))
{
RtlRaiseStatus(Status);
}
Resource->ExclusiveWaiters = 0;
Resource->NumberActive = 0;
Resource->OwningThread = NULL;
Resource->TimeoutBoost = 0; /* no info on this one, default value is 0 */
}
VOID STDCALL
RtlDeleteResource(PRTL_RESOURCE Resource)
{
RtlDeleteCriticalSection(&Resource->Lock);
NtClose(Resource->ExclusiveSemaphore);
NtClose(Resource->SharedSemaphore);
Resource->OwningThread = NULL;
Resource->ExclusiveWaiters = 0;
Resource->SharedWaiters = 0;
Resource->NumberActive = 0;
}
BOOLEAN STDCALL
RtlAcquireResourceExclusive(PRTL_RESOURCE Resource,
BOOLEAN Wait)
{
NTSTATUS Status;
BOOLEAN retVal = FALSE;
start:
RtlEnterCriticalSection(&Resource->Lock);
if (Resource->NumberActive == 0) /* lock is free */
{
Resource->NumberActive = -1;
retVal = TRUE;
}
else if (Resource->NumberActive < 0) /* exclusive lock in progress */
{
if (Resource->OwningThread == NtCurrentTeb()->Cid.UniqueThread)
{
retVal = TRUE;
Resource->NumberActive--;
goto done;
}
wait:
if (Wait == TRUE)
{
Resource->ExclusiveWaiters++;
RtlLeaveCriticalSection(&Resource->Lock);
Status = NtWaitForSingleObject(Resource->ExclusiveSemaphore,
FALSE,
NULL);
if (!NT_SUCCESS(Status))
goto done;
goto start; /* restart the acquisition to avoid deadlocks */
}
}
else /* one or more shared locks are in progress */
{
if (Wait == TRUE)
goto wait;
}
if (retVal == TRUE)
Resource->OwningThread = NtCurrentTeb()->Cid.UniqueThread;
done:
RtlLeaveCriticalSection(&Resource->Lock);
return retVal;
}
BOOLEAN STDCALL
RtlAcquireResourceShared(PRTL_RESOURCE Resource,
BOOLEAN Wait)
{
NTSTATUS Status = STATUS_UNSUCCESSFUL;
BOOLEAN retVal = FALSE;
start:
RtlEnterCriticalSection(&Resource->Lock);
if (Resource->NumberActive < 0)
{
if (Resource->OwningThread == NtCurrentTeb()->Cid.UniqueThread)
{
Resource->NumberActive--;
retVal = TRUE;
goto done;
}
if (Wait == TRUE)
{
Resource->SharedWaiters++;
RtlLeaveCriticalSection(&Resource->Lock);
Status = NtWaitForSingleObject(Resource->SharedSemaphore,
FALSE,
NULL);
if (!NT_SUCCESS(Status))
goto done;
goto start;
}
}
else
{
if (Status != STATUS_WAIT_0) /* otherwise RtlReleaseResource() has already done it */
Resource->NumberActive++;
retVal = TRUE;
}
done:
RtlLeaveCriticalSection(&Resource->Lock);
return retVal;
}
VOID STDCALL
RtlConvertExclusiveToShared(PRTL_RESOURCE Resource)
{
RtlEnterCriticalSection(&Resource->Lock);
if (Resource->NumberActive == -1)
{
Resource->OwningThread = NULL;
if (Resource->SharedWaiters > 0)
{
ULONG n;
/* prevent new writers from joining until
* all queued readers have done their thing */
n = Resource->SharedWaiters;
Resource->NumberActive = Resource->SharedWaiters + 1;
Resource->SharedWaiters = 0;
NtReleaseSemaphore(Resource->SharedSemaphore,
n,
NULL);
}
else
{
Resource->NumberActive = 1;
}
}
RtlLeaveCriticalSection(&Resource->Lock);
}
VOID STDCALL
RtlConvertSharedToExclusive(PRTL_RESOURCE Resource)
{
NTSTATUS Status;
RtlEnterCriticalSection(&Resource->Lock);
if (Resource->NumberActive == 1)
{
Resource->OwningThread = NtCurrentTeb()->Cid.UniqueThread;
Resource->NumberActive = -1;
}
else
{
Resource->ExclusiveWaiters++;
RtlLeaveCriticalSection(&Resource->Lock);
Status = NtWaitForSingleObject(Resource->ExclusiveSemaphore,
FALSE,
NULL);
if (!NT_SUCCESS(Status))
return;
RtlEnterCriticalSection(&Resource->Lock);
Resource->OwningThread = NtCurrentTeb()->Cid.UniqueThread;
Resource->NumberActive = -1;
}
RtlLeaveCriticalSection(&Resource->Lock);
}
VOID STDCALL
RtlReleaseResource(PRTL_RESOURCE Resource)
{
RtlEnterCriticalSection(&Resource->Lock);
if (Resource->NumberActive > 0) /* have one or more readers */
{
Resource->NumberActive--;
if (Resource->NumberActive == 0)
{
if (Resource->ExclusiveWaiters > 0)
{
wake_exclusive:
Resource->ExclusiveWaiters--;
NtReleaseSemaphore(Resource->ExclusiveSemaphore,
1,
NULL);
}
}
}
else if (Resource->NumberActive < 0) /* have a writer, possibly recursive */
{
Resource->NumberActive++;
if (Resource->NumberActive == 0)
{
Resource->OwningThread = 0;
if (Resource->ExclusiveWaiters > 0)
{
goto wake_exclusive;
}
else
{
if (Resource->SharedWaiters > 0)
{
ULONG n;
/* prevent new writers from joining until
* all queued readers have done their thing */
n = Resource->SharedWaiters;
Resource->NumberActive = Resource->SharedWaiters;
Resource->SharedWaiters = 0;
NtReleaseSemaphore(Resource->SharedSemaphore,
n,
NULL);
}
}
}
}
RtlLeaveCriticalSection(&Resource->Lock);
}
VOID STDCALL
RtlDumpResource(PRTL_RESOURCE Resource)
{
DbgPrint("RtlDumpResource(%p):\n\tactive count = %i\n\twaiting readers = %i\n\twaiting writers = %i\n",
Resource,
Resource->NumberActive,
Resource->SharedWaiters,
Resource->ExclusiveWaiters);
if (Resource->NumberActive != 0)
{
DbgPrint("\towner thread = %08x\n",
Resource->OwningThread);
}
}
/* EOF */