Skip to content

Commit

Permalink
scheduler: fix idle-thread reentrant bug
Browse files Browse the repository at this point in the history
  • Loading branch information
moodyhunter committed Aug 20, 2024
1 parent ae5be82 commit 4deb5f7
Show file tree
Hide file tree
Showing 7 changed files with 39 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@
X(x86_acpi)
// clang-format on

#define MOS_PLATFORM_MEMORY_BARRIER() __asm__ __volatile__("" ::: "memory")

typedef struct _platform_process_options
{
bool iopl;
Expand Down
5 changes: 5 additions & 0 deletions kernel/include/private/mos/lib/sync/spinlock.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@

#pragma once

#include "mos/platform/platform_defs.h"

#include <mos/mos_global.h>
#include <mos/types.h>

#define barrier() MOS_PLATFORM_MEMORY_BARRIER()

typedef struct
{
bool flag;
Expand All @@ -27,6 +31,7 @@ typedef struct
#define _spinlock_real_acquire(lock) \
do \
{ \
barrier(); \
while (__atomic_test_and_set(&(lock)->flag, __ATOMIC_ACQUIRE)) \
; \
} while (0)
Expand Down
19 changes: 19 additions & 0 deletions kernel/include/private/mos/tasks/kthread.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,23 @@
#include <mos/platform/platform.h>

void kthread_init(void);

/**
* @brief Create a kernel-mode thread.
*
* @param entry The entry point of the thread
* @param arg The argument to pass to the thread
* @param name The name of the thread
* @return thread_t* The created thread
*/
thread_t *kthread_create(thread_entry_t entry, void *arg, const char *name);

/**
* @brief Create a kernel thread, but do not add it to the scheduler.
*
* @param entry The entry point of the thread
* @param arg The argument to pass to the thread
* @param name The name of the thread
* @return thread_t* The created thread
*/
__nodiscard thread_t *kthread_create_no_sched(thread_entry_t entry, void *arg, const char *name);
2 changes: 1 addition & 1 deletion kernel/tasks/idle_task.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ static void create_idle_task()
char namebuf[32];
snprintf(namebuf, sizeof(namebuf), "idle-%u", i);
pr_dinfo(process, "creating the idle task for CPU %u", i);
thread_t *t = kthread_create(idle_task, NULL, namebuf);
thread_t *t = kthread_create_no_sched(idle_task, NULL, namebuf);
platform_info->cpu.percpu_value[i].idle_thread = t;
// ! scheduler will switch to this thread if no other threads are available, thus scheduler_add_thread isn't called
// thread_set_cpu(t, i);
Expand Down
8 changes: 7 additions & 1 deletion kernel/tasks/kthread.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ void kthread_init(void)
}

thread_t *kthread_create(thread_entry_t entry, void *arg, const char *name)
{
thread_t *thread = kthread_create_no_sched(entry, arg, name);
scheduler_add_thread(thread);
return thread;
}

thread_t *kthread_create_no_sched(thread_entry_t entry, void *arg, const char *name)
{
MOS_ASSERT_X(kthreadd, "kthreadd not initialized");
pr_dinfo2(thread, "creating kernel thread '%s'", name);
Expand All @@ -43,6 +50,5 @@ thread_t *kthread_create(thread_entry_t entry, void *arg, const char *name)
thread_t *thread = thread_new(kthreadd, THREAD_MODE_KERNEL, name, 0, NULL);
platform_context_setup_child_thread(thread, kthread_entry, kthread_arg);
thread_complete_init(thread);
scheduler_add_thread(thread);
return thread;
}
2 changes: 1 addition & 1 deletion kernel/tasks/schedule.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ void reschedule(void)

if (!next)
{
if (current->state == THREAD_STATE_RUNNING)
if (current && current->state == THREAD_STATE_RUNNING)
{
// give the current thread another chance to run, if it's the only one and it's able to run
MOS_ASSERT_X(spinlock_is_locked(&current->state_lock), "thread state lock must be held");
Expand Down
5 changes: 4 additions & 1 deletion kernel/tasks/scheduler/naive.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,10 @@ static thread_t *naive_sched_select_next(scheduler_t *instance)

naive_sched_node_t *node = list_entry(scheduler->threads.next, naive_sched_node_t);
thread_t *thread = node->thread;
spinlock_acquire(&thread->state_lock);
if (thread == current_thread)
spinlock_assert_locked(&thread->state_lock);
else
spinlock_acquire(&thread->state_lock);
list_remove(node);
spinlock_release(&scheduler->lock);

Expand Down

0 comments on commit 4deb5f7

Please sign in to comment.