// ke_semaphore.c - counting semaphore #include #include #include #include #include static void SemDestroy(OBJECT* obj) { (void)obj; } KSTATUS SemaphoreCreate(int32_t initial, int32_t max, SEMAPHORE **out) { if (!out || initial < 0 || max < 1 || initial > max) return STATUS_INVALID_PARAMETER; SEMAPHORE* s = (SEMAPHORE *)ObAllocateObject(ObjectTypeSemaphore, sizeof(SEMAPHORE)); if (!s) return STATUS_NO_MEMORY; s->Header.Destroy = SemDestroy; s->Lock = (SPINLOCK)SPINLOCK_INIT; s->Count = initial; s->MaxCount = max; LIST_INIT(&s->WaitList); *out = s; return STATUS_SUCCESS; } KSTATUS KeWaitSemaphore(SEMAPHORE* sem) { if (!sem) return STATUS_INVALID_PARAMETER; THREAD* self = KeCurrentThread(); while (true) { uintptr_t flags = KeAcquireSpinlock(&sem->Lock); if (sem->Count > 0) { sem->Count--; KeReleaseSpinlock(&sem->Lock, flags); return STATUS_SUCCESS; } ListInsertTail(&sem->WaitList, &self->SchedulerLink); KeReleaseSpinlock(&sem->Lock, flags); KeBlockThread(self, &sem->Header); } } KSTATUS KeTrySemaphore(SEMAPHORE* sem) { if (!sem) return STATUS_INVALID_PARAMETER; uintptr_t flags = KeAcquireSpinlock(&sem->Lock); if (sem->Count > 0) { sem->Count--; KeReleaseSpinlock(&sem->Lock, flags); return STATUS_SUCCESS; } KeReleaseSpinlock(&sem->Lock, flags); return STATUS_FAILURE; } void KeSignalSemaphore(SEMAPHORE* sem) { if (!sem) return; uintptr_t flags = KeAcquireSpinlock(&sem->Lock); if (!LIST_IS_EMPTY(&sem->WaitList)) { LIST_ENTRY* node = ListPopHead(&sem->WaitList); THREAD* waiter = CONTAINING_RECORD(node, THREAD, SchedulerLink); KeReleaseSpinlock(&sem->Lock, flags); KeUnblockThread(waiter); return; } if (sem->Count < sem->MaxCount) sem->Count++; KeReleaseSpinlock(&sem->Lock, flags); }