reactos/subsystems/win32/csrsrv/wait.c

437 lines
11 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Client/Server Runtime SubSystem
* FILE: subsystems/win32/csrsrv/wait.c
* PURPOSE: CSR Server DLL Wait Implementation
* PROGRAMMERS: Emanuele Aliberti
* Alex Ionescu (alex@relsoft.net)
*/
/* INCLUDES *******************************************************************/
#include "srv.h"
#define NDEBUG
#include <debug.h>
/* DATA ***********************************************************************/
RTL_CRITICAL_SECTION CsrWaitListsLock;
/* PRIVATE FUNCTIONS **********************************************************/
/*++
* @name CsrInitializeWait
*
* The CsrInitializeWait routine initializes a CSR Wait Object.
*
* @param WaitFunction
* Pointer to the function that will handle this wait.
*
* @param CsrWaitThread
* Pointer to the CSR Thread that will perform the wait.
*
* @param WaitApiMessage
* Pointer to the CSR API Message associated to this wait.
*
* @param WaitContext
* Pointer to a user-defined parameter associated to this wait.
*
* @param NewWaitBlock
* Pointed to the initialized CSR Wait Block for this wait.
*
* @return TRUE in case of success, FALSE otherwise.
*
* @remarks None.
*
*--*/
BOOLEAN
NTAPI
CsrInitializeWait(IN CSR_WAIT_FUNCTION WaitFunction,
IN PCSR_THREAD CsrWaitThread,
IN OUT PCSR_API_MESSAGE WaitApiMessage,
IN PVOID WaitContext,
OUT PCSR_WAIT_BLOCK *NewWaitBlock)
{
ULONG Size;
PCSR_WAIT_BLOCK WaitBlock;
/* Calculate the size of the wait block */
Size = sizeof(CSR_WAIT_BLOCK) -
sizeof(WaitBlock->WaitApiMessage) +
WaitApiMessage->Header.u1.s1.TotalLength;
/* Allocate the Wait Block */
WaitBlock = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, Size);
if (!WaitBlock)
{
/* Fail */
WaitApiMessage->Status = STATUS_NO_MEMORY;
return FALSE;
}
/* Initialize it */
WaitBlock->Size = Size;
WaitBlock->WaitThread = CsrWaitThread;
WaitBlock->WaitContext = WaitContext;
WaitBlock->WaitFunction = WaitFunction;
WaitBlock->WaitList.Flink = NULL;
WaitBlock->WaitList.Blink = NULL;
/* Copy the message */
RtlCopyMemory(&WaitBlock->WaitApiMessage,
WaitApiMessage,
WaitApiMessage->Header.u1.s1.TotalLength);
/* Return the block */
*NewWaitBlock = WaitBlock;
return TRUE;
}
/*++
* @name CsrNotifyWaitBlock
*
* The CsrNotifyWaitBlock routine calls the wait function for a registered
* CSR Wait Block, and replies to the attached CSR API Message, if any.
*
* @param WaitBlock
* Pointer to the CSR Wait Block.
*
* @param WaitList
* Pointer to the wait list for this wait.
*
* @param WaitArgument[1-2]
* User-defined values to pass to the wait function.
*
* @param WaitFlags
* Wait flags for this wait.
*
* @param DereferenceThread
* Specifies whether the CSR Thread should be dereferenced at the
* end of this wait.
*
* @return TRUE in case of success, FALSE otherwise.
*
* @remarks After a wait block is notified, the wait function becomes invalid.
*
*--*/
BOOLEAN
NTAPI
CsrNotifyWaitBlock(IN PCSR_WAIT_BLOCK WaitBlock,
IN PLIST_ENTRY WaitList,
IN PVOID WaitArgument1,
IN PVOID WaitArgument2,
IN ULONG WaitFlags,
IN BOOLEAN DereferenceThread)
{
/* Call the wait function */
if (WaitBlock->WaitFunction(WaitList,
WaitBlock->WaitThread,
&WaitBlock->WaitApiMessage,
WaitBlock->WaitContext,
WaitArgument1,
WaitArgument2,
WaitFlags))
{
/* The wait is done, clear the block */
WaitBlock->WaitThread->WaitBlock = NULL;
/* Check for captured arguments */
if (WaitBlock->WaitApiMessage.CsrCaptureData)
{
/* Release them */
CsrReleaseCapturedArguments(&WaitBlock->WaitApiMessage);
}
/* Reply to the port */
NtReplyPort(WaitBlock->WaitThread->Process->ClientPort,
&WaitBlock->WaitApiMessage.Header);
/* Check if we should dereference the thread */
if (DereferenceThread)
{
/* Remove it from the Wait List */
if (WaitBlock->WaitList.Flink)
{
RemoveEntryList(&WaitBlock->WaitList);
}
/* Dereference the thread */
CsrDereferenceThread(WaitBlock->WaitThread);
/* Free the wait block */
RtlFreeHeap(CsrHeap, 0, WaitBlock);
}
else
{
/* The wait is complete, but the thread is being kept alive */
WaitBlock->WaitFunction = NULL;
}
/* The wait succeeded */
return TRUE;
}
/* The wait failed */
return FALSE;
}
/* PUBLIC FUNCTIONS ***********************************************************/
/*++
* @name CsrCreateWait
* @implemented NT4
*
* The CsrCreateWait routine creates a CSR Wait.
*
* @param WaitList
* Pointer to a wait list in which the wait will be added.
*
* @param WaitFunction
* Pointer to the function that will handle this wait.
*
* @param CsrWaitThread
* Pointer to the CSR Thread that will perform the wait.
*
* @param WaitApiMessage
* Pointer to the CSR API Message associated to this wait.
*
* @param WaitContext
* Pointer to a user-defined parameter associated to this wait.
*
* @return TRUE in case of success, FALSE otherwise.
*
* @remarks None.
*
*--*/
BOOLEAN
NTAPI
CsrCreateWait(IN PLIST_ENTRY WaitList,
IN CSR_WAIT_FUNCTION WaitFunction,
IN PCSR_THREAD CsrWaitThread,
IN OUT PCSR_API_MESSAGE WaitApiMessage,
IN PVOID WaitContext)
{
PCSR_WAIT_BLOCK WaitBlock;
/* Initialize the wait */
if (!CsrInitializeWait(WaitFunction,
CsrWaitThread,
WaitApiMessage,
WaitContext,
&WaitBlock))
{
return FALSE;
}
/* Acquire the Wait Lock */
CsrAcquireWaitLock();
/* Make sure the thread wasn't destroyed */
if (CsrWaitThread->Flags & CsrThreadTerminated)
{
/* Fail the wait */
RtlFreeHeap(CsrHeap, 0, WaitBlock);
CsrReleaseWaitLock();
return FALSE;
}
/* Associate the newly created wait to the waiting thread */
CsrWaitThread->WaitBlock = WaitBlock;
/* Insert the wait in the queue */
InsertTailList(WaitList, &WaitBlock->WaitList);
/* Return */
CsrReleaseWaitLock();
return TRUE;
}
/*++
* @name CsrDereferenceWait
* @implemented NT4
*
* The CsrDereferenceWait routine dereferences a CSR Wait Block.
*
* @param WaitList
* Pointer to the Wait List associated to the wait.
* @return None.
*
* @remarks None.
*
*--*/
VOID
NTAPI
CsrDereferenceWait(IN PLIST_ENTRY WaitList)
{
PLIST_ENTRY NextEntry;
PCSR_WAIT_BLOCK WaitBlock;
/* Acquire the Process and Wait Locks */
CsrAcquireProcessLock();
CsrAcquireWaitLock();
/* Set the list pointers */
NextEntry = WaitList->Flink;
/* Start the loop */
while (NextEntry != WaitList)
{
/* Get the wait block */
WaitBlock = CONTAINING_RECORD(NextEntry, CSR_WAIT_BLOCK, WaitList);
/* Move to the next entry */
NextEntry = NextEntry->Flink;
/* Check if there's no Wait Routine (satisfied wait) */
if (WaitBlock->WaitFunction == NULL)
{
/* Remove it from the Wait List */
if (WaitBlock->WaitList.Flink)
{
RemoveEntryList(&WaitBlock->WaitList);
}
/* Dereference the thread waiting on it */
CsrDereferenceThread(WaitBlock->WaitThread);
/* Free the block */
RtlFreeHeap(CsrHeap, 0, WaitBlock);
}
}
/* Release the locks */
CsrReleaseWaitLock();
CsrReleaseProcessLock();
}
/*++
* @name CsrMoveSatisfiedWait
* @implemented NT5
*
* The CsrMoveSatisfiedWait routine moves satisfied waits from
* a wait list to another list.
*
* @param DestinationList
* Pointer to a list in which the satisfied waits will be added.
*
* @param WaitList
* Pointer to the wait list whose satisfied wait blocks
* will be moved away.
*
* @return None.
*
* @remarks None.
*
*--*/
VOID
NTAPI
CsrMoveSatisfiedWait(IN PLIST_ENTRY DestinationList,
IN PLIST_ENTRY WaitList)
{
PLIST_ENTRY NextEntry;
PCSR_WAIT_BLOCK WaitBlock;
/* Acquire the Wait Lock */
CsrAcquireWaitLock();
/* Set the List pointers */
NextEntry = WaitList->Flink;
/* Start looping */
while (NextEntry != WaitList)
{
/* Get the Wait block */
WaitBlock = CONTAINING_RECORD(NextEntry, CSR_WAIT_BLOCK, WaitList);
/* Go to the next entry */
NextEntry = NextEntry->Flink;
/* Check if there's no Wait Routine (satisfied wait) */
if (WaitBlock->WaitFunction == NULL)
{
/* Remove it from the Wait Block Queue */
RemoveEntryList(&WaitBlock->WaitList);
/* Insert the wait into the destination list */
InsertTailList(DestinationList, &WaitBlock->WaitList);
}
}
/* Release the wait lock */
CsrReleaseWaitLock();
}
/*++
* @name CsrNotifyWait
* @implemented NT4
*
* The CsrNotifyWait routine notifies CSR Wait Blocks.
*
* @param WaitList
* Pointer to the wait list whose wait blocks will be notified.
*
* @param NotifyAll
* Whether or not we must notify all the waits.
*
* @param WaitArgument[1-2]
* User-defined argument to pass on to the wait function.
*
* @return TRUE in case of success, FALSE otherwise.
*
* @remarks None.
*
*--*/
BOOLEAN
NTAPI
CsrNotifyWait(IN PLIST_ENTRY WaitList,
IN BOOLEAN NotifyAll,
IN PVOID WaitArgument1,
IN PVOID WaitArgument2)
{
PLIST_ENTRY NextEntry;
PCSR_WAIT_BLOCK WaitBlock;
BOOLEAN NotifySuccess = FALSE;
/* Acquire the Wait Lock */
CsrAcquireWaitLock();
/* Set the List pointers */
NextEntry = WaitList->Flink;
/* Start looping */
while (NextEntry != WaitList)
{
/* Get the Wait block */
WaitBlock = CONTAINING_RECORD(NextEntry, CSR_WAIT_BLOCK, WaitList);
/* Go to the next entry */
NextEntry = NextEntry->Flink;
/* Check if there is a Wait Routine */
if (WaitBlock->WaitFunction != NULL)
{
/* Notify the Waiter */
NotifySuccess |= CsrNotifyWaitBlock(WaitBlock,
WaitList,
WaitArgument1,
WaitArgument2,
0,
FALSE);
/*
* We've already done a wait, so leave unless
* we want to notify all the waits...
*/
if (!NotifyAll) break;
}
}
/* Release the wait lock and return */
CsrReleaseWaitLock();
return NotifySuccess;
}
/* EOF */