// Kernel passive-level work queue. This file owns the generic mechanism used // to move ISR/DPC-originated work to a sleepable system thread context. #include #include #include #include #include #include #include #include #include #include static SPINLOCK gWorkQueueLock = SPINLOCK_INIT; static LIST_ENTRY gWorkQueueList; static EVENT* gWorkQueueEvent; static volatile long gWorkQueueListReady; static volatile long gWorkQueueStartState; // 0=not started, 1=starting, 2=started. static void KiWorkQueueWorker(void* arg) { (void)arg; KeAssertIrql(PASSIVE_LEVEL); for (;;) { (void)KeWaitForEvent(gWorkQueueEvent, 0); for (;;) { KWORK_ITEM* item = (KWORK_ITEM*)0; uintptr_t flags = KeAcquireSpinlock(&gWorkQueueLock); if (!LIST_IS_EMPTY(&gWorkQueueList)) { LIST_ENTRY* node = ListPopHead(&gWorkQueueList); item = CONTAINING_RECORD(node, KWORK_ITEM, Link); } KeReleaseSpinlock(&gWorkQueueLock, flags); if (!item) break; // Allow the item to be queued again while it is running. This keeps // level-triggered users such as cursor updates naturally coalesced // but does not lose an update that arrives during the callback. _InterlockedExchange(&item->Queued, 0); if (item->Routine) item->Routine(item->Context); } } } void KeInitializeWorkItem(KWORK_ITEM* item, KWORK_ROUTINE routine, void* context) { if (!item) return; LIST_INIT(&item->Link); item->Routine = routine; item->Context = context; item->Queued = 0; } bool KeIsWorkQueueStarted(void) { return _InterlockedCompareExchange(&gWorkQueueStartState, 2, 2) == 2; } bool KeQueueWorkItem(KWORK_ITEM* item) { if (!item || !item->Routine) return false; if (_InterlockedCompareExchange(&item->Queued, 1, 0) != 0) return false; if (!_InterlockedCompareExchange(&gWorkQueueListReady, 1, 1)) { _InterlockedExchange(&item->Queued, 0); return false; } uintptr_t flags = KeAcquireSpinlock(&gWorkQueueLock); ListInsertTail(&gWorkQueueList, &item->Link); EVENT* event = gWorkQueueEvent; KeReleaseSpinlock(&gWorkQueueLock, flags); if (event) KeSignalEvent(event); return true; } KSTATUS KeStartWorkQueue(void) { long state = _InterlockedCompareExchange(&gWorkQueueStartState, 1, 0); if (state == 2) return STATUS_SUCCESS; if (state == 1) { while (_InterlockedCompareExchange(&gWorkQueueStartState, 2, 2) == 1) KeYield(); return KeIsWorkQueueStarted() ? STATUS_SUCCESS : STATUS_FAILURE; } LIST_INIT(&gWorkQueueList); _InterlockedExchange(&gWorkQueueListReady, 1); KSTATUS s = KeEventCreate(EventAutoReset, 0, &gWorkQueueEvent); if (KSUCCESS(s)) { THREAD* worker = (THREAD*)0; s = KeCreateKernelThread((uintptr_t)KiWorkQueueWorker, 0, PriorityNormal, &worker); // Persistent system worker; keep the creator reference for kernel life. (void)worker; } if (KSUCCESS(s)) { _InterlockedExchange(&gWorkQueueStartState, 2); KeSignalEvent(gWorkQueueEvent); } else { _InterlockedExchange(&gWorkQueueStartState, 0); } return s; }