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); }
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); } }
/*++ * @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; }
/* * @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); } } }