feat(sched): add timer-driven scheduling and wait queues
This commit is contained in:
parent
bbf184f9fc
commit
e8a14dbc15
@ -57,14 +57,20 @@
|
|||||||
- 已建立 x86 上下文切换入口,保存/恢复 callee-saved 寄存器和栈指针。
|
- 已建立 x86 上下文切换入口,保存/恢复 callee-saved 寄存器和栈指针。
|
||||||
- 已建立线程 trampoline,新线程能从独立内核栈进入自己的入口函数。
|
- 已建立线程 trampoline,新线程能从独立内核栈进入自己的入口函数。
|
||||||
- 已建立协作式 round-robin,两个 kernel thread 能通过 `sched_yield()` 轮转运行。
|
- 已建立协作式 round-robin,两个 kernel thread 能通过 `sched_yield()` 轮转运行。
|
||||||
- `scripts/check.sh` 已验证 `timer initialized`、`timer tick=1/2/3`、`scheduler initialized`、`kernel thread selftest ok` 和 `thread 1/2` 轮转日志。
|
- 已把调度接入 `timer_tick()`,timer tick 会唤醒到期 sleep 线程并触发 round-robin。
|
||||||
|
- 已建立 idle thread,所有普通线程 sleep/wait 时由 idle 承接 CPU。
|
||||||
|
- 已提供 `sched_sleep()`,线程可以睡眠指定 tick 数并被 timer 唤醒。
|
||||||
|
- 已提供 `wait_queue_init()`、`wait_queue_sleep()`、`wait_queue_wake_one()` 和 `wait_queue_wake_all()`。
|
||||||
|
- `scripts/check.sh` 已验证 `timer initialized`、`timer tick=1/2/3`、`scheduler initialized`、`kernel thread selftest ok`、timer 驱动线程轮转、`sched_sleep()` 和 wait queue wakeup。
|
||||||
|
|
||||||
后续扩展:
|
后续扩展:
|
||||||
|
|
||||||
- 把 IRQ 分发扩展为可注册 handler 的表,而不是只处理 timer。
|
- 把 IRQ 分发扩展为可注册 handler 的表,而不是只处理 timer。
|
||||||
- 把协作式调度接入 timer tick,演进为抢占式调度。
|
- 把当前直接在 timer IRQ 内触发调度的路径收敛为更明确的 interrupt-exit reschedule 模型。
|
||||||
- 建立 `yield()`、`sleep()`、timer wakeup 和 wait queue。
|
- 建立基础 spinlock 或 interrupt-safe lock。
|
||||||
|
- 为 wait queue 增加条件等待、超时等待和状态检查。
|
||||||
|
- 为线程退出增加资源回收路径。
|
||||||
|
|
||||||
下一阶段:
|
下一阶段:
|
||||||
|
|
||||||
- 继续在 `04-time-scheduler.md` 内推进 timer 驱动的抢占式调度、`sleep()` 和 wait queue。
|
- 继续在 `04-time-scheduler.md` 内推进 interrupt-safe lock、线程退出回收和更严格的 interrupt-exit reschedule。
|
||||||
|
|||||||
@ -28,7 +28,7 @@
|
|||||||
| `01-early-debug.md` | 基础完成 | 已有 early log 前端、QEMU debug port、COM1 串口和最小 `panic()`。 |
|
| `01-early-debug.md` | 基础完成 | 已有 early log 前端、QEMU debug port、COM1 串口和最小 `panic()`。 |
|
||||||
| `02-cpu-interrupts.md` | 基础完成 | 已有 GDT/TSS/IDT、exception vector 0-31、`trap_frame` 和 invalid opcode 回归测试。 |
|
| `02-cpu-interrupts.md` | 基础完成 | 已有 GDT/TSS/IDT、exception vector 0-31、`trap_frame` 和 invalid opcode 回归测试。 |
|
||||||
| `03-memory.md` | 基础完成 | 已有最小物理页 allocator、页表 map/unmap/query、page fault 诊断和内核堆。 |
|
| `03-memory.md` | 基础完成 | 已有最小物理页 allocator、页表 map/unmap/query、page fault 诊断和内核堆。 |
|
||||||
| `04-time-scheduler.md` | 进行中 | 已有 PIT timer interrupt、通用 tick 计数、kernel thread、内核栈、上下文切换和协作式 round-robin;抢占式调度和等待队列未完成。 |
|
| `04-time-scheduler.md` | 进行中 | 已有 PIT timer interrupt、通用 tick、kernel thread、内核栈、上下文切换、timer 驱动 round-robin、sleep 和 wait queue 基础;锁、退出回收和更严格的中断返回调度未完成。 |
|
||||||
| `05-input-events.md` | 未开始 | 需要输入事件模型和键盘接入。 |
|
| `05-input-events.md` | 未开始 | 需要输入事件模型和键盘接入。 |
|
||||||
| `06-storage-vfs.md` | 未开始 | 需要块层、缓存、VFS 和基础文件系统。 |
|
| `06-storage-vfs.md` | 未开始 | 需要块层、缓存、VFS 和基础文件系统。 |
|
||||||
| `07-user-mode.md` | 未开始 | 需要 syscall、进程、用户地址空间和 ELF 加载。 |
|
| `07-user-mode.md` | 未开始 | 需要 syscall、进程、用户地址空间和 ELF 加载。 |
|
||||||
@ -36,7 +36,7 @@
|
|||||||
| `09-driver-expansion.md` | 未开始 | 需要设备模型、PCI/ACPI、存储、网络等驱动扩展。 |
|
| `09-driver-expansion.md` | 未开始 | 需要设备模型、PCI/ACPI、存储、网络等驱动扩展。 |
|
||||||
| `10-real-machine.md` | 未开始 | 需要 U 盘真机启动验证和硬件差异记录。 |
|
| `10-real-machine.md` | 未开始 | 需要 U 盘真机启动验证和硬件差异记录。 |
|
||||||
|
|
||||||
当前最合适的下一步仍在 `04-time-scheduler.md` 内:把调度接入 timer tick,演进到抢占式调度,然后做 `sleep()` 和 wait queue。
|
当前最合适的下一步仍在 `04-time-scheduler.md` 内:补 interrupt-safe lock、线程退出回收,并把调度路径收敛为更明确的 interrupt-exit reschedule。
|
||||||
|
|
||||||
## Linux 级能力缺口路由
|
## Linux 级能力缺口路由
|
||||||
|
|
||||||
|
|||||||
@ -26,6 +26,7 @@
|
|||||||
- timer 基础:已接入 x86 PIC/PIT,timer IRQ 能进入通用 tick 入口。
|
- timer 基础:已接入 x86 PIC/PIT,timer IRQ 能进入通用 tick 入口。
|
||||||
- kernel thread 基础:已建立线程对象、内核栈和 run queue。
|
- kernel thread 基础:已建立线程对象、内核栈和 run queue。
|
||||||
- 调度基础:已建立 x86 上下文切换入口和协作式 round-robin。
|
- 调度基础:已建立 x86 上下文切换入口和协作式 round-robin。
|
||||||
|
- sleep/wait 基础:timer tick 能唤醒 sleep 线程,wait queue 支持 sleep 和 wake。
|
||||||
- 构建系统已拆成根 Makefile、`arch/x86/Makefile` 和目录 Makefile。
|
- 构建系统已拆成根 Makefile、`arch/x86/Makefile` 和目录 Makefile。
|
||||||
- `scripts/check.sh` 已验证启动日志、串口日志和 invalid opcode 异常路径,GitHub Actions 已接入。
|
- `scripts/check.sh` 已验证启动日志、串口日志和 invalid opcode 异常路径,GitHub Actions 已接入。
|
||||||
- `.clang-format` 已用于强制当前 C 代码风格。
|
- `.clang-format` 已用于强制当前 C 代码风格。
|
||||||
@ -45,8 +46,9 @@
|
|||||||
|
|
||||||
目标:
|
目标:
|
||||||
|
|
||||||
- 把调度接入 timer tick,演进到抢占式调度。
|
- 建立 interrupt-safe lock。
|
||||||
- 建立 `sleep()`、timer wakeup 和 wait queue。
|
- 建立线程退出资源回收。
|
||||||
|
- 把调度路径收敛为更明确的 interrupt-exit reschedule。
|
||||||
|
|
||||||
## 任务路由
|
## 任务路由
|
||||||
|
|
||||||
|
|||||||
@ -10,9 +10,15 @@ enum thread_state {
|
|||||||
THREAD_READY,
|
THREAD_READY,
|
||||||
THREAD_RUNNING,
|
THREAD_RUNNING,
|
||||||
THREAD_SLEEPING,
|
THREAD_SLEEPING,
|
||||||
|
THREAD_WAITING,
|
||||||
THREAD_DEAD,
|
THREAD_DEAD,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct wait_queue {
|
||||||
|
struct thread *head;
|
||||||
|
struct thread *tail;
|
||||||
|
};
|
||||||
|
|
||||||
struct thread {
|
struct thread {
|
||||||
uint64_t id;
|
uint64_t id;
|
||||||
enum thread_state state;
|
enum thread_state state;
|
||||||
@ -22,7 +28,9 @@ struct thread {
|
|||||||
void *stack_base;
|
void *stack_base;
|
||||||
uintptr_t stack_top;
|
uintptr_t stack_top;
|
||||||
size_t stack_size;
|
size_t stack_size;
|
||||||
|
uint64_t wake_tick;
|
||||||
struct thread *next;
|
struct thread *next;
|
||||||
|
struct thread *wait_next;
|
||||||
char name[32];
|
char name[32];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -30,6 +38,12 @@ 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 sched_start(void) __attribute__((noreturn));
|
void sched_start(void) __attribute__((noreturn));
|
||||||
|
void sched_tick(uint64_t tick);
|
||||||
void sched_yield(void);
|
void sched_yield(void);
|
||||||
|
void sched_sleep(uint64_t ticks);
|
||||||
|
void wait_queue_init(struct wait_queue *queue);
|
||||||
|
void wait_queue_sleep(struct wait_queue *queue);
|
||||||
|
void wait_queue_wake_one(struct wait_queue *queue);
|
||||||
|
void wait_queue_wake_all(struct wait_queue *queue);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
#include <tianole/early_log.h>
|
#include <tianole/early_log.h>
|
||||||
#include <tianole/mm.h>
|
#include <tianole/mm.h>
|
||||||
#include <tianole/sched.h>
|
#include <tianole/sched.h>
|
||||||
|
#include <tianole/timer.h>
|
||||||
|
|
||||||
#define KERNEL_STACK_SIZE (PAGE_SIZE * 4u)
|
#define KERNEL_STACK_SIZE (PAGE_SIZE * 4u)
|
||||||
#define STACK_ALIGNMENT 16u
|
#define STACK_ALIGNMENT 16u
|
||||||
@ -16,6 +17,8 @@ static struct thread *current_thread;
|
|||||||
static uintptr_t boot_stack_pointer;
|
static uintptr_t boot_stack_pointer;
|
||||||
static uint64_t next_thread_id = 1;
|
static uint64_t next_thread_id = 1;
|
||||||
static int scheduler_ready;
|
static int scheduler_ready;
|
||||||
|
static int schedule_locked;
|
||||||
|
static struct thread *idle_thread;
|
||||||
|
|
||||||
static void thread_trampoline(void) __attribute__((noreturn));
|
static void thread_trampoline(void) __attribute__((noreturn));
|
||||||
|
|
||||||
@ -102,7 +105,9 @@ struct thread *kernel_thread_create(
|
|||||||
thread->stack_top = align_down_uintptr(stack_top, STACK_ALIGNMENT);
|
thread->stack_top = align_down_uintptr(stack_top, STACK_ALIGNMENT);
|
||||||
thread->stack_pointer = prepare_initial_stack(thread->stack_top);
|
thread->stack_pointer = prepare_initial_stack(thread->stack_top);
|
||||||
thread->stack_size = KERNEL_STACK_SIZE;
|
thread->stack_size = KERNEL_STACK_SIZE;
|
||||||
|
thread->wake_tick = 0;
|
||||||
thread->next = 0;
|
thread->next = 0;
|
||||||
|
thread->wait_next = 0;
|
||||||
copy_thread_name(thread->name, sizeof(thread->name), name);
|
copy_thread_name(thread->name, sizeof(thread->name), name);
|
||||||
|
|
||||||
enqueue_thread(thread);
|
enqueue_thread(thread);
|
||||||
@ -123,36 +128,60 @@ static struct thread *next_runnable_thread(void)
|
|||||||
|
|
||||||
thread = start;
|
thread = start;
|
||||||
while (thread != 0) {
|
while (thread != 0) {
|
||||||
if (thread->state == THREAD_READY) {
|
if (thread->state == THREAD_READY && thread != idle_thread) {
|
||||||
return thread;
|
return thread;
|
||||||
}
|
}
|
||||||
thread = thread->next;
|
thread = thread->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (thread = run_queue_head; thread != start; thread = thread->next) {
|
for (thread = run_queue_head; thread != start; thread = thread->next) {
|
||||||
if (thread->state == THREAD_READY) {
|
if (thread->state == THREAD_READY && thread != idle_thread) {
|
||||||
return thread;
|
return thread;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (idle_thread != 0 && idle_thread->state == THREAD_READY) {
|
||||||
|
return idle_thread;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void wake_sleeping_threads(uint64_t tick)
|
||||||
|
{
|
||||||
|
struct thread *thread;
|
||||||
|
|
||||||
|
for (thread = run_queue_head; thread != 0; thread = thread->next) {
|
||||||
|
if (thread->state == THREAD_SLEEPING &&
|
||||||
|
thread->wake_tick <= tick) {
|
||||||
|
thread->wake_tick = 0;
|
||||||
|
thread->state = THREAD_READY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void sched_yield(void)
|
void sched_yield(void)
|
||||||
{
|
{
|
||||||
struct thread *prev = current_thread;
|
struct thread *prev = current_thread;
|
||||||
struct thread *next = next_runnable_thread();
|
struct thread *next = next_runnable_thread();
|
||||||
|
|
||||||
|
if (schedule_locked != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (next == 0 || next == prev) {
|
if (next == 0 || next == prev) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
schedule_locked = 1;
|
||||||
|
|
||||||
if (prev != 0 && prev->state == THREAD_RUNNING) {
|
if (prev != 0 && prev->state == THREAD_RUNNING) {
|
||||||
prev->state = THREAD_READY;
|
prev->state = THREAD_READY;
|
||||||
}
|
}
|
||||||
|
|
||||||
next->state = THREAD_RUNNING;
|
next->state = THREAD_RUNNING;
|
||||||
current_thread = next;
|
current_thread = next;
|
||||||
|
schedule_locked = 0;
|
||||||
|
|
||||||
if (prev == 0) {
|
if (prev == 0) {
|
||||||
arch_context_switch(&boot_stack_pointer, next->stack_pointer);
|
arch_context_switch(&boot_stack_pointer, next->stack_pointer);
|
||||||
@ -162,6 +191,90 @@ void sched_yield(void)
|
|||||||
arch_context_switch(&prev->stack_pointer, next->stack_pointer);
|
arch_context_switch(&prev->stack_pointer, next->stack_pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sched_tick(uint64_t tick)
|
||||||
|
{
|
||||||
|
wake_sleeping_threads(tick);
|
||||||
|
|
||||||
|
if (current_thread != 0 && current_thread->state == THREAD_RUNNING) {
|
||||||
|
sched_yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sched_sleep(uint64_t ticks)
|
||||||
|
{
|
||||||
|
uint64_t now;
|
||||||
|
|
||||||
|
if (current_thread == 0 || ticks == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
now = timer_ticks();
|
||||||
|
current_thread->wake_tick = now + ticks;
|
||||||
|
current_thread->state = THREAD_SLEEPING;
|
||||||
|
sched_yield();
|
||||||
|
}
|
||||||
|
|
||||||
|
void wait_queue_init(struct wait_queue *queue)
|
||||||
|
{
|
||||||
|
if (queue == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
queue->head = 0;
|
||||||
|
queue->tail = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wait_queue_enqueue(struct wait_queue *queue, struct thread *thread)
|
||||||
|
{
|
||||||
|
thread->wait_next = 0;
|
||||||
|
|
||||||
|
if (queue->tail != 0) {
|
||||||
|
queue->tail->wait_next = thread;
|
||||||
|
} else {
|
||||||
|
queue->head = thread;
|
||||||
|
}
|
||||||
|
|
||||||
|
queue->tail = thread;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wait_queue_sleep(struct wait_queue *queue)
|
||||||
|
{
|
||||||
|
if (queue == 0 || current_thread == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wait_queue_enqueue(queue, current_thread);
|
||||||
|
current_thread->state = THREAD_WAITING;
|
||||||
|
sched_yield();
|
||||||
|
}
|
||||||
|
|
||||||
|
void wait_queue_wake_one(struct wait_queue *queue)
|
||||||
|
{
|
||||||
|
struct thread *thread;
|
||||||
|
|
||||||
|
if (queue == 0 || queue->head == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
thread = queue->head;
|
||||||
|
queue->head = thread->wait_next;
|
||||||
|
if (queue->head == 0) {
|
||||||
|
queue->tail = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
thread->wait_next = 0;
|
||||||
|
if (thread->state == THREAD_WAITING) {
|
||||||
|
thread->state = THREAD_READY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void wait_queue_wake_all(struct wait_queue *queue)
|
||||||
|
{
|
||||||
|
while (queue != 0 && queue->head != 0) {
|
||||||
|
wait_queue_wake_one(queue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void thread_trampoline(void)
|
static void thread_trampoline(void)
|
||||||
{
|
{
|
||||||
struct thread *thread = current_thread;
|
struct thread *thread = current_thread;
|
||||||
@ -218,12 +331,42 @@ static void scheduler_demo_entry(void *arg)
|
|||||||
uint64_t step;
|
uint64_t step;
|
||||||
|
|
||||||
for (step = 1; step <= 3; step++) {
|
for (step = 1; step <= 3; step++) {
|
||||||
early_log_puts("thread ");
|
early_log_puts("preempt thread ");
|
||||||
early_log_u64_decimal(id);
|
early_log_u64_decimal(id);
|
||||||
early_log_puts(" step=");
|
early_log_puts(" step=");
|
||||||
early_log_u64_decimal(step);
|
early_log_u64_decimal(step);
|
||||||
early_log_puts("\n");
|
early_log_puts("\n");
|
||||||
sched_yield();
|
sched_sleep(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct wait_queue demo_wait_queue;
|
||||||
|
|
||||||
|
static void wait_queue_demo_waiter(void *arg)
|
||||||
|
{
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
|
early_log_puts("waiter sleeping\n");
|
||||||
|
wait_queue_sleep(&demo_wait_queue);
|
||||||
|
early_log_puts("waiter woke\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wait_queue_demo_waker(void *arg)
|
||||||
|
{
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
|
early_log_puts("waker sleeping\n");
|
||||||
|
sched_sleep(4);
|
||||||
|
early_log_puts("waker wake_one\n");
|
||||||
|
wait_queue_wake_one(&demo_wait_queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void idle_thread_entry(void *arg)
|
||||||
|
{
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
__asm__ volatile("hlt");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,6 +378,7 @@ void sched_init(void)
|
|||||||
|
|
||||||
run_queue_head = 0;
|
run_queue_head = 0;
|
||||||
run_queue_tail = 0;
|
run_queue_tail = 0;
|
||||||
|
idle_thread = 0;
|
||||||
scheduler_ready = 1;
|
scheduler_ready = 1;
|
||||||
|
|
||||||
early_log_puts("scheduler initialized\n");
|
early_log_puts("scheduler initialized\n");
|
||||||
@ -247,11 +391,18 @@ void sched_start(void)
|
|||||||
"round-robin-a", scheduler_demo_entry, (void *)(uintptr_t)1);
|
"round-robin-a", scheduler_demo_entry, (void *)(uintptr_t)1);
|
||||||
struct thread *second = kernel_thread_create(
|
struct thread *second = kernel_thread_create(
|
||||||
"round-robin-b", scheduler_demo_entry, (void *)(uintptr_t)2);
|
"round-robin-b", scheduler_demo_entry, (void *)(uintptr_t)2);
|
||||||
|
struct thread *waiter =
|
||||||
|
kernel_thread_create("waiter", wait_queue_demo_waiter, 0);
|
||||||
|
struct thread *waker =
|
||||||
|
kernel_thread_create("waker", wait_queue_demo_waker, 0);
|
||||||
|
idle_thread = kernel_thread_create("idle", idle_thread_entry, 0);
|
||||||
|
|
||||||
if (first == 0 || second == 0) {
|
if (first == 0 || second == 0 || waiter == 0 || waker == 0 ||
|
||||||
|
idle_thread == 0) {
|
||||||
panic("scheduler demo thread creation failed");
|
panic("scheduler demo thread creation failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wait_queue_init(&demo_wait_queue);
|
||||||
early_log_puts("scheduler starting\n");
|
early_log_puts("scheduler starting\n");
|
||||||
sched_yield();
|
sched_yield();
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include <tianole/early_log.h>
|
#include <tianole/early_log.h>
|
||||||
|
#include <tianole/sched.h>
|
||||||
#include <tianole/timer.h>
|
#include <tianole/timer.h>
|
||||||
|
|
||||||
static uint64_t tick_count;
|
static uint64_t tick_count;
|
||||||
@ -14,6 +15,8 @@ void timer_tick(void)
|
|||||||
early_log_u64_decimal(tick_count);
|
early_log_u64_decimal(tick_count);
|
||||||
early_log_puts("\n");
|
early_log_puts("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sched_tick(tick_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t timer_ticks(void)
|
uint64_t timer_ticks(void)
|
||||||
|
|||||||
@ -27,12 +27,16 @@ check_lines build/debug.log \
|
|||||||
"kernel thread selftest ok" \
|
"kernel thread selftest ok" \
|
||||||
"timer initialized" \
|
"timer initialized" \
|
||||||
"scheduler starting" \
|
"scheduler starting" \
|
||||||
"thread 1 step=1" \
|
"preempt thread 1 step=1" \
|
||||||
"thread 2 step=1" \
|
"preempt thread 2 step=1" \
|
||||||
"thread 1 step=2" \
|
"waiter sleeping" \
|
||||||
"thread 2 step=2" \
|
"waker sleeping" \
|
||||||
"thread 1 step=3" \
|
"preempt thread 1 step=2" \
|
||||||
"thread 2 step=3" \
|
"preempt thread 2 step=2" \
|
||||||
|
"preempt thread 1 step=3" \
|
||||||
|
"preempt thread 2 step=3" \
|
||||||
|
"waker wake_one" \
|
||||||
|
"waiter woke" \
|
||||||
"timer tick=1" \
|
"timer tick=1" \
|
||||||
"timer tick=2" \
|
"timer tick=2" \
|
||||||
"timer tick=3"
|
"timer tick=3"
|
||||||
@ -54,12 +58,16 @@ check_lines build/serial.log \
|
|||||||
"kernel thread selftest ok" \
|
"kernel thread selftest ok" \
|
||||||
"timer initialized" \
|
"timer initialized" \
|
||||||
"scheduler starting" \
|
"scheduler starting" \
|
||||||
"thread 1 step=1" \
|
"preempt thread 1 step=1" \
|
||||||
"thread 2 step=1" \
|
"preempt thread 2 step=1" \
|
||||||
"thread 1 step=2" \
|
"waiter sleeping" \
|
||||||
"thread 2 step=2" \
|
"waker sleeping" \
|
||||||
"thread 1 step=3" \
|
"preempt thread 1 step=2" \
|
||||||
"thread 2 step=3" \
|
"preempt thread 2 step=2" \
|
||||||
|
"preempt thread 1 step=3" \
|
||||||
|
"preempt thread 2 step=3" \
|
||||||
|
"waker wake_one" \
|
||||||
|
"waiter woke" \
|
||||||
"timer tick=1" \
|
"timer tick=1" \
|
||||||
"timer tick=2" \
|
"timer tick=2" \
|
||||||
"timer tick=3"
|
"timer tick=3"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user