/* * 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 /* 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 */