/*++ Copyright (c) 1989 Microsoft Corporation Module Name: wait.c Abstract: This module contains the primitives to implement the Wait functions on the Server side of the Client-Server Runtime Subsystem to the Session Manager SubSystem. Author: Steve Wood (stevewo) 8-Oct-1990 Revision History: --*/ #include "csrsrv.h" BOOLEAN CsrInitializeWait( IN CSR_WAIT_ROUTINE WaitRoutine, IN PCSR_THREAD WaitingThread, IN OUT PCSR_API_MSG WaitReplyMessage, IN PVOID WaitParameter, OUT PCSR_WAIT_BLOCK *WaitBlockPtr ) { ULONG Length; PCSR_WAIT_BLOCK WaitBlock; Length = sizeof( *WaitBlock ) - sizeof( WaitBlock->WaitReplyMessage ) + WaitReplyMessage->h.u1.s1.TotalLength; WaitBlock = RtlAllocateHeap( CsrHeap, MAKE_TAG( WAIT_TAG ), Length ); if (WaitBlock == NULL) { WaitReplyMessage->ReturnValue = (ULONG)STATUS_NO_MEMORY; return( FALSE ); } WaitBlock->Length = Length; WaitBlock->WaitingThread = WaitingThread; WaitBlock->WaitParameter = WaitParameter; WaitBlock->WaitRoutine = WaitRoutine; WaitBlock->UserLink.Flink = WaitBlock->UserLink.Blink = NULL; WaitBlock->Link.Flink = WaitBlock->Link.Blink = NULL; RtlMoveMemory( &WaitBlock->WaitReplyMessage, WaitReplyMessage, WaitReplyMessage->h.u1.s1.TotalLength ); *WaitBlockPtr = WaitBlock; return TRUE; } BOOLEAN CsrCreateWait( IN PLIST_ENTRY WaitQueue, IN CSR_WAIT_ROUTINE WaitRoutine, IN PCSR_THREAD WaitingThread, IN OUT PCSR_API_MSG WaitReplyMessage, IN PVOID WaitParameter, IN PLIST_ENTRY UserLinkListHead OPTIONAL ) { PCSR_WAIT_BLOCK WaitBlock; if (!CsrInitializeWait( WaitRoutine, WaitingThread, WaitReplyMessage, WaitParameter, &WaitBlock ) ) { return FALSE; } AcquireWaitListsLock(); if ( WaitingThread->Flags & CSR_THREAD_DESTROYED ) { RtlFreeHeap( CsrHeap, 0, WaitBlock ); ReleaseWaitListsLock(); return FALSE; } WaitingThread->WaitBlock = WaitBlock; InsertTailList( WaitQueue, &WaitBlock->Link ); if ( ARGUMENT_PRESENT(UserLinkListHead) ) { InsertTailList( UserLinkListHead, &WaitBlock->UserLink ); } ReleaseWaitListsLock(); return( TRUE ); } BOOLEAN CsrNotifyWaitBlock( IN PCSR_WAIT_BLOCK WaitBlock, IN PLIST_ENTRY WaitQueue, IN PVOID SatisfyParameter1, IN PVOID SatisfyParameter2, IN ULONG WaitFlags, IN BOOLEAN DereferenceThread ) { if ((*WaitBlock->WaitRoutine)( WaitQueue, WaitBlock->WaitingThread, &WaitBlock->WaitReplyMessage, WaitBlock->WaitParameter, SatisfyParameter1, SatisfyParameter2, WaitFlags ) ) { // // we don't take any locks other than the waitlist lock // because the only thing we have to worry about is the thread // going away beneath us and that's prevented by having // DestroyThread and DestroyProcess take the waitlist lock. // WaitBlock->WaitingThread->WaitBlock = NULL; if (WaitBlock->WaitReplyMessage.CaptureBuffer != NULL) { CsrReleaseCapturedArguments(&WaitBlock->WaitReplyMessage); } NtReplyPort( WaitBlock->WaitingThread->Process->ClientPort, (PPORT_MESSAGE)&WaitBlock->WaitReplyMessage ); if (DereferenceThread) { if ( WaitBlock->Link.Flink ) { RemoveEntryList( &WaitBlock->Link ); } if ( WaitBlock->UserLink.Flink ) { RemoveEntryList( &WaitBlock->UserLink ); } CsrDereferenceThread(WaitBlock->WaitingThread); RtlFreeHeap( CsrHeap, 0, WaitBlock ); } else { // // indicate that this wait has been satisfied. when the // console unwinds to the point where it can release the // console lock, it will dereference the thread. // WaitBlock->WaitRoutine = NULL; } return( TRUE ); } else { return( FALSE ); } } BOOLEAN CsrNotifyWait( IN PLIST_ENTRY WaitQueue, IN BOOLEAN SatisfyAll, IN PVOID SatisfyParameter1, IN PVOID SatisfyParameter2 ) { PLIST_ENTRY ListHead, ListNext; PCSR_WAIT_BLOCK WaitBlock; BOOLEAN Result; Result = FALSE; AcquireWaitListsLock(); ListHead = WaitQueue; ListNext = ListHead->Flink; while (ListNext != ListHead) { WaitBlock = CONTAINING_RECORD( ListNext, CSR_WAIT_BLOCK, Link ); ListNext = ListNext->Flink; if (WaitBlock->WaitRoutine) { Result |= CsrNotifyWaitBlock( WaitBlock, WaitQueue, SatisfyParameter1, SatisfyParameter2, 0, FALSE ); if (!SatisfyAll) { break; } } } ReleaseWaitListsLock(); return( Result ); } VOID CsrDereferenceWait( IN PLIST_ENTRY WaitQueue ) { PLIST_ENTRY ListHead, ListNext; PCSR_WAIT_BLOCK WaitBlock; AcquireProcessStructureLock(); AcquireWaitListsLock(); ListHead = WaitQueue; ListNext = ListHead->Flink; while (ListNext != ListHead) { WaitBlock = CONTAINING_RECORD( ListNext, CSR_WAIT_BLOCK, Link ); ListNext = ListNext->Flink; if (!WaitBlock->WaitRoutine) { if ( WaitBlock->Link.Flink ) { RemoveEntryList( &WaitBlock->Link ); } if ( WaitBlock->UserLink.Flink ) { RemoveEntryList( &WaitBlock->UserLink ); } CsrDereferenceThread(WaitBlock->WaitingThread); RtlFreeHeap( CsrHeap, 0, WaitBlock ); } } ReleaseWaitListsLock(); ReleaseProcessStructureLock(); } VOID CsrMoveSatisfiedWait( IN PLIST_ENTRY DstWaitQueue, IN PLIST_ENTRY SrcWaitQueue ) { PLIST_ENTRY ListHead, ListNext; PCSR_WAIT_BLOCK WaitBlock; AcquireWaitListsLock(); ListHead = SrcWaitQueue; ListNext = ListHead->Flink; while (ListNext != ListHead) { WaitBlock = CONTAINING_RECORD( ListNext, CSR_WAIT_BLOCK, Link ); ListNext = ListNext->Flink; if (!WaitBlock->WaitRoutine) { RemoveEntryList( &WaitBlock->Link ); InsertTailList( DstWaitQueue, &WaitBlock->Link ); } } ReleaseWaitListsLock(); }