|
|
/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
rxtdi.c
Abstract:
This module implements the NT specific notification routines in the connection engine
Revision History:
Balan Sethu Raman [SethuR] 15-Feb-1995
Notes:
The notification of a transport binding/unbinding to the mini redirectors is done in a worker thread. In order to simplify the task of writing a routine the connection engine guarantees that not more than one invocation of MRxTranspotrtUpdateHandler will be active at any instant of time for a given mini redirector.
There is no thread dedicated to processing these notifications. A worker thread is used to process the notifications. In order to ensure condition (1) all the notifications are queued ( interlocked queue ).
--*/
#include "precomp.h"
#pragma hdrstop
#include "mrx.h"
typedef struct _RXCE_MINIRDR_NOTIFICATION_CONTEXT_ { LIST_ENTRY NotificationListEntry; PRXCE_TRANSPORT pTransport; RXCE_TRANSPORT_EVENT TransportEvent; } RXCE_MINIRDR_NOTIFICATION_CONTEXT, *PRXCE_MINIRDR_NOTIFICATION_CONTEXT;
typedef struct _RXCE_MINIRDR_NOTIFICATION_HANDLER_ { WORK_QUEUE_ITEM WorkQueueEntry; KSPIN_LOCK Lock; LIST_ENTRY ListHead; BOOLEAN NotifierActive; } RXCE_MINIRDR_NOTIFICATION_HANDLER, *PRXCE_MINIRDR_NOTIFICATION_HANDLER;
RXCE_MINIRDR_NOTIFICATION_HANDLER s_RxCeMinirdrNotificationHandler;
extern VOID MiniRedirectorsNotifier( PVOID NotificationContext);
NTSTATUS InitializeMiniRedirectorNotifier() { s_RxCeMinirdrNotificationHandler.NotifierActive = FALSE; KeInitializeSpinLock(&s_RxCeMinirdrNotificationHandler.Lock); InitializeListHead(&s_RxCeMinirdrNotificationHandler.ListHead); return STATUS_SUCCESS; }
NTSTATUS NotifyMiniRedirectors( RXCE_TRANSPORT_HANDLE hTransport, RXCE_TRANSPORT_EVENT TransportEvent, RXCE_NOTIFICATION_MODE Mode) { NTSTATUS Status; KIRQL SavedIrql;
PRXCE_MINIRDR_NOTIFICATION_CONTEXT pContext;
pContext = RxAllocatePoolWithTag( PagedPool | POOL_COLD_ALLOCATION, sizeof(RXCE_MINIRDR_NOTIFICATION_CONTEXT), RX_MISC_POOLTAG);
if (pContext != NULL) { pContext->TransportEvent = TransportEvent;
// Reference the transport entry
pContext->pTransport = RxCeReferenceTransport(hTransport);
if (Mode == RXCE_ASYNCHRONOUS_NOTIFICATION) { BOOLEAN DispatchNotifier;
// Acquire the spin lock ...
KeAcquireSpinLock( &s_RxCeMinirdrNotificationHandler.Lock, &SavedIrql);
DispatchNotifier = (IsListEmpty(&s_RxCeMinirdrNotificationHandler.ListHead) && !s_RxCeMinirdrNotificationHandler.NotifierActive);
InsertTailList(&s_RxCeMinirdrNotificationHandler.ListHead,&pContext->NotificationListEntry);
if (DispatchNotifier) { s_RxCeMinirdrNotificationHandler.NotifierActive = TRUE; }
// Release the spin lock
KeReleaseSpinLock( &s_RxCeMinirdrNotificationHandler.Lock, SavedIrql);
// If the notification list is empty a worker thread needs to be fired up.
if (DispatchNotifier) { RxPostToWorkerThread( CriticalWorkQueue, &s_RxCeMinirdrNotificationHandler.WorkQueueEntry, MiniRedirectorsNotifier, &s_RxCeMinirdrNotificationHandler); }
Status = STATUS_SUCCESS; } else { ULONG i; PMRX_TRANSPORT_UPDATE_HANDLER MRxTransportUpdateHandler; PLIST_ENTRY ListEntry;
// Notify all the mini redirectors ....
for (ListEntry = RxRegisteredMiniRdrs.Flink; ListEntry!= &RxRegisteredMiniRdrs; ListEntry = ListEntry->Flink) {
PRDBSS_DEVICE_OBJECT RxDeviceObject = CONTAINING_RECORD( ListEntry, RDBSS_DEVICE_OBJECT, MiniRdrListLinks ); MRxTransportUpdateHandler = RxDeviceObject->Dispatch->MRxTransportUpdateHandler;
if ( MRxTransportUpdateHandler != NULL) { Status = MRxTransportUpdateHandler( pContext->pTransport, pContext->TransportEvent, pContext->pTransport->pProviderInfo); } }
// Derefrence the transport entry
RxCeDereferenceTransport(pContext->pTransport);
// free the notification context.
RxFreePool(pContext);
Status = STATUS_SUCCESS; } } else { Status = STATUS_INSUFFICIENT_RESOURCES; }
return Status; }
VOID MiniRedirectorsNotifier( PVOID NotificationContext) { NTSTATUS Status; KIRQL SavedIrql;
PLIST_ENTRY pEntry;
PRXCE_MINIRDR_NOTIFICATION_CONTEXT pContext; PMRX_TRANSPORT_UPDATE_HANDLER MRxTransportUpdateHandler;
for (;;) { PLIST_ENTRY ListEntry;
// Acquire the spin lock ...
KeAcquireSpinLock( &s_RxCeMinirdrNotificationHandler.Lock, &SavedIrql);
// Remove an item from the notification list.
if (!IsListEmpty(&s_RxCeMinirdrNotificationHandler.ListHead)) { pEntry = RemoveHeadList( &s_RxCeMinirdrNotificationHandler.ListHead); } else { pEntry = NULL; s_RxCeMinirdrNotificationHandler.NotifierActive = FALSE; }
// Release the spin lock
KeReleaseSpinLock(&s_RxCeMinirdrNotificationHandler.Lock,SavedIrql);
if (pEntry == NULL) { break; }
pContext = (PRXCE_MINIRDR_NOTIFICATION_CONTEXT) CONTAINING_RECORD( pEntry, RXCE_MINIRDR_NOTIFICATION_CONTEXT, NotificationListEntry);
// Notify all the mini redirectors ....
for (ListEntry = RxRegisteredMiniRdrs.Flink; ListEntry!= &RxRegisteredMiniRdrs; ListEntry = ListEntry->Flink) {
PRDBSS_DEVICE_OBJECT RxDeviceObject = CONTAINING_RECORD( ListEntry, RDBSS_DEVICE_OBJECT, MiniRdrListLinks ); MRxTransportUpdateHandler = RxDeviceObject->Dispatch->MRxTransportUpdateHandler;
if ( MRxTransportUpdateHandler != NULL) { Status = MRxTransportUpdateHandler( pContext->pTransport, pContext->TransportEvent, pContext->pTransport->pProviderInfo);
if (!NT_SUCCESS(Status)) { } } }
// Derefrence the transport entry
RxCeDereferenceTransport(pContext->pTransport);
// free the notification context.
RxFreePool(pContext); } }
|