windows-nt/Source/XPSP1/NT/base/subsys/csr/server/wait.c
2020-09-26 16:20:57 +08:00

262 lines
6.9 KiB
C

/*++
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();
}