VOID FxInterrupt::WorkItemHandler( VOID ) { ASSERT(m_EvtInterruptWorkItem != NULL ); FX_TRACK_DRIVER(GetDriverGlobals()); // // Call the drivers registered WorkItemForIsr event callback // if (m_CallbackLock != NULL) { KIRQL irql = 0; m_CallbackLock->Lock(&irql); FxPerfTraceWorkItem(&m_EvtInterruptWorkItem); m_EvtInterruptWorkItem(GetHandle(), m_Device->GetHandle()); m_CallbackLock->Unlock(irql); } else { FxPerfTraceWorkItem(&m_EvtInterruptWorkItem); m_EvtInterruptWorkItem(GetHandle(), m_Device->GetHandle()); } return; }
VOID FxInterrupt::DpcHandler( __in_opt PVOID SystemArgument1, __in_opt PVOID SystemArgument2 ) { UNREFERENCED_PARAMETER(SystemArgument1); UNREFERENCED_PARAMETER(SystemArgument2); ASSERT(m_EvtInterruptDpc != NULL); FX_TRACK_DRIVER(GetDriverGlobals()); // // Call the drivers registered DpcForIsr event callback // if (m_CallbackLock != NULL) { KIRQL irql = 0; m_CallbackLock->Lock(&irql); m_EvtInterruptDpc(GetHandle(), m_Device->GetHandle()); m_CallbackLock->Unlock(irql); } else { m_EvtInterruptDpc(GetHandle(), m_Device->GetHandle()); } return; }
VOID FxDpc::DpcHandler( __in PKDPC Dpc, __in PVOID SystemArgument1, __in PVOID SystemArgument2 ) { UNREFERENCED_PARAMETER(Dpc); UNREFERENCED_PARAMETER(SystemArgument1); UNREFERENCED_PARAMETER(SystemArgument2); FX_TRACK_DRIVER(GetDriverGlobals()); if (m_Callback != NULL) { FxPerfTraceDpc(&m_Callback); if (m_CallbackLock != NULL) { KIRQL irql = 0; m_CallbackLock->Lock(&irql); m_Callback((WDFDPC)(this->GetObjectHandle())); m_CallbackLock->Unlock(irql); } else { m_Callback((WDFDPC)(this->GetObjectHandle())); } } }
VOID FxWorkItem::WorkItemHandler( VOID ) { KIRQL irql; FX_TRACK_DRIVER(GetDriverGlobals()); Lock(&irql); // // Mark the workitem as no longer enqueued and completed // // The handler is allowed to re-enqueue, so mark it before the callback // m_Enqueued = FALSE; m_WorkItemRunningCount++; Unlock(irql); if (m_CallbackLock != NULL) { m_CallbackLock->Lock(&irql); #if FX_IS_KERNEL_MODE FxPerfTraceWorkItem(&m_Callback); #endif m_Callback(GetHandle()); m_CallbackLock->Unlock(irql); } else { #if FX_IS_KERNEL_MODE FxPerfTraceWorkItem(&m_Callback); #endif m_Callback(GetHandle()); } Lock(&irql); m_WorkItemRunningCount--; // // The workitem can be re-enqueued by the drivers // work item handler routine. We can't set the work // item completed event until we are sure there are // no outstanding work items. // if (m_WorkItemRunningCount == 0L && m_Enqueued == FALSE) { m_WorkItemCompleted.Set(); } Unlock(irql); }
_Must_inspect_result_ NTSTATUS FxPkgIo::Dispatch( __inout MdIrp Irp ) { FxIrp fxIrp(Irp); FX_TRACK_DRIVER(GetDriverGlobals()); DoTraceLevelMessage( GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO, "WDFDEVICE 0x%p !devobj 0x%p %!IRPMJ!, IRP_MN %x, IRP 0x%p", m_Device->GetHandle(), m_Device->GetDeviceObject(), fxIrp.GetMajorFunction(), fxIrp.GetMinorFunction(), Irp); return DispatchStep1(Irp, m_DynamicDispatchInfoListHead.Flink); }
NTSTATUS WDFEXPORT(WdfDeviceWdmDispatchIrpToIoQueue)( __in PWDF_DRIVER_GLOBALS DriverGlobals, __in WDFDEVICE Device, __in MdIrp Irp, __in WDFQUEUE Queue, __in ULONG Flags ) { FxIoQueue *queue; FxDevice *device; PFX_DRIVER_GLOBALS fxDriverGlobals; PIO_STACK_LOCATION stack; NTSTATUS status; FxIoInCallerContext* ioInCallerCtx; queue = NULL; ioInCallerCtx = NULL; FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), Device, FX_TYPE_DEVICE, (PVOID*) &device); fxDriverGlobals = device->GetDriverGlobals(); FX_TRACK_DRIVER(fxDriverGlobals); FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), Queue, FX_TYPE_QUEUE, (PVOID*)&queue); FxPointerNotNull(fxDriverGlobals, Irp); // // If the caller is a preprocess routine, the contract for this DDI is just like IoCallDriver. // The caller sets up their stack location and then the DDI advances to the next stack // location. This means that the caller either has to call IoSkipCurrentIrpStackLocation // or IoCopyCurrentIrpStackLocationToNext before calling this DDI. // if (Flags & WDF_DISPATCH_IRP_TO_IO_QUEUE_PREPROCESSED_IRP) { IoSetNextIrpStackLocation(Irp); } // // Verifier checks. // status = VerifyWdfDeviceWdmDispatchIrpToIoQueue(fxDriverGlobals, device, Irp, queue, Flags); if(!NT_SUCCESS(status)) { Irp->IoStatus.Status = status; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } // // Adjust stack if IRP needs to be forwarded to parent device. // if (device->m_ParentDevice == queue->GetDevice()) { IoCopyCurrentIrpStackLocationToNext(Irp); IoSetNextIrpStackLocation(Irp); // // From now on use new device. // device = device->m_ParentDevice; // // Save a pointer to the device object for this request so that it can // be used later in completion. // stack = IoGetCurrentIrpStackLocation(Irp); stack->DeviceObject = device->GetDeviceObject(); } // // Get in-context caller callback if required. // if (Flags & WDF_DISPATCH_IRP_TO_IO_QUEUE_INVOKE_INCALLERCTX_CALLBACK) { ioInCallerCtx = device->m_PkgIo->GetIoInCallerContextCallback( queue->GetCxDeviceInfo()); } // // DispatchStep2 will convert the IRP into a WDFREQUEST, queue it and if // possible dispatch the request to the driver. // return device->m_PkgIo->DispatchStep2(Irp, ioInCallerCtx, queue); }
VOID FxEventQueue::EventQueueWorker( VOID ) /*++ Routine Description: This is the work item that attempts to run the queue state machine on the special power thread. --*/ { FxPostProcessInfo info; KIRQL irql; FxPkgPnp* pPkgPnp; #if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) FX_TRACK_DRIVER(m_PkgPnp->GetDriverGlobals()); #endif // // Cache away m_PkgPnp while we know we still have a valid object. Once // we Unlock() after the worker routine, the object could be gone until // the worker routine set a flag postponing deletion. // pPkgPnp = m_PkgPnp; Lock(&irql); ASSERT(m_QueueFlags & FxEventQueueFlagWorkItemQueued); // // Clear the queued flag, so that it's clear that the work item can // be safely re-enqueued. // m_QueueFlags &= ~FxEventQueueFlagWorkItemQueued; // // We should only see this count rise to a small number (like 10 or so). // ASSERT(m_WorkItemRunningCount < 0xFF); m_WorkItemRunningCount++; Unlock(irql); // // Call the function that will actually run the state machine. // m_EventWorker(m_PkgPnp, &info, m_EventWorkerContext); Lock(&irql); m_WorkItemRunningCount--; GetFinishedState(&info); Unlock(irql); // // NOTE: There is no need to use a reference count to keep this event queue // (and the containing state machine) alive. Instead, the thread // which wants to delete the state machine must wait for this work // item to exit. If there was a reference to release, we would have // a race between Unlock()ing and releasing the reference if the state // machine moved into the finished state and deletes the device after // we dropped the lock, but before we released the reference. // // This is important in that the device deletion can trigger // DriverUnload to run before the release executes. DriverUnload // frees the IFR buffer. If this potential release logs something to // the IFR, you would bugcheck. Since it is impossible to defensively // prevent all destructors from logging to the IFR, we can't use a // ref count here to keep the queue alive. // // // If Evaluate needs to use pPkgPnp, then the call to the worker routine // above made sure that pPkgPnp has not yet been freed. // info.Evaluate(pPkgPnp); }