/*++

Copyright (c) 2012 Minoca Corp. All Rights Reserved

Module Name:

    workitem.c

Abstract:

    This module handles kernel work items.

Author:

    Evan Green 12-Sep-2012

Environment:

    Kernel

--*/

//
// ------------------------------------------------------------------- Includes
//

#include <minoca/kernel/kernel.h>
#include "kep.h"

//
// ---------------------------------------------------------------- Definitions
//

//
// Define work item crash codes.
//

#define WORK_ITEM_CRASH_MODIFY_QUEUED_ITEM 0x1
#define WORK_ITEM_CRASH_BAD_QUEUE_STATE 0x2

//
// Work item flags.
//

//
// This bit is set when the work item is actively in a queue. It cannot be
// used directly to prevent double-queuing, as it is subject to multiprocessor
// races if used that way.
//

#define WORK_ITEM_FLAG_QUEUED 0x00000001

//
// This bit is set if the work item can be added to a queue or destroyed at
// dispatch level. It is automatically inherited from the queue flags if the
// queue is set to support dispatch level.
//

#define WORK_ITEM_FLAG_SUPPORT_DISPATCH_LEVEL 0x00000002

//
// ------------------------------------------------------ Data Type Definitions
//

/*++

Structure Description:

    This structure defines a work queue.

Members:

    State - Stoers a pointer to the current work queue state.

    Lock - Stores either a pointer to a queued lock or a spin lock protecting
        the work item list, depending on whether the queue needs to accept
        work items at dispatch level.

    WorkItemListHead - Stores the head of the list of work items to execute.

    WorkItemCount - Stores the number of work items currently queued.

    Event - Stores a pointer to the event used to kick the work item threads
        into action.

    Flags - Stores a bitfield of flags governing the behavior of the work
        queue. See WORK_QUEUE_FLAG_* definitions.

    CurrentThreadCount - Stores the number of threads that are alive and
        processing (or waiting on) the work queue.

    Name - Stores a pointer to a string containing the name of the worker
        threads.

--*/

struct _WORK_QUEUE {
    volatile WORK_QUEUE_STATE State;
    union {
        PQUEUED_LOCK QueuedLock;
        KSPIN_LOCK SpinLock;
    } Lock;

    LIST_ENTRY WorkItemListHead;
    UINTN WorkItemCount;
    PKEVENT Event;
    ULONG Flags;
    volatile ULONG CurrentThreadCount;
    PSTR Name;
};

/*++

Structure Description:

    This structure defines a work item, to be performed by a worker thread at
    low level.

Members:

    ListEntry - Stores pointers to the next and previous work items in the
        work queue. The work queue is sorted by priority.

    ReferenceCount - Stores the reference count of the work item.

    Queue - Stores a pointer to the queue this work item was or will be
        put on.

    Event - Stores a pointer to an event that is signaled when the work item
        completes.

    Routine - Stores the worker routine.

    Parameter - Stores the parameter to pass to the worker routine.

    Priority - Stores the priority of the work item.

    Flags - Stores a pointer to internal flags used by the operating system.
        Do not modify these directly. See WORK_ITEM_FLAG_* definitions.

--*/

struct _WORK_ITEM {
    LIST_ENTRY ListEntry;
    UINTN ReferenceCount;
    PWORK_QUEUE Queue;
    PKEVENT Event;
    PWORK_ITEM_ROUTINE Routine;
    PVOID Parameter;
    WORK_PRIORITY Priority;
    ULONG Flags;
};

//
// ----------------------------------------------- Internal Function Prototypes
//

VOID
KepWorkerThread (
    );

VOID
KepDestroyWorkQueue (
    PWORK_QUEUE Queue
    );

VOID
KepWorkItemAddReference (
    PWORK_ITEM WorkItem
    );

VOID
KepWorkItemReleaseReference (
    PWORK_ITEM WorkItem
    );

//
// -------------------------------------------------------------------- Globals
//

//
// Store a pointer to the system work queue.
//

PWORK_QUEUE KeSystemWorkQueue = NULL;

//
// ------------------------------------------------------------------ Functions
//

KERNEL_API
PWORK_QUEUE
KeCreateWorkQueue (
    ULONG Flags,
    PSTR Name
    )

/*++

Routine Description:

    This routine creates a new work queue.

Arguments:

    Flags - Supplies a bitfield of flags governing the behavior of the work
        queue. See WORK_QUEUE_FLAG_* definitions.

    Name - Supplies an optional pointer to the name of the worker threads
        created. A copy of this memory will be made. This should only be used
        for debugging, as text may be added to the end of the name supplied
        here to the actual worker thread names.

Return Value:

    Returns a pointer to the new work queue on success.

    NULL on failure.

--*/

{

    ULONG NameSize;
    BOOL NonPaged;
    PWORK_QUEUE Queue;
    KSTATUS Status;

    //
    // Parse the flags.
    //

    NonPaged = FALSE;
    if ((Flags & WORK_QUEUE_FLAG_SUPPORT_DISPATCH_LEVEL) != 0) {
        NonPaged = TRUE;
    }

    //
    // Create and initialize the work queue structure.
    //

    if (NonPaged != FALSE) {
        Queue = MmAllocateNonPagedPool(sizeof(WORK_QUEUE), KE_ALLOCATION_TAG);

    } else {
        Queue = MmAllocatePagedPool(sizeof(WORK_QUEUE), KE_ALLOCATION_TAG);
    }

    if (Queue == NULL) {
        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto CreateWorkQueueEnd;
    }

    RtlZeroMemory(Queue, sizeof(WORK_QUEUE));

    //
    // Create a copy of the name, if supplied.
    //

    if (Name != NULL) {
        NameSize = RtlStringLength(Name) + 1;
        Queue->Name = MmAllocatePagedPool(NameSize, KE_ALLOCATION_TAG);
        if (Queue->Name == NULL) {
            Status = STATUS_INSUFFICIENT_RESOURCES;
            goto CreateWorkQueueEnd;
        }

        RtlStringCopy(Queue->Name, Name, NameSize);
    }

    if (NonPaged != FALSE) {
        KeInitializeSpinLock(&(Queue->Lock.SpinLock));

    } else {
        Queue->Lock.QueuedLock = KeCreateQueuedLock();
        if (Queue->Lock.QueuedLock == NULL) {
            Status = STATUS_INSUFFICIENT_RESOURCES;
            goto CreateWorkQueueEnd;
        }
    }

    INITIALIZE_LIST_HEAD(&(Queue->WorkItemListHead));
    Queue->Event = KeCreateEvent(NULL);
    if (Queue->Event == NULL) {
        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto CreateWorkQueueEnd;
    }

    Queue->Flags = Flags;
    Queue->State = WorkQueueStateOpen;

    //
    // Create a worker thread.
    //

    Status = PsCreateKernelThread(KepWorkerThread, Queue, Name);
    if (!KSUCCESS(Status)) {
        goto CreateWorkQueueEnd;
    }

    Status = STATUS_SUCCESS;

CreateWorkQueueEnd:
    if (!KSUCCESS(Status)) {
        if (Queue != NULL) {
            if (Queue->Name != NULL) {
                MmFreePagedPool(Queue->Name);
            }

            if (NonPaged == FALSE) {
                if (Queue->Lock.QueuedLock != NULL) {
                    KeDestroyQueuedLock(Queue->Lock.QueuedLock);
                }
            }

            if (Queue->Event != NULL) {
                KeDestroyEvent(Queue->Event);
            }

            if (NonPaged != FALSE) {
                MmFreeNonPagedPool(Queue);

            } else {
                MmFreePagedPool(Queue);
            }

            Queue = NULL;
        }
    }

    return Queue;
}

KERNEL_API
VOID
KeDestroyWorkQueue (
    PWORK_QUEUE WorkQueue
    )

/*++

Routine Description:

    This routine destroys a work queue. If there are items on the work queue,
    they will be completed.

Arguments:

    WorkQueue - Supplies a pointer to the work queue to destroy.

Return Value:

    None.

--*/

{

    BOOL DispatchLevel;
    RUNLEVEL OldRunLevel;

    OldRunLevel = RunLevelCount;

    ASSERT((WorkQueue->State != WorkQueueStateInvalid) &&
           (WorkQueue->State != WorkQueueStateDestroying) &&
           (WorkQueue->State != WorkQueueStateDestroyed));

    DispatchLevel = FALSE;
    if ((WorkQueue->Flags & WORK_QUEUE_FLAG_SUPPORT_DISPATCH_LEVEL) != 0) {
        DispatchLevel = TRUE;
    }

    if (DispatchLevel != FALSE) {
        OldRunLevel = KeRaiseRunLevel(RunLevelDispatch);
    }

    //
    // Indicate to the worker threads that a transition is occurring. This
    // routine cannot just set the state directly to destroying because if the
    // thread happens to see that and deletes the queue before this routine
    // gets around to signalling the event, this routine will touch freed
    // memory. The signal event routine must be called because the queues might
    // be asleep from inactivity. So move to this transitory state where the
    // queues know to stay awake but spin waiting for the state to move to
    // destroying.
    //

    WorkQueue->State = WorkQueueStateWakingForDestroying;
    KeSignalEvent(WorkQueue->Event, SignalOptionSignalAll);

    //
    // Now that all workers are awake and spinning, let them destroy themselves.
    // Muah.
    //

    WorkQueue->State = WorkQueueStateDestroying;
    if (DispatchLevel != FALSE) {
        KeLowerRunLevel(OldRunLevel);
    }

    return;
}

KERNEL_API
VOID
KeFlushWorkQueue (
    PWORK_QUEUE WorkQueue
    )

/*++

Routine Description:

    This routine flushes a work queue. If there are items on the work queue,
    they will be completed before this routine returns.

Arguments:

    WorkQueue - Supplies a pointer to the work queue to flush.

Return Value:

    None.

--*/

{

    BOOL DispatchLevel;
    RUNLEVEL OldRunLevel;
    PWORK_ITEM Sentinal;

    ASSERT(KeGetRunLevel() <= RunLevelDispatch);

    OldRunLevel = RunLevelCount;
    if (WorkQueue == NULL) {
        WorkQueue = KeSystemWorkQueue;
    }

    ASSERT(WorkQueue != NULL);
    ASSERT((WorkQueue->State != WorkQueueStateInvalid) &&
           (WorkQueue->State != WorkQueueStateDestroying) &&
           (WorkQueue->State != WorkQueueStateDestroyed));

    DispatchLevel = FALSE;
    if ((WorkQueue->Flags & WORK_QUEUE_FLAG_SUPPORT_DISPATCH_LEVEL) != 0) {
        DispatchLevel = TRUE;
    }

    //
    // Acquire the queue's lock at the appropriate run level.
    //

    if (DispatchLevel != FALSE) {
        OldRunLevel = KeRaiseRunLevel(RunLevelDispatch);
        KeAcquireSpinLock(&(WorkQueue->Lock.SpinLock));

    } else {
        KeAcquireQueuedLock(WorkQueue->Lock.QueuedLock);
    }

    //
    // If the queue is empty, then there is no sentinal to record and no work
    // to do.
    //

    if (LIST_EMPTY(&(WorkQueue->WorkItemListHead)) != FALSE) {
        Sentinal = NULL;

    //
    // Otherwise, record the last item in the work queue and signal the worker
    // threads.
    //

    } else {
        Sentinal = (PWORK_ITEM)LIST_VALUE(WorkQueue->WorkItemListHead.Previous,
                                          WORK_ITEM,
                                          ListEntry);

        ASSERT(Sentinal != NULL);

        KeSignalEvent(WorkQueue->Event, SignalOptionSignalAll);
    }

    //
    // Unlock the list to let work proceed.
    //

    if (DispatchLevel != FALSE) {
        KeReleaseSpinLock(&(WorkQueue->Lock.SpinLock));
        KeLowerRunLevel(OldRunLevel);

    } else {
        KeReleaseQueuedLock(WorkQueue->Lock.QueuedLock);
    }

    //
    // If there is a sentinal, wait on it to complete.
    //

    if (Sentinal != NULL) {
        KeWaitForEvent(Sentinal->Event, FALSE, WAIT_TIME_INDEFINITE);
    }

    return;
}

KERNEL_API
PWORK_ITEM
KeCreateWorkItem (
    PWORK_QUEUE WorkQueue,
    WORK_PRIORITY Priority,
    PWORK_ITEM_ROUTINE WorkRoutine,
    PVOID Parameter,
    ULONG AllocationTag
    )

/*++

Routine Description:

    This routine creates a new reusable work item.

Arguments:

    WorkQueue - Supplies a pointer to the queue this work item will
        eventually be queued to. Supply NULL to use the system work queue.

    Priority - Supplies the work priority.

    WorkRoutine - Supplies the routine to execute to do the work. This routine
        should be prepared to take one parameter.

    Parameter - Supplies an optional parameter to pass to the worker routine.

    AllocationTag - Supplies an allocation tag to associate with the work item.

Return Value:

    Returns a pointer to the new work item on success.

    NULL on failure.

--*/

{

    PWORK_ITEM NewWorkItem;
    BOOL NonPaged;
    KSTATUS Status;

    ASSERT(KeGetRunLevel() <= RunLevelDispatch);

    NewWorkItem = NULL;
    if ((Priority < WorkPriorityNormal) || (Priority > WorkPriorityHigh) ||
        (WorkRoutine == NULL)) {

        Status = STATUS_INVALID_PARAMETER;
        goto CreateWorkItemEnd;
    }

    //
    // If no work queue was specified, use the system work queue.
    //

    if (WorkQueue == NULL) {
        WorkQueue = KeSystemWorkQueue;
    }

    NonPaged = FALSE;
    if ((WorkQueue->Flags & WORK_QUEUE_FLAG_SUPPORT_DISPATCH_LEVEL) != 0) {
        NonPaged = TRUE;
    }

    //
    // Allocate space for a work item.
    //

    if (NonPaged != FALSE) {
        NewWorkItem = MmAllocateNonPagedPool(sizeof(WORK_ITEM), AllocationTag);

    } else {
        NewWorkItem = MmAllocatePagedPool(sizeof(WORK_ITEM), AllocationTag);
    }

    if (NewWorkItem == NULL) {
        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto CreateWorkItemEnd;
    }

    RtlZeroMemory(NewWorkItem, sizeof(WORK_ITEM));
    NewWorkItem->ReferenceCount = 1;

    //
    // If the work queue has to support dispatch level, then the work item
    // needs to as well.
    //

    if (NonPaged != FALSE) {
        NewWorkItem->Flags |= WORK_ITEM_FLAG_SUPPORT_DISPATCH_LEVEL;
    }

    //
    // Initialize the rest of the work item. With the above flag set the
    // destroy routine can be used if things do not work out.
    //

    KeSetWorkItemParameters(NewWorkItem, Priority, WorkRoutine, Parameter);
    NewWorkItem->Queue = WorkQueue;
    NewWorkItem->Event = KeCreateEvent(NULL);
    if (NewWorkItem->Event == NULL) {
        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto CreateWorkItemEnd;
    }

    KeSignalEvent(NewWorkItem->Event, SignalOptionSignalAll);
    Status = STATUS_SUCCESS;

CreateWorkItemEnd:
    if (!KSUCCESS(Status)) {
        if (NewWorkItem != NULL) {
            KeDestroyWorkItem(NewWorkItem);
            NewWorkItem = NULL;
        }
    }

    return NewWorkItem;
}

KERNEL_API
VOID
KeDestroyWorkItem (
    PWORK_ITEM WorkItem
    )

/*++

Routine Description:

    This routine destroys a reusable work item. If this is a work item that
    can re-queue itself, then the caller needs to make sure that that can no
    longer happen before trying to destroy the work item.

Arguments:

    WorkItem - Supplies a pointer to the work item.

Return Value:

    None.

--*/

{

    //
    // Always attempt to cancel the work item.
    //

    KeCancelWorkItem(WorkItem);
    KepWorkItemReleaseReference(WorkItem);
    return;
}

KERNEL_API
KSTATUS
KeCancelWorkItem (
    PWORK_ITEM WorkItem
    )

/*++

Routine Description:

    This routine attempts to cancel the work item. If the work item is still on
    its work queue then this routine will pull it off and return successfully.
    Otherwise the work item may have been selected to run and this routine will
    return that the cancel was too late. Keep in mind that "too late" may also
    mean "too early" if the work item was never queued.

Arguments:

    WorkItem - Supplies a pointer to the work item to cancel.

Return Value:

    Status code.

--*/

{

    BOOL DispatchLevel;
    RUNLEVEL OldRunLevel;
    PWORK_QUEUE Queue;
    KSTATUS Status;

    OldRunLevel = RunLevelCount;

    ASSERT(KeGetRunLevel() <= RunLevelDispatch);

    //
    // Quickly return "too late" if the work item is not queued. It may be
    // about to run or running, or it might not have been queued.
    //

    if ((WorkItem->Flags & WORK_ITEM_FLAG_QUEUED) == 0) {
        return STATUS_TOO_LATE;
    }

    //
    // If the queue is not in a state to cancel a work item. Crash.
    //

    Queue = WorkItem->Queue;
    if ((Queue->State != WorkQueueStateOpen) &&
        (Queue->State != WorkQueueStatePaused)) {

        KeCrashSystem(CRASH_WORK_ITEM_CORRUPTION,
                      WORK_ITEM_CRASH_BAD_QUEUE_STATE,
                      (UINTN)WorkItem,
                      (UINTN)Queue,
                      Queue->State);
    }

    //
    // Determine whether or not to raise to dispatch level before acquiring
    // the lock.
    //

    DispatchLevel = FALSE;
    if ((Queue->Flags & WORK_QUEUE_FLAG_SUPPORT_DISPATCH_LEVEL) != 0) {
        DispatchLevel = TRUE;
    }

    //
    // Acquire the work queue lock.
    //

    if (DispatchLevel != FALSE) {
        OldRunLevel = KeRaiseRunLevel(RunLevelDispatch);
        KeAcquireSpinLock(&(Queue->Lock.SpinLock));

    } else {
        KeAcquireQueuedLock(Queue->Lock.QueuedLock);
    }

    //
    // Now that the lock is held, check again to see if the work item was
    // selected to run and pulled off the list.
    //

    if ((WorkItem->Flags & WORK_ITEM_FLAG_QUEUED) == 0) {
        WorkItem = NULL;
        Status = STATUS_TOO_LATE;
        goto CancelWorkItemEnd;
    }

    ASSERT((WorkItem->Flags & WORK_ITEM_FLAG_QUEUED) != 0);
    ASSERT(WorkItem->ListEntry.Next != NULL);

    //
    // Remove the work item from the queue, signal it, and return successfully.
    //

    LIST_REMOVE(&(WorkItem->ListEntry));
    WorkItem->ListEntry.Next = NULL;
    Queue->WorkItemCount -= 1;
    WorkItem->Flags &= ~WORK_ITEM_FLAG_QUEUED;
    KeSignalEvent(WorkItem->Event, SignalOptionSignalAll);
    Status = STATUS_SUCCESS;

CancelWorkItemEnd:
    if (DispatchLevel != FALSE) {
        KeReleaseSpinLock(&(Queue->Lock.SpinLock));
        KeLowerRunLevel(OldRunLevel);

    } else {
        KeReleaseQueuedLock(Queue->Lock.QueuedLock);
    }

    if (WorkItem != NULL) {
        KepWorkItemReleaseReference(WorkItem);
    }

    return Status;
}

KERNEL_API
VOID
KeFlushWorkItem (
    PWORK_ITEM WorkItem
    )

/*++

Routine Description:

    This routine does not return until the given work item has completed.

Arguments:

    WorkItem - Supplies a pointer to the work item.

Return Value:

    None.

--*/

{

    KeWaitForEvent(WorkItem->Event, FALSE, WAIT_TIME_INDEFINITE);
    return;
}

KERNEL_API
VOID
KeSetWorkItemParameters (
    PWORK_ITEM WorkItem,
    WORK_PRIORITY Priority,
    PWORK_ITEM_ROUTINE WorkRoutine,
    PVOID Parameter
    )

/*++

Routine Description:

    This routine resets the parameters of a work item to the given parameters.
    The work item must not be queued. This routine must be called at or below
    dispatch level.

Arguments:

    WorkItem - Supplies a pointer to the work item to modify.

    Priority - Supplies the new work priority.

    WorkRoutine - Supplies the routine to execute to do the work. This routine
        should be prepared to take one parameter.

    Parameter - Supplies an optional parameter to pass to the worker routine.

Return Value:

    None.

--*/

{

    if ((WorkItem->Flags & WORK_ITEM_FLAG_QUEUED) != 0) {
        KeCrashSystem(CRASH_WORK_ITEM_CORRUPTION,
                      WORK_ITEM_CRASH_MODIFY_QUEUED_ITEM,
                      (UINTN)WorkItem,
                      (UINTN)WorkRoutine,
                      (UINTN)Parameter);
    }

    WorkItem->Priority = Priority;
    WorkItem->Routine = WorkRoutine;
    WorkItem->Parameter = Parameter;
    return;
}

KERNEL_API
KSTATUS
KeQueueWorkItem (
    PWORK_ITEM WorkItem
    )

/*++

Routine Description:

    This routine queues a work item onto the work queue for execution as soon
    as possible. This routine must be called from dispatch level or below.

Arguments:

    WorkItem - Supplies a pointer to the work item to queue.

Return Value:

    STATUS_SUCCESS on success.

    STATUS_RESOURCE_IN_USE if the work item is already queued.

--*/

{

    BOOL DispatchLevel;
    RUNLEVEL OldRunLevel;
    PWORK_QUEUE Queue;
    KSTATUS Status;

    OldRunLevel = RunLevelCount;

    ASSERT(KeGetRunLevel() <= RunLevelDispatch);

    if ((WorkItem->Flags & WORK_ITEM_FLAG_QUEUED) != 0) {
        return STATUS_RESOURCE_IN_USE;
    }

    Queue = WorkItem->Queue;
    if ((Queue->State != WorkQueueStateOpen) &&
        (Queue->State != WorkQueueStatePaused)) {

        KeCrashSystem(CRASH_WORK_ITEM_CORRUPTION,
                      WORK_ITEM_CRASH_BAD_QUEUE_STATE,
                      (UINTN)WorkItem,
                      (UINTN)Queue,
                      Queue->State);
    }

    //
    // Determine whether or not to raise to dispatch level before acquiring
    // the lock.
    //

    DispatchLevel = FALSE;
    if ((Queue->Flags & WORK_QUEUE_FLAG_SUPPORT_DISPATCH_LEVEL) != 0) {
        DispatchLevel = TRUE;
    }

    KepWorkItemAddReference(WorkItem);

    //
    // Acquire the work queue lock.
    //

    if (DispatchLevel != FALSE) {
        OldRunLevel = KeRaiseRunLevel(RunLevelDispatch);
        KeAcquireSpinLock(&(Queue->Lock.SpinLock));

    } else {
        KeAcquireQueuedLock(Queue->Lock.QueuedLock);
    }

    //
    // Now that the lock is held, check again to see if someone else snuck in
    // and queued this work item.
    //

    if ((WorkItem->Flags & WORK_ITEM_FLAG_QUEUED) != 0) {
        Status = STATUS_RESOURCE_IN_USE;
        goto QueueWorkItemEnd;
    }

    //
    // Mark the work item as having been queued now that the lock is held.
    //

    WorkItem->Flags |= WORK_ITEM_FLAG_QUEUED;
    KeSignalEvent(WorkItem->Event, SignalOptionUnsignal);

    //
    // Insert high priority items on the beginning of the list, and normal items
    // on the end.
    //

    if (WorkItem->Priority == WorkPriorityHigh) {
        INSERT_AFTER(&(WorkItem->ListEntry), &(Queue->WorkItemListHead));

    } else {
        INSERT_BEFORE(&(WorkItem->ListEntry), &(Queue->WorkItemListHead));
    }

    Queue->WorkItemCount += 1;
    WorkItem = NULL;
    Status = STATUS_SUCCESS;

QueueWorkItemEnd:
    if (DispatchLevel != FALSE) {
        KeReleaseSpinLock(&(Queue->Lock.SpinLock));
        KeLowerRunLevel(OldRunLevel);

    } else {
        KeReleaseQueuedLock(Queue->Lock.QueuedLock);
    }

    if (KSUCCESS(Status)) {

        //
        // Signal the event to kick off the worker threads.
        //

        KeSignalEvent(Queue->Event, SignalOptionSignalAll);
    }

    if (WorkItem != NULL) {
        KepWorkItemReleaseReference(WorkItem);
    }

    return Status;
}

KERNEL_API
KSTATUS
KeCreateAndQueueWorkItem (
    PWORK_QUEUE WorkQueue,
    WORK_PRIORITY Priority,
    PWORK_ITEM_ROUTINE WorkRoutine,
    PVOID Parameter
    )

/*++

Routine Description:

    This routine creates and queues a work item. This work item will get
    executed in a worker thread an arbitrary amount of time later. The work
    item will be automatically freed after the work routine is executed.

Arguments:

    WorkQueue - Supplies a pointer to the queue this work item will
        eventually be queued to. Supply NULL to use the system work queue.

    Priority - Supplies the work priority.

    WorkRoutine - Supplies the routine to execute to doe the work. This
        routine should be prepared to take one parameter.

    Parameter - Supplies an optional parameter to pass to the worker routine.

Return Value:

    STATUS_SUCCESS on success.

    STATUS_UNSUCCESSFUL on failure.

--*/

{

    KSTATUS Status;
    PWORK_ITEM WorkItem;

    //
    // Create the new work item, and set the flag to automatically free it.
    //

    WorkItem = KeCreateWorkItem(WorkQueue,
                                Priority,
                                WorkRoutine,
                                Parameter,
                                KE_WORK_ITEM_ALLOCATION_TAG);

    if (WorkItem == NULL) {
        return STATUS_UNSUCCESSFUL;
    }

    Status = KeQueueWorkItem(WorkItem);
    if (!KSUCCESS(Status)) {
        return Status;
    }

    //
    // Release the reference on the work item from when it was created, so that
    // after it runs it will automatically destroy itself.
    //

    KepWorkItemReleaseReference(WorkItem);
    return Status;
}

KSTATUS
KepInitializeSystemWorkQueue (
    VOID
    )

/*++

Routine Description:

    This routine initializes the system work queue. This must happen after the
    Object Manager initializes.

Arguments:

    None.

Return Value:

    Status code.

--*/

{

    ULONG Flags;

    Flags = WORK_QUEUE_FLAG_SUPPORT_DISPATCH_LEVEL;
    KeSystemWorkQueue = KeCreateWorkQueue(Flags, "KeWorker");
    if (KeSystemWorkQueue == NULL) {
        return STATUS_UNSUCCESSFUL;
    }

    return STATUS_SUCCESS;
}

//
// --------------------------------------------------------- Internal Functions
//

VOID
KepWorkerThread (
    PVOID Parameter
    )

/*++

Routine Description:

    This routine processes work items off of a work queue.

Arguments:

    Parameter - Supplies a pointer to a parameter that in this case contains a
        pointer to the work queue to service.

Return Value:

    None. Does not return.

--*/

{

    RUNLEVEL OldRunLevel;
    PWORK_QUEUE Queue;
    BOOL RaiseToDispatch;
    ULONG RemainingThreads;
    PWORK_ITEM WorkItem;

    OldRunLevel = RunLevelCount;
    Queue = (PWORK_QUEUE)Parameter;
    RtlAtomicAdd32(&(Queue->CurrentThreadCount), 1);
    RaiseToDispatch = FALSE;
    if ((Queue->Flags & WORK_QUEUE_FLAG_SUPPORT_DISPATCH_LEVEL) != 0) {
        RaiseToDispatch = TRUE;
    }

    while (TRUE) {

        //
        // Wait for the event, then process work items until none are left.
        //

        KeWaitForEvent(Queue->Event, FALSE, WAIT_TIME_INDEFINITE);
        while (TRUE) {
            WorkItem = NULL;
            if (RaiseToDispatch != FALSE) {
                OldRunLevel = KeRaiseRunLevel(RunLevelDispatch);
                KeAcquireSpinLock(&(Queue->Lock.SpinLock));

            } else {
                KeAcquireQueuedLock(Queue->Lock.QueuedLock);
            }

            if (LIST_EMPTY(&(Queue->WorkItemListHead)) == FALSE) {
                WorkItem = LIST_VALUE(Queue->WorkItemListHead.Next,
                                      WORK_ITEM,
                                      ListEntry);

                LIST_REMOVE(&(WorkItem->ListEntry));
                WorkItem->ListEntry.Next = NULL;
                Queue->WorkItemCount -= 1;
                WorkItem->Flags &= ~WORK_ITEM_FLAG_QUEUED;

            } else {
                KeSignalEvent(Queue->Event, SignalOptionUnsignal);
            }

            if (RaiseToDispatch != FALSE) {
                KeReleaseSpinLock(&(Queue->Lock.SpinLock));
                KeLowerRunLevel(OldRunLevel);

            } else {
                KeReleaseQueuedLock(Queue->Lock.QueuedLock);
            }

            //
            // If there is a work item, execute it.
            //

            if (WorkItem != NULL) {
                WorkItem->Routine(WorkItem->Parameter);
                KeSignalEvent(WorkItem->Event, SignalOptionSignalAll);
                KepWorkItemReleaseReference(WorkItem);

            //
            // If there was no work item, stop looking.
            //

            } else {
                break;
            }

            //
            // If the work queue became paused, stop processing events.
            //

            if (Queue->State == WorkQueueStatePaused) {
                break;
            }
        }

        //
        // If this thread happened to catch someone else marking this queue
        // for destruction, politely wait for that operation to complete and
        // avoid destroying the queue out from under it.
        //

        while (Queue->State == WorkQueueStateWakingForDestroying) {
            KeYield();
        }

        if (Queue->State == WorkQueueStateDestroying) {
            RemainingThreads = RtlAtomicAdd32(&(Queue->CurrentThreadCount), -1);

            //
            // If this is the last thread standing, turn out the lights by
            // destroying the work queue.
            //

            if (RemainingThreads == 1) {
                Queue->State = WorkQueueStateDestroyed;
                KepDestroyWorkQueue(Queue);
                break;
            }
        }
    }

    return;
}

VOID
KepDestroyWorkQueue (
    PWORK_QUEUE Queue
    )

/*++

Routine Description:

    This routine destroys and frees a work queue. This routine will be
    called automatically by the last worker thread to exit.

Arguments:

    Queue - Supplies a pointer to the queue to destroy.

Return Value:

    None.

--*/

{

    BOOL NonPaged;

    ASSERT(Queue->CurrentThreadCount == 0);

    NonPaged = FALSE;
    if ((Queue->Flags & WORK_QUEUE_FLAG_SUPPORT_DISPATCH_LEVEL) != 0) {
        NonPaged = TRUE;
    }

    if (Queue->Name != NULL) {
        MmFreePagedPool(Queue->Name);
    }

    if ((NonPaged != FALSE) && (Queue->Lock.QueuedLock != NULL)) {
        KeDestroyQueuedLock(Queue->Lock.QueuedLock);
    }

    if (Queue->Event != NULL) {
        KeDestroyEvent(Queue->Event);
    }

    if (NonPaged != FALSE) {
        MmFreeNonPagedPool(Queue);

    } else {
        MmFreePagedPool(Queue);
    }

    return;
}

VOID
KepWorkItemAddReference (
    PWORK_ITEM WorkItem
    )

/*++

Routine Description:

    This routine adds a reference to the given work item.

Arguments:

    WorkItem - Supplies a pointer to the work item to add a reference to.

Return Value:

    None.

--*/

{

    UINTN OldReferenceCount;

    OldReferenceCount = RtlAtomicAdd(&(WorkItem->ReferenceCount), 1);

    ASSERT((OldReferenceCount != 0) && (OldReferenceCount < 0x10000000));

    return;
}

VOID
KepWorkItemReleaseReference (
    PWORK_ITEM WorkItem
    )

/*++

Routine Description:

    This routine release the reference on a work item. If the reference count
    drops to zero, the work item will be destroyed.

Arguments:

    WorkItem - Supplies a pointer to the work item to release.

Return Value:

    None.

--*/

{

    BOOL NonPaged;
    UINTN OldReferenceCount;

    OldReferenceCount = RtlAtomicAdd(&(WorkItem->ReferenceCount), -1);

    ASSERT((OldReferenceCount != 0) && (OldReferenceCount < 0x10000000));

    if (OldReferenceCount == 1) {

        ASSERT((WorkItem->Flags & WORK_ITEM_FLAG_QUEUED) == 0);

        if (WorkItem->Event != NULL) {
            KeDestroyEvent(WorkItem->Event);
        }

        NonPaged = FALSE;
        if ((WorkItem->Flags & WORK_ITEM_FLAG_SUPPORT_DISPATCH_LEVEL) != 0) {
            NonPaged = TRUE;
        }

        if (NonPaged != FALSE) {
            MmFreeNonPagedPool(WorkItem);

        } else {
            MmFreePagedPool(WorkItem);
        }
    }

    return;
}

