windows-nt/Source/XPSP1/NT/base/fs/rdr2/rxce/calldown.c

230 lines
5.7 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
calldown.c
Abstract:
This module implements the calldown routines for coordinating between multiple
calldowns/callouts.
Calldowns refer to invocation of a mini rdr routine by the wrapper while callouts
refer to invocations made by the wrapper to other components, e.g., TDI.
Revision History:
Balan Sethu Raman [SethuR] 15-Feb-1995
Notes:
There are a number of instances in which the same function needs to be invoked
on all the mini redirectors that have been registered. The RDBSS needs to be
synchronized with the completion of the invocation of all these calls. It
will be beneficial to invoke these calls in parallel when more than one
mini redirectors are registered. This module provides the framework for such
calldowns. This is provided by the routine RxCalldownMiniRedirectors.
An instance of coordination between multiple callouts occurs when a connect
request is initiated across multiple instances in parallel. The data structures
corresponding to this are defined in rxcep.h for now since the usage is restricted
to the connection engine. It would be a suitable candidate for migration if more uses
are found later.
--*/
#include "precomp.h"
#pragma hdrstop
#include "mrx.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, RxInitializeMRxCalldownContext)
#pragma alloc_text(PAGE, RxCompleteMRxCalldownRoutine)
#pragma alloc_text(PAGE, RxCalldownMRxWorkerRoutine)
#pragma alloc_text(PAGE, RxCalldownMiniRedirectors)
#endif
VOID
RxInitializeMRxCalldownContext(
PMRX_CALLDOWN_CONTEXT pContext,
PRDBSS_DEVICE_OBJECT pMRxDeviceObject,
PMRX_CALLDOWN_ROUTINE pRoutine,
PVOID pParameter)
/*++
Routine Description:
This routine initializes a mini redirector calldown context.
Arguments:
pContext - the MRx calldown context
Notes:
--*/
{
PAGED_CODE();
pContext->pMRxDeviceObject = pMRxDeviceObject;
pContext->pRoutine = pRoutine;
pContext->pParameter = pParameter;
pContext->pCompletionContext = NULL;
}
VOID
RxCompleteMRxCalldownRoutine(
PMRX_CALLDOWN_COMPLETION_CONTEXT pCompletionContext)
/*++
Routine Description:
This routine constitutes the tail of a mini redirector calldown completion.
It encapsulates the synchronization mechanism for the resumption of RDBSS
Arguments:
pCompletionContext - the MRx calldown completion context
Notes:
--*/
{
PAGED_CODE();
if (pCompletionContext != NULL) {
LONG WaitCount;
WaitCount = InterlockedDecrement(&pCompletionContext->WaitCount);
if (WaitCount == 0) {
KeSetEvent(
&pCompletionContext->Event,
IO_NO_INCREMENT,
FALSE);
}
}
}
VOID
RxCalldownMRxWorkerRoutine(
PMRX_CALLDOWN_CONTEXT pContext)
/*++
Routine Description:
This is the calldown worker routine that invokes the appropriate mini
redirector routine and follows it up with a call to the completion routine.
Arguments:
pContext - the MRx calldown context
Notes:
--*/
{
PRDBSS_DEVICE_OBJECT pMRxDeviceObject = pContext->pMRxDeviceObject;
PAGED_CODE();
if ( pContext->pRoutine != NULL) {
pContext->CompletionStatus = (pContext->pRoutine)(pContext->pParameter);
}
RxCompleteMRxCalldownRoutine(pContext->pCompletionContext);
}
NTSTATUS
RxCalldownMiniRedirectors(
LONG NumberOfMiniRdrs,
PMRX_CALLDOWN_CONTEXT pCalldownContext,
BOOLEAN PostCalldowns)
/*++
Routine Description:
This routine encapsulates the multiple mini redirector calldown.
Arguments:
NumberOfMiniRdrs - the number of mini redirectors
pCalldownContext - the MRx calldown context array for the mini redirectors
PostCalldowns - if TRUE the calldown employs multiple threads
Notes:
The three parameters for this routine constitute an effort to provide
maximum flexibility. The values should be carefully specified for
utmost efficiency.
Since the different calldowns can choose to employ a subset of the
mini redirectors registered at any time the calldown mechanism accepts an
array of calldown contexts and the appropriate number.
In most cases when there is only one mini redirector registered it is
necessary that the context switches be minimized. The routine provides
for this by having an explicit specification (PostCalldowns ) parameter.
--*/
{
LONG Index;
PMRX_CALLDOWN_CONTEXT pContext;
MRX_CALLDOWN_COMPLETION_CONTEXT CompletionContext;
PAGED_CODE();
if (NumberOfMiniRdrs == 0) {
return STATUS_SUCCESS;
}
pContext = pCalldownContext;
CompletionContext.WaitCount = NumberOfMiniRdrs;
KeInitializeEvent(
&CompletionContext.Event,
NotificationEvent,
FALSE);
for (Index = 0,pContext = pCalldownContext;
Index < NumberOfMiniRdrs;
Index++,pContext++) {
pContext->pCompletionContext = &CompletionContext;
}
if (PostCalldowns) {
for (Index = 0, pContext = pCalldownContext;
Index < NumberOfMiniRdrs;
Index++,pContext++) {
RxPostToWorkerThread(
RxFileSystemDeviceObject,
CriticalWorkQueue,
&pContext->WorkQueueItem,
RxCalldownMRxWorkerRoutine,
pContext);
}
} else {
for (Index = 0, pContext = pCalldownContext;
Index < NumberOfMiniRdrs;
Index++,pContext++) {
RxCalldownMRxWorkerRoutine(&pCalldownContext[Index]);
}
}
KeWaitForSingleObject(
&CompletionContext.Event,
Executive,
KernelMode,
FALSE,
NULL);
return STATUS_SUCCESS;
}