230 lines
5.7 KiB
C
230 lines
5.7 KiB
C
/*++
|
||
|
||
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;
|
||
}
|
||
|
||
|
||
|