Skip to content

Commit

Permalink
sched/basic Fix issue in sched_enqueue_thread()
Browse files Browse the repository at this point in the history
Multiple calls to `sched_enqueue_thread()` would add repeatedly add the thread to the run-queue.

Fixed by checking first if the thread is already enqueued.
  • Loading branch information
suhas-pai committed Aug 27, 2024
1 parent a29d4d4 commit 9e4b63f
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 15 deletions.
45 changes: 31 additions & 14 deletions kernel/src/sched/basic/sched.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,27 @@ __debug_optimize(3) bool thread_runnable(const struct thread *const thread) {
memory_order_relaxed);
}

__debug_optimize(3)
bool thread_enqueued_nolock(const struct thread *const thread) {
return !list_empty(&thread->sched_info.list);
}

__debug_optimize(3) bool thread_enqueued(const struct thread *const thread) {
const int flag = spin_acquire_save_irq(&g_run_queue_lock);
const bool result = !list_empty(&thread->sched_info.list);
const bool result = thread_enqueued_nolock(thread);

spin_release_restore_irq(&g_run_queue_lock, flag);
return result;
}

__debug_optimize(3)
bool thread_running_nolock(const struct thread *const thread) {
return thread->cpu != NULL;
}

__debug_optimize(3) bool thread_running(const struct thread *const thread) {
const int flag = spin_acquire_save_irq(&g_run_queue_lock);
const bool result = thread->cpu != NULL;
const bool result = thread_running_nolock(thread);

spin_release_restore_irq(&g_run_queue_lock, flag);
return result;
Expand All @@ -62,20 +72,23 @@ __debug_optimize(3) bool thread_running(const struct thread *const thread) {
__debug_optimize(3)
static void sched_enqueue_thread_for_use(struct thread *const thread) {
list_radd(&g_run_queue, &thread->sched_info.list);
list_verify(&g_run_queue, sched_info.list);;
}

__debug_optimize(3)
static void sched_dequeue_thread_for_use(struct thread *const thread) {
list_remove(&thread->sched_info.list);
list_verify(&g_run_queue, sched_info.list);;
}

__debug_optimize(3) void sched_enqueue_thread(struct thread *const thread) {
const int flag = spin_acquire_save_irq(&g_run_queue_lock);

// sched_enqueue_thread() might be called from a dequeued but running thread
// so only enqueue-for-use in for threads that are not running.
// so only enqueue-for-use in for threads that are not running and aren't
// already enqueued.

if (thread->cpu == NULL) {
if (!thread_running_nolock(thread) && !thread_enqueued_nolock(thread)) {
sched_enqueue_thread_for_use(thread);
}

Expand All @@ -101,27 +114,31 @@ static struct thread *get_next_thread(struct thread *const prev) {
const int flag = spin_acquire_save_irq(&g_run_queue_lock);
struct thread *next = NULL;

list_verify(&g_run_queue, sched_info.list);;
list_foreach(next, &g_run_queue, sched_info.list) {
if (next != prev) {
if (thread_runnable(prev)) {
sched_enqueue_thread_for_use(prev);
}

sched_dequeue_thread_for_use(next);
spin_release_restore_irq(&g_run_queue_lock, flag);
if (next == prev) {
continue;
}

return next;
if (thread_runnable(prev)) {
sched_enqueue_thread_for_use(prev);
}

sched_dequeue_thread_for_use(next);
spin_release_restore_irq(&g_run_queue_lock, flag);

return next;
}

if (thread_runnable(prev)) {
spin_release_restore_irq(&g_run_queue_lock, flag);
return prev;
}

struct thread *const result = prev->cpu->idle_thread;
spin_release_restore_irq(&g_run_queue_lock, flag);
struct cpu_info *const cpu = prev->cpu;
struct thread *const result = cpu->idle_thread;

spin_release_restore_irq(&g_run_queue_lock, flag);
return result;
}

Expand Down
1 change: 0 additions & 1 deletion kernel/src/sched/scheduler.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
#pragma once

#include "sys/irqdef.h"

#include "thread.h"

void sched_init();
Expand Down

0 comments on commit 9e4b63f

Please sign in to comment.