From: Tulio A M Mendes Date: Sun, 15 Feb 2026 01:22:20 +0000 (-0300) Subject: fix: E1000 rx_thread scheduling — move sched_enqueue_ready outside sem lock X-Git-Url: https://projects.tadryanom.me/?a=commitdiff_plain;h=bf9d339bdd1e630d9bf510459b1809130944e558;p=AdrOS.git fix: E1000 rx_thread scheduling — move sched_enqueue_ready outside sem lock - 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 --- diff --git a/src/kernel/sync.c b/src/kernel/sync.c index bb3b999b..58145b4d 100644 --- a/src/kernel/sync.c +++ b/src/kernel/sync.c @@ -93,7 +93,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)) { @@ -104,17 +104,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); + } } /* ------------------------------------------------------------------ */