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