reactos/sdk/lib/drivers/wdf/shared/inc/private/common/fxsystemthread.hpp

292 lines
5.9 KiB
C++
Raw Normal View History

/*++
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
STDCALL
StaticThreadThunk(
__inout PVOID Context
);
//
// This thunk is called from the workitem in another
// thread that is reaping this thread
//
static
VOID
STDCALL
StaticReaperThunk(
__inout PVOID Context
);
};
#endif // _FXSYSTEMTHREAD_H_