Beispiel #1
0
VOID
NTAPI
WorkItemRoutine(
    IN PVOID Context)
{
    PKSIWORKER KsWorker;
    KIRQL OldLevel;
    PWORK_QUEUE_ITEM WorkItem;
    PLIST_ENTRY Entry;


    /* get ks worker implementation */
    KsWorker = (PKSIWORKER)Context;

    /* acquire back the lock */
    KeAcquireSpinLock(&KsWorker->Lock, &OldLevel);

    do
    {
        /* sanity check */
        ASSERT(!IsListEmpty(&KsWorker->QueuedWorkItems));

        /* remove first entry */
        Entry = RemoveHeadList(&KsWorker->QueuedWorkItems);
        /* get offset to work item */
        WorkItem = (PWORK_QUEUE_ITEM)CONTAINING_RECORD(Entry, WORK_QUEUE_ITEM, List);

        /* release lock as the callback might call one KsWorker functions */
        KeReleaseSpinLock(&KsWorker->Lock, OldLevel);

        /*  now dispatch the work */
        WorkItem->WorkerRoutine(WorkItem->Parameter);

        /* acquire back the lock */
        KeAcquireSpinLock(&KsWorker->Lock, &OldLevel);

        /* decrement queued work item count */
        InterlockedDecrement(&KsWorker->QueuedWorkItemCount);

    }while(KsWorker->QueuedWorkItemCount);

    /* release the lock */
    KeReleaseSpinLock(&KsWorker->Lock, OldLevel);

    /* signal completion event */
    KeSetEvent(&KsWorker->Event, IO_NO_INCREMENT, FALSE);

}
Beispiel #2
0
VOID
NTAPI
PopProcessShutDownLists(VOID)
{
    PPOP_SHUTDOWN_WAIT_ENTRY ShutDownWaitEntry;
    PWORK_QUEUE_ITEM WorkItem;
    PLIST_ENTRY ListEntry;

    /* First signal the shutdown event */
    KeSetEvent(&PopShutdownEvent, IO_NO_INCREMENT, FALSE);

    /* Acquire the shutdown list lock */
    KeAcquireGuardedMutex(&PopShutdownListMutex);

    /* Block any further attempts to register a shutdown event */
    PopShutdownListAvailable = FALSE;

    /* Release the list lock, since we are exclusively using the lists now */
    KeReleaseGuardedMutex(&PopShutdownListMutex);

    /* Process the shutdown queue */
    while (!IsListEmpty(&PopShutdownQueue))
    {
        /* Get the head entry */
        ListEntry = RemoveHeadList(&PopShutdownQueue);
        WorkItem = CONTAINING_RECORD(ListEntry, WORK_QUEUE_ITEM, List);

        /* Call the shutdown worker routine */
        WorkItem->WorkerRoutine(WorkItem->Parameter);
    }

    /* Now process the shutdown thread list */
    while (PopShutdownThreadList != NULL)
    {
        /* Get the top entry and remove it from the list */
        ShutDownWaitEntry = PopShutdownThreadList;
        PopShutdownThreadList = PopShutdownThreadList->NextEntry;

        /* Wait for the thread to finish and dereference it */
        KeWaitForSingleObject(ShutDownWaitEntry->Thread, 0, 0, 0, 0);
        ObfDereferenceObject(ShutDownWaitEntry->Thread);

        /* Finally free the entry */
        ExFreePoolWithTag(ShutDownWaitEntry, 0);
    }
}
Beispiel #3
0
/*++
 * @name ExpWorkerThreadEntryPoint
 *
 *     The ExpWorkerThreadEntryPoint routine is the entrypoint for any new
 *     worker thread created by teh system.
 *
 * @param Context
 *        Contains the work queue type masked with a flag specifing whether the
 *        thread is dynamic or not.
 *
 * @return None.
 *
 * @remarks A dynamic thread can timeout after 10 minutes of waiting on a queue
 *          while a static thread will never timeout.
 *
 *          Worker threads must return at IRQL == PASSIVE_LEVEL, must not have
 *          active impersonation info, and must not have disabled APCs.
 *
 *          NB: We will re-enable APCs for broken threads but all other cases
 *              will generate a bugcheck.
 *
 *--*/
VOID
NTAPI
ExpWorkerThreadEntryPoint(IN PVOID Context)
{
    PWORK_QUEUE_ITEM WorkItem;
    PLIST_ENTRY QueueEntry;
    WORK_QUEUE_TYPE WorkQueueType;
    PEX_WORK_QUEUE WorkQueue;
    LARGE_INTEGER Timeout;
    PLARGE_INTEGER TimeoutPointer = NULL;
    PETHREAD Thread = PsGetCurrentThread();
    KPROCESSOR_MODE WaitMode;
    EX_QUEUE_WORKER_INFO OldValue, NewValue;

    /* Check if this is a dyamic thread */
    if ((ULONG_PTR)Context & EX_DYNAMIC_WORK_THREAD)
    {
        /* It is, which means we will eventually time out after 10 minutes */
        Timeout.QuadPart = Int32x32To64(10, -10000000 * 60);
        TimeoutPointer = &Timeout;
    }

    /* Get Queue Type and Worker Queue */
    WorkQueueType = (WORK_QUEUE_TYPE)((ULONG_PTR)Context &
                                      ~EX_DYNAMIC_WORK_THREAD);
    WorkQueue = &ExWorkerQueue[WorkQueueType];

    /* Select the wait mode */
    WaitMode = (UCHAR)WorkQueue->Info.WaitMode;

    /* Nobody should have initialized this yet, do it now */
    ASSERT(Thread->ExWorkerCanWaitUser == 0);
    if (WaitMode == UserMode) Thread->ExWorkerCanWaitUser = TRUE;

    /* If we shouldn't swap, disable that feature */
    if (!ExpWorkersCanSwap) KeSetKernelStackSwapEnable(FALSE);

    /* Set the worker flags */
    do
    {
        /* Check if the queue is being disabled */
        if (WorkQueue->Info.QueueDisabled)
        {
            /* Re-enable stack swapping and kill us */
            KeSetKernelStackSwapEnable(TRUE);
            PsTerminateSystemThread(STATUS_SYSTEM_SHUTDOWN);
        }

        /* Increase the worker count */
        OldValue = WorkQueue->Info;
        NewValue = OldValue;
        NewValue.WorkerCount++;
    }
    while (InterlockedCompareExchange((PLONG)&WorkQueue->Info,
                                      *(PLONG)&NewValue,
                                      *(PLONG)&OldValue) != *(PLONG)&OldValue);

    /* Success, you are now officially a worker thread! */
    Thread->ActiveExWorker = TRUE;

    /* Loop forever */
ProcessLoop:
    for (;;)
    {
        /* Wait for Something to Happen on the Queue */
        QueueEntry = KeRemoveQueue(&WorkQueue->WorkerQueue,
                                   WaitMode,
                                   TimeoutPointer);

        /* Check if we timed out and quit this loop in that case */
        if ((NTSTATUS)(ULONG_PTR)QueueEntry == STATUS_TIMEOUT) break;

        /* Increment Processed Work Items */
        InterlockedIncrement((PLONG)&WorkQueue->WorkItemsProcessed);

        /* Get the Work Item */
        WorkItem = CONTAINING_RECORD(QueueEntry, WORK_QUEUE_ITEM, List);

        /* Make sure nobody is trying to play smart with us */
        ASSERT((ULONG_PTR)WorkItem->WorkerRoutine > MmUserProbeAddress);

        /* Call the Worker Routine */
        WorkItem->WorkerRoutine(WorkItem->Parameter);

        /* Make sure APCs are not disabled */
        if (Thread->Tcb.SpecialApcDisable)
        {
            /* We're nice and do it behind your back */
            DPRINT1("Warning: Broken Worker Thread: %p %lx %p came back "
                    "with APCs disabled!\n",
                    WorkItem->WorkerRoutine,
                    WorkItem->Parameter,
                    WorkItem);
            Thread->Tcb.SpecialApcDisable = 0;
        }

        /* Make sure it returned at right IRQL */
        if (KeGetCurrentIrql() != PASSIVE_LEVEL)
        {
            /* It didn't, bugcheck! */
            KeBugCheckEx(WORKER_THREAD_RETURNED_AT_BAD_IRQL,
                         (ULONG_PTR)WorkItem->WorkerRoutine,
                         KeGetCurrentIrql(),
                         (ULONG_PTR)WorkItem->Parameter,
                         (ULONG_PTR)WorkItem);
        }

        /* Make sure it returned with Impersionation Disabled */
        if (Thread->ActiveImpersonationInfo)
        {
            /* It didn't, bugcheck! */
            KeBugCheckEx(IMPERSONATING_WORKER_THREAD,
                         (ULONG_PTR)WorkItem->WorkerRoutine,
                         (ULONG_PTR)WorkItem->Parameter,
                         (ULONG_PTR)WorkItem,
                         0);
        }
    }

    /* This is a dynamic thread. Terminate it unless IRPs are pending */
    if (!IsListEmpty(&Thread->IrpList)) goto ProcessLoop;

    /* Don't terminate it if the queue is disabled either */
    if (WorkQueue->Info.QueueDisabled) goto ProcessLoop;

    /* Set the worker flags */
    do
    {
        /* Decrease the worker count */
        OldValue = WorkQueue->Info;
        NewValue = OldValue;
        NewValue.WorkerCount--;
    }
    while (InterlockedCompareExchange((PLONG)&WorkQueue->Info,
                                      *(PLONG)&NewValue,
                                      *(PLONG)&OldValue) != *(PLONG)&OldValue);

    /* Decrement dynamic thread count */
    InterlockedDecrement(&WorkQueue->DynamicThreadCount);

    /* We're not a worker thread anymore */
    Thread->ActiveExWorker = FALSE;

    /* Re-enable the stack swap */
    KeSetKernelStackSwapEnable(TRUE);
    return;
}
Beispiel #4
-1
/*
 * @implemented
 */
VOID
NTAPI
FsRtlWorkerThread(IN PVOID StartContext)
{
    KIRQL Irql;
    PLIST_ENTRY Entry;
    PWORK_QUEUE_ITEM WorkItem;
    ULONG QueueId = (ULONG)StartContext;

    /* Set our priority according to the queue we're dealing with */
    KeSetPriorityThread(&PsGetCurrentThread()->Tcb, LOW_REALTIME_PRIORITY + QueueId);

    /* Loop for events */
    for (;;)
    {
        /* Look for next event */
        Entry = KeRemoveQueue(&FsRtlWorkerQueues[QueueId], KernelMode, NULL);
        WorkItem = CONTAINING_RECORD(Entry, WORK_QUEUE_ITEM, List);

        /* Call its routine (here: FsRtlStackOverflowRead) */
        WorkItem->WorkerRoutine(WorkItem->Parameter);

        /* Check we're still at passive level or bugcheck */
        Irql = KeGetCurrentIrql();
        if (Irql != PASSIVE_LEVEL)
        {
            KeBugCheckEx(IRQL_NOT_LESS_OR_EQUAL, (ULONG_PTR)WorkItem->WorkerRoutine,   
                         (ULONG_PTR)Irql, (ULONG_PTR)WorkItem->WorkerRoutine,
                         (ULONG_PTR)WorkItem);
        }
    }
}