2020-09-24 20:51:15 +00:00
|
|
|
/*++
|
|
|
|
|
|
|
|
Copyright (c) Microsoft Corporation
|
|
|
|
|
|
|
|
Module Name:
|
|
|
|
|
|
|
|
FxSystemThread.hpp
|
|
|
|
|
|
|
|
Abstract:
|
|
|
|
|
|
|
|
This class provides the safe handling for system threads
|
|
|
|
in the driver frameworks.
|
|
|
|
|
|
|
|
|
|
|
|
Author:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Revision History:
|
|
|
|
|
|
|
|
--*/
|
|
|
|
|
|
|
|
#ifndef _FXSYSTEMTHREAD_H_
|
|
|
|
#define _FXSYSTEMTHREAD_H_
|
|
|
|
|
|
|
|
class FxSystemThread : public FxNonPagedObject {
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
MxEvent m_InitEvent;
|
|
|
|
MxEvent m_WorkEvent;
|
|
|
|
|
|
|
|
LIST_ENTRY m_WorkList;
|
|
|
|
|
|
|
|
PVOID m_ThreadPtr;
|
|
|
|
|
|
|
|
MdEThread m_PEThread;
|
|
|
|
|
|
|
|
// Used for Async thread spinup and reaping
|
|
|
|
//WORK_QUEUE_ITEM m_Spinup; // Async-Thread-Spinup
|
|
|
|
WORK_QUEUE_ITEM m_Reaper;
|
|
|
|
|
|
|
|
BOOLEAN m_Exit;
|
|
|
|
BOOLEAN m_Initialized;
|
|
|
|
|
|
|
|
FxSystemThread(
|
|
|
|
__in PFX_DRIVER_GLOBALS FxDriverGlobals
|
|
|
|
);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Create the system thread in order to be able to service work items
|
|
|
|
//
|
|
|
|
// It is recommended this is done from the system process context
|
|
|
|
// since the thread's handle is available to the user mode process
|
|
|
|
// for a temporary window. XP and later supports OBJ_KERNELHANDLE, but
|
|
|
|
// DriverFrameworks must support W2K with the same binary.
|
|
|
|
//
|
|
|
|
// It is safe to call this at DriverEntry which is in the system process
|
|
|
|
// to create an initial driver thread, and this driver thread should be
|
|
|
|
// used for creating any child driver threads on demand by using
|
|
|
|
// Initialize(FxSystemThread* SpinupThread).
|
|
|
|
//
|
|
|
|
BOOLEAN
|
|
|
|
Initialize(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
_Must_inspect_result_
|
|
|
|
static
|
|
|
|
NTSTATUS
|
|
|
|
_CreateAndInit(
|
|
|
|
__deref_out FxSystemThread** SystemThread,
|
|
|
|
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
|
|
|
__in WDFDEVICE Device,
|
|
|
|
__in MdDeviceObject DeviceObject
|
|
|
|
);
|
|
|
|
|
|
|
|
virtual
|
|
|
|
~FxSystemThread(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// This is called to tell the thread to exit.
|
|
|
|
//
|
|
|
|
// It must be called from thread context such as
|
|
|
|
// the driver unload routine since it will wait for the
|
|
|
|
// thread to exit.
|
|
|
|
//
|
|
|
|
// A worker thread will not exit unless it has processed
|
|
|
|
// all of its queued work items. If processing of queued
|
|
|
|
// workitems is no longer desired, then use CancelWorkItem
|
|
|
|
// to remove the items before calling this method.
|
|
|
|
//
|
|
|
|
BOOLEAN
|
|
|
|
ExitThread(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
//
|
|
|
|
// This is called to tell the thread to exit.
|
|
|
|
//
|
|
|
|
// This may be called from any context since it
|
|
|
|
// only signals the thread to exit, and does not
|
|
|
|
// wait for it. It is safe to release the object
|
|
|
|
// reference when this routine returns.
|
|
|
|
//
|
|
|
|
// This routine requires an FxSystemThread* to perform
|
|
|
|
// final thread reaping. This allows a driver to ensure that
|
|
|
|
// child threads have exited by waiting on their object pointer,
|
|
|
|
// before exiting a top level driver thread.
|
|
|
|
//
|
|
|
|
// This is required since a frameworks object that contains a
|
|
|
|
// system thread can be dereferenced, and thus destroyed
|
|
|
|
// in any context, so waiting may not be available. But unless
|
|
|
|
// a wait is done on the thread object pointer, no guarantee can be
|
|
|
|
// made that the thread has actually run and exited before
|
|
|
|
// the drivers code get unloaded, resulting in a system crash.
|
|
|
|
//
|
|
|
|
// Top level threads, such as the reaper, are exited using the
|
|
|
|
// ExitThread() synchronous call that waits for it to exit. This
|
|
|
|
// can be done in synchronous thread context such as DriverUnload
|
|
|
|
// time.
|
|
|
|
//
|
|
|
|
// If Synchronous threading is configured in the frameworks, the
|
|
|
|
// FxDriver object always contains a top level worker thread that
|
|
|
|
// may be used as the reaper, and DriverUnload synchronously waits
|
|
|
|
// for this thread to finish processing its work queue before
|
|
|
|
// exiting.
|
|
|
|
//
|
|
|
|
// A worker thread will not exit unless it has processed
|
|
|
|
// all of its queued work items. If processing of queued
|
|
|
|
// workitems is no longer desired, then use CancelWorkItem
|
|
|
|
// to remove the items before calling this method.
|
|
|
|
//
|
|
|
|
BOOLEAN
|
|
|
|
ExitThreadAsync(
|
|
|
|
__inout FxSystemThread* Reaper
|
|
|
|
);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Queue a work item to the thread
|
|
|
|
//
|
|
|
|
// It is valid to queue work items before thread
|
|
|
|
// Initialize()/Initialize(FxSystemThread*) is called. The items
|
|
|
|
// remain queued until the system thread is started.
|
|
|
|
//
|
|
|
|
BOOLEAN
|
|
|
|
QueueWorkItem(
|
|
|
|
__inout PWORK_QUEUE_ITEM WorkItem
|
|
|
|
);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Attempt to cancel the work item.
|
|
|
|
//
|
|
|
|
// Returns TRUE if success.
|
|
|
|
//
|
|
|
|
// If returns FALSE, the work item
|
|
|
|
// routine either has been called, is running,
|
|
|
|
// or is about to be called.
|
|
|
|
//
|
|
|
|
BOOLEAN
|
|
|
|
CancelWorkItem(
|
|
|
|
__inout PWORK_QUEUE_ITEM WorkItem
|
|
|
|
);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Determine if current thread is this
|
|
|
|
// worker thread
|
|
|
|
//
|
|
|
|
__inline
|
|
|
|
BOOLEAN
|
|
|
|
IsCurrentThread()
|
|
|
|
{
|
|
|
|
return (Mx::GetCurrentEThread() == m_PEThread) ? TRUE : FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
DECLARE_INTERNAL_NEW_OPERATOR();
|
|
|
|
|
|
|
|
#ifdef INLINE_WRAPPER_ALLOCATION
|
|
|
|
#if (FX_CORE_MODE==FX_CORE_USER_MODE)
|
|
|
|
FORCEINLINE
|
|
|
|
PVOID
|
|
|
|
GetCOMWrapper(
|
|
|
|
)
|
|
|
|
{
|
|
|
|
PBYTE ptr = (PBYTE) this;
|
|
|
|
return (ptr + (USHORT) WDF_ALIGN_SIZE_UP(sizeof(*this), MEMORY_ALLOCATION_ALIGNMENT));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
//
|
|
|
|
// This is the thread's main processing function
|
|
|
|
//
|
|
|
|
VOID
|
|
|
|
Thread(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// This is the reaper method
|
|
|
|
//
|
|
|
|
VOID
|
|
|
|
Reaper(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
_Must_inspect_result_
|
|
|
|
NTSTATUS
|
|
|
|
CreateThread(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
//
|
|
|
|
// This is the thunk used to get from the system
|
|
|
|
// thread start callback into this class
|
|
|
|
//
|
|
|
|
static
|
|
|
|
VOID
|
2020-10-16 03:30:51 +00:00
|
|
|
STDCALL
|
2020-09-24 20:51:15 +00:00
|
|
|
StaticThreadThunk(
|
|
|
|
__inout PVOID Context
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// This thunk is called from the workitem in another
|
|
|
|
// thread that is reaping this thread
|
|
|
|
//
|
|
|
|
static
|
|
|
|
VOID
|
2020-10-16 03:30:51 +00:00
|
|
|
STDCALL
|
2020-09-24 20:51:15 +00:00
|
|
|
StaticReaperThunk(
|
|
|
|
__inout PVOID Context
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif // _FXSYSTEMTHREAD_H_
|