Merge pull request #42 from wnsntgs/Kernel/Lib/SemaphoreWakeupFix

Fix semaphore wakeup race
This commit is contained in:
Matheus
2026-09-23 15:11:05 -03:00
committed by GitHub
+16 -11
View File
@@ -74,16 +74,17 @@ int semaphore_wait(semaphore_t *sem, bool interruptible) {
sched_prepare_sleep(interruptible); sched_prepare_sleep(interruptible);
spinlock_release(&sem->lock); spinlock_release(&sem->lock);
ret = sched_yield(); ret = sched_yield();
if (ret) {
spinlock_acquire(&sem->lock);
// Wait for the signaller to finish using this semaphore before
// returning as it may belong to the caller's stack.
spinlock_acquire(&sem->lock);
if (ret) {
if (removeself(sem)) if (removeself(sem))
++sem->i; ++sem->i;
else else
ret = 0; // we have already been removed in the meantime, so pretend we did not actually get interrupted ret = 0; // The semaphore signal won the race.
spinlock_release(&sem->lock);
} }
spinlock_release(&sem->lock);
goto leave; goto leave;
} }
@@ -121,11 +122,13 @@ void semaphore_signal(semaphore_t *sem) {
__assert(thread); __assert(thread);
} }
spinlock_release(&sem->lock); // Complete the wake before an interrupted waiter can observe its
interrupt_set(intstate); // removal and return (otherwise this wake could reach its next wait).
if (thread) if (thread)
sched_wakeup(thread, 0); sched_wakeup(thread, 0);
spinlock_release(&sem->lock);
interrupt_set(intstate);
} }
bool semaphore_signal_limit(semaphore_t *sem, int limit) { bool semaphore_signal_limit(semaphore_t *sem, int limit) {
@@ -146,11 +149,13 @@ bool semaphore_signal_limit(semaphore_t *sem, int limit) {
successful = true; successful = true;
leave: leave:
spinlock_release(&sem->lock); // Complete the wake before an interrupted waiter can observe its
interrupt_set(intstate); // removal and return (otherwise this wake could reach its next wait).
if (thread) if (thread)
sched_wakeup(thread, 0); sched_wakeup(thread, 0);
spinlock_release(&sem->lock);
interrupt_set(intstate);
return successful; return successful;
} }