/*++

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_