// ke_mutex.c - binary ownership mutex #include "ke_mutex.h" #include "ke_thread.h" #include "ke_sched.h" #include "mm_virt.h" #include "ob_object.h" static void MutexDestroy(OBJECT* obj) { (void)obj; } KSTATUS MutexCreate(MUTEX **out) { if (!out) return STATUS_INVALID_PARAMETER; MUTEX* m = (MUTEX *)ObAllocateObject(ObjectTypeMutex, sizeof(MUTEX)); if (!m) return STATUS_NO_MEMORY; m->Header.Destroy = MutexDestroy; m->Lock = (SPINLOCK)SPINLOCK_INIT; m->Owner = (struct THREAD *)0; LIST_INIT(&m->WaitList); *out = m; return STATUS_SUCCESS; } KSTATUS KeAcquireMutex(MUTEX* mutex) { if (!mutex) return STATUS_INVALID_PARAMETER; THREAD* self = KeCurrentThread(); for (;;) { uintptr_t flags = KeAcquireSpinlock(&mutex->Lock); if (!mutex->Owner) { mutex->Owner = self; KeReleaseSpinlock(&mutex->Lock, flags); return STATUS_SUCCESS; } ListInsertTail(&mutex->WaitList, &self->SchedulerLink); KeReleaseSpinlock(&mutex->Lock, flags); KeBlockThread(self, &mutex->Header); } } KSTATUS KeTryAcquireMutex(MUTEX* mutex) { if (!mutex) return STATUS_INVALID_PARAMETER; THREAD* self = KeCurrentThread(); uintptr_t flags = KeAcquireSpinlock(&mutex->Lock); if (!mutex->Owner) { mutex->Owner = self; KeReleaseSpinlock(&mutex->Lock, flags); return STATUS_SUCCESS; } KeReleaseSpinlock(&mutex->Lock, flags); return STATUS_FAILURE; } void KeReleaseMutex(MUTEX* mutex) { if (!mutex) return; uintptr_t flags = KeAcquireSpinlock(&mutex->Lock); mutex->Owner = (struct THREAD *)0; if (!LIST_IS_EMPTY(&mutex->WaitList)) { LIST_ENTRY* node = ListPopHead(&mutex->WaitList); THREAD* waiter = CONTAINING_RECORD(node, THREAD, SchedulerLink); KeReleaseSpinlock(&mutex->Lock, flags); KeUnblockThread(waiter); return; } KeReleaseSpinlock(&mutex->Lock, flags); }