feat(sched): add observable kernel thread exit

This commit is contained in:
Microindole 2026-05-12 17:41:03 +08:00
parent 7292b9eb56
commit 624034acb5
No known key found for this signature in database
GPG Key ID: 22FB34CD2133ACA1
6 changed files with 73 additions and 9 deletions

View File

@ -152,9 +152,10 @@
- 已把 `kernel_thread_create()` 中的线程 id 分配和 run queue 入队纳入 interrupt-safe lock 保护。 - 已把 `kernel_thread_create()` 中的线程 id 分配和 run queue 入队纳入 interrupt-safe lock 保护。
- 已建立 `sched_irq_exit()`timer IRQ 只设置 `need_resched`trap 的 IRQ 返回边界统一消费调度请求。 - 已建立 `sched_irq_exit()`timer IRQ 只设置 `need_resched`trap 的 IRQ 返回边界统一消费调度请求。
- 已建立最小 DEAD 线程回收路径,调度前会释放非当前 DEAD 线程的内核栈和线程对象。 - 已建立最小 DEAD 线程回收路径,调度前会释放非当前 DEAD 线程的内核栈和线程对象。
- 已建立统一 `kernel_thread_exit()`/`sched_thread_exit()`,线程入口返回和显式退出都会进入明确退出路径,再由调度安全边界回收非当前 DEAD 线程。
- 已在调度私有头中加入 thread state helper调度核心、线程退出和 wait queue 路径不再直接散写主要状态转换。 - 已在调度私有头中加入 thread state helper调度核心、线程退出和 wait queue 路径不再直接散写主要状态转换。
- 已把调度代码按职责拆分为 `core.c`、`thread.c`、`wait.c`、`idle.c` 和私有 `sched.h`,并把当前阶段自测/演示线程移到 `kernel/selftest/sched.c` - 已把调度代码按职责拆分为 `core.c`、`thread.c`、`wait.c`、`idle.c` 和私有 `sched.h`,并把当前阶段自测/演示线程移到 `kernel/selftest/sched.c`
- `scripts/check.sh` 已验证 `timer initialized`、`timer tick=1/2/3`、`scheduler initialized`、`kernel thread selftest ok`、timer 驱动线程轮转、`sched_sleep()`、wait queue wakeup、条件等待和超时等待 - `scripts/check.sh` 已验证 `timer initialized`、`timer tick=1/2/3`、`scheduler initialized`、`kernel thread selftest ok`、timer 驱动线程轮转、`sched_sleep()`、wait queue wakeup、条件等待、超时等待、线程返回退出、显式退出和 DEAD 线程回收
后续扩展: 后续扩展:
@ -181,7 +182,7 @@
### D. thread lifecycle ### D. thread lifecycle
- 为线程退出增加更完整的生命周期状态、引用规则和最终释放约束。 - 为线程退出增加更完整的生命周期状态、引用规则和最终释放约束。
- 补充“当前线程不能释放自身内核栈”的文档和自测 - 继续补充“当前线程不能释放自身内核栈”的更严格断言和未来 join/wait 语义
- 为未来 `kthread_stop()`、join/wait 和进程退出保留接口空间。 - 为未来 `kthread_stop()`、join/wait 和进程退出保留接口空间。
- 回收路径需要覆盖等待队列残留、run queue 残留和 timer sleep 残留。 - 回收路径需要覆盖等待队列残留、run queue 残留和 timer sleep 残留。

View File

@ -41,6 +41,7 @@ struct thread {
void sched_init(void); void sched_init(void);
struct thread *kernel_thread_create( struct thread *kernel_thread_create(
const char *name, kernel_thread_entry_t entry, void *arg); const char *name, kernel_thread_entry_t entry, void *arg);
void kernel_thread_exit(void) __attribute__((noreturn));
void sched_start(void) __attribute__((noreturn)); void sched_start(void) __attribute__((noreturn));
void sched_tick(uint64_t tick); void sched_tick(uint64_t tick);
void sched_irq_exit(void); void sched_irq_exit(void);

View File

@ -74,6 +74,7 @@ static inline void thread_set_dead(struct thread *thread)
void enqueue_thread(struct thread *thread); void enqueue_thread(struct thread *thread);
void sched_reap_dead_threads(void); void sched_reap_dead_threads(void);
void sched_thread_exit(void) __attribute__((noreturn));
void sched_selftest(void); void sched_selftest(void);
int sched_idle_create(void); int sched_idle_create(void);
void sched_demo_start(void) __attribute__((noreturn)); void sched_demo_start(void) __attribute__((noreturn));

View File

@ -98,6 +98,9 @@ struct thread *kernel_thread_create(
static void release_thread(struct thread *thread) static void release_thread(struct thread *thread)
{ {
early_log_puts("thread reaped ");
early_log_puts(thread->name);
early_log_puts("\n");
kfree(thread->stack_base); kfree(thread->stack_base);
kfree(thread); kfree(thread);
} }
@ -106,7 +109,10 @@ void sched_reap_dead_threads(void)
{ {
struct thread *prev = 0; struct thread *prev = 0;
struct thread *thread = run_queue_head; struct thread *thread = run_queue_head;
struct thread *reap_list = 0;
uint64_t flags;
spin_lock_irqsave(&scheduler_lock, &flags);
while (thread != 0) { while (thread != 0) {
struct thread *next = thread->next; struct thread *next = thread->next;
@ -121,13 +127,41 @@ void sched_reap_dead_threads(void)
run_queue_tail = prev; run_queue_tail = prev;
} }
release_thread(thread); thread->next = reap_list;
reap_list = thread;
} else { } else {
prev = thread; prev = thread;
} }
thread = next; thread = next;
} }
spin_unlock_irqrestore(&scheduler_lock, flags);
while (reap_list != 0) {
struct thread *next = reap_list->next;
reap_list->next = 0;
release_thread(reap_list);
reap_list = next;
}
}
void sched_thread_exit(void)
{
if (current_thread == 0) {
panic("thread exit without current thread");
}
thread_set_dead(current_thread);
for (;;) {
sched_yield();
}
}
void kernel_thread_exit(void)
{
sched_thread_exit();
} }
static void thread_trampoline(void) static void thread_trampoline(void)
@ -139,9 +173,5 @@ static void thread_trampoline(void)
} }
thread->entry(thread->arg); thread->entry(thread->arg);
thread_set_dead(thread); kernel_thread_exit();
for (;;) {
sched_yield();
}
} }

View File

@ -134,6 +134,21 @@ static void timeout_wait_demo_waiter(void *arg)
early_log_puts("timeout waiter timed out\n"); early_log_puts("timeout waiter timed out\n");
} }
static void return_exit_demo_thread(void *arg)
{
(void)arg;
early_log_puts("return exit thread returning\n");
}
static void explicit_exit_demo_thread(void *arg)
{
(void)arg;
early_log_puts("explicit exit thread exiting\n");
kernel_thread_exit();
}
void sched_demo_start(void) void sched_demo_start(void)
{ {
struct thread *first = kernel_thread_create( struct thread *first = kernel_thread_create(
@ -150,10 +165,14 @@ void sched_demo_start(void)
"condition-waker", condition_wait_demo_waker, 0); "condition-waker", condition_wait_demo_waker, 0);
struct thread *timeout_waiter = kernel_thread_create( struct thread *timeout_waiter = kernel_thread_create(
"timeout-waiter", timeout_wait_demo_waiter, 0); "timeout-waiter", timeout_wait_demo_waiter, 0);
struct thread *return_exit =
kernel_thread_create("return-exit", return_exit_demo_thread, 0);
struct thread *explicit_exit = kernel_thread_create(
"explicit-exit", explicit_exit_demo_thread, 0);
if (first == 0 || second == 0 || waiter == 0 || waker == 0 || if (first == 0 || second == 0 || waiter == 0 || waker == 0 ||
condition_waiter == 0 || condition_waker == 0 || condition_waiter == 0 || condition_waker == 0 ||
timeout_waiter == 0) { timeout_waiter == 0 || return_exit == 0 || explicit_exit == 0) {
panic("scheduler demo thread creation failed"); panic("scheduler demo thread creation failed");
} }

View File

@ -34,6 +34,12 @@ check_lines build/debug.log \
"condition waiter sleeping" \ "condition waiter sleeping" \
"condition waker sleeping" \ "condition waker sleeping" \
"timeout waiter sleeping" \ "timeout waiter sleeping" \
"return exit thread returning" \
"explicit exit thread exiting" \
"thread reaped worker-a" \
"thread reaped worker-b" \
"thread reaped return-exit" \
"thread reaped explicit-exit" \
"preempt thread 1 step=2" \ "preempt thread 1 step=2" \
"preempt thread 2 step=2" \ "preempt thread 2 step=2" \
"timeout waiter timed out" \ "timeout waiter timed out" \
@ -71,6 +77,12 @@ check_lines build/serial.log \
"condition waiter sleeping" \ "condition waiter sleeping" \
"condition waker sleeping" \ "condition waker sleeping" \
"timeout waiter sleeping" \ "timeout waiter sleeping" \
"return exit thread returning" \
"explicit exit thread exiting" \
"thread reaped worker-a" \
"thread reaped worker-b" \
"thread reaped return-exit" \
"thread reaped explicit-exit" \
"preempt thread 1 step=2" \ "preempt thread 1 step=2" \
"preempt thread 2 step=2" \ "preempt thread 2 step=2" \
"timeout waiter timed out" \ "timeout waiter timed out" \