reactos/sdk/lib/rtl/resource.c

327 lines
8 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries
* FILE: lib/rtl/resource.c
* PURPOSE: Resource (multiple-reader-single-writer lock) functions
* PROGRAMMER: Partially takem from Wine:
* Copyright 1996-1998 Marcus Meissner
* 1999 Alex Korobka
*/
/* INCLUDES *****************************************************************/
#include <rtl.h>
#define NDEBUG
#include <debug.h>
/* FUNCTIONS ***************************************************************/
/*
* @implemented
*/
VOID
NTAPI
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 */
}
/*
* @implemented
*/
VOID
NTAPI
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;
}
/*
* @implemented
*/
BOOLEAN
NTAPI
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()->ClientId.UniqueThread)
{
retVal = TRUE;
Resource->NumberActive--;
goto done;
}
wait:
if (Wait)
{
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)
goto wait;
}
if (retVal)
Resource->OwningThread = NtCurrentTeb()->ClientId.UniqueThread;
done:
RtlLeaveCriticalSection(&Resource->Lock);
return retVal;
}
/*
* @implemented
*/
BOOLEAN
NTAPI
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()->ClientId.UniqueThread)
{
Resource->NumberActive--;
retVal = TRUE;
goto done;
}
if (Wait)
{
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;
}
/*
* @implemented
*/
VOID
NTAPI
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);
}
/*
* @implemented
*/
VOID
NTAPI
RtlConvertSharedToExclusive(PRTL_RESOURCE Resource)
{
NTSTATUS Status;
RtlEnterCriticalSection(&Resource->Lock);
if (Resource->NumberActive == 1)
{
Resource->OwningThread = NtCurrentTeb()->ClientId.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()->ClientId.UniqueThread;
Resource->NumberActive = -1;
}
RtlLeaveCriticalSection(&Resource->Lock);
}
/*
* @implemented
*/
VOID
NTAPI
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);
}
/*
* @implemented
*/
VOID
NTAPI
RtlDumpResource(PRTL_RESOURCE Resource)
{
DbgPrint("RtlDumpResource(%p):\n\tactive count = %d\n\twaiting readers = %u\n\twaiting writers = %u\n",
Resource,
Resource->NumberActive,
Resource->SharedWaiters,
Resource->ExclusiveWaiters);
if (Resource->NumberActive != 0)
{
DbgPrint("\towner thread = %p\n",
Resource->OwningThread);
}
}
/* EOF */