]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
fix: E1000 rx_thread scheduling — move sched_enqueue_ready outside sem lock
authorTulio A M Mendes <[email protected]>
Sun, 15 Feb 2026 01:22:20 +0000 (22:22 -0300)
committerTulio A M Mendes <[email protected]>
Sun, 15 Feb 2026 01:22:20 +0000 (22:22 -0300)
- 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

index 526ab6426528b1ccf33a184b48d53513349a33e6..1c2526761308d5981dd774dbcbfad8f787263a25 100644 (file)
@@ -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);
+    }
 }
 
 /* ------------------------------------------------------------------ */