From 3edd198867cf60bce29343ca096df08f20eff3ec Mon Sep 17 00:00:00 2001 From: Tulio A M Mendes Date: Sat, 14 Feb 2026 22:22:20 -0300 Subject: [PATCH] =?utf8?q?fix:=20E1000=20rx=5Fthread=20scheduling=20?= =?utf8?q?=E2=80=94=20move=20sched=5Fenqueue=5Fready=20outside=20sem=20loc?= =?utf8?q?k?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit - ksem_signal now calls sched_enqueue_ready after releasing the semaphore spinlock, avoiding lock-order issues when called from IRQ context (sched_enqueue_ready acquires sched_lock internally) - Prevents potential deadlock: IRQ → ksem_signal → sched_lock while schedule() already holds sched_lock - 35/35 smoke tests pass, cppcheck clean --- src/kernel/sync.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/kernel/sync.c b/src/kernel/sync.c index 526ab64..1c25267 100644 --- a/src/kernel/sync.c +++ b/src/kernel/sync.c @@ -84,7 +84,7 @@ void ksem_signal(ksem_t* s) { uintptr_t flags = spin_lock_irqsave(&s->lock); /* Find a waiter still blocked/sleeping (skip those already woken by timeout) */ - int woke = 0; + struct process* to_wake = NULL; for (uint32_t i = 0; i < s->nwaiters; i++) { struct process* p = s->waiters[i]; if (p && (p->state == PROCESS_BLOCKED || p->state == PROCESS_SLEEPING)) { @@ -95,17 +95,22 @@ void ksem_signal(ksem_t* s) { p->state = PROCESS_READY; p->wake_at_tick = 0; - sched_enqueue_ready(p); - woke = 1; + to_wake = p; break; } } - if (!woke) { + if (!to_wake) { s->count++; } spin_unlock_irqrestore(&s->lock, flags); + + /* Enqueue outside the semaphore lock to avoid lock-order issues + * (sched_enqueue_ready acquires sched_lock internally). */ + if (to_wake) { + sched_enqueue_ready(to_wake); + } } /* ------------------------------------------------------------------ */ -- 2.43.0