mirror of
https://github.com/reactos/reactos.git
synced 2024-11-01 04:11:30 +00:00
437 lines
11 KiB
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 */
|