refactor(sched): centralize thread state transitions
- docs/agents: add kernel design guide
This commit is contained in:
parent
f97c30d5d0
commit
7292b9eb56
@ -7,6 +7,7 @@
|
|||||||
建议内容:
|
建议内容:
|
||||||
|
|
||||||
- `code-style.md`:agent 修改代码时必须遵守的代码组织和风格规则。
|
- `code-style.md`:agent 修改代码时必须遵守的代码组织和风格规则。
|
||||||
|
- `kernel-design.md`:顶层内核设计约束,说明子系统边界、调用方向、生命周期和设计变更流程。
|
||||||
- `linux-layout.md`:Tianole 和 Linux 顶层目录的映射与取舍。
|
- `linux-layout.md`:Tianole 和 Linux 顶层目录的映射与取舍。
|
||||||
- `session-notes/`:实现日志和阶段结论。
|
- `session-notes/`:实现日志和阶段结论。
|
||||||
- `tasks/`:适合 agent 执行的边界清晰任务,按路线阶段拆分。
|
- `tasks/`:适合 agent 执行的边界清晰任务,按路线阶段拆分。
|
||||||
@ -18,6 +19,7 @@
|
|||||||
当前任务入口:
|
当前任务入口:
|
||||||
|
|
||||||
- `code-style.md`:代码风格和文件组织规则。
|
- `code-style.md`:代码风格和文件组织规则。
|
||||||
|
- `kernel-design.md`:顶层内核设计约束。
|
||||||
- `linux-layout.md`:Linux 顶层目录映射。
|
- `linux-layout.md`:Linux 顶层目录映射。
|
||||||
- `tasks/README.md`:agent 任务索引。
|
- `tasks/README.md`:agent 任务索引。
|
||||||
- `tasks/02-cpu-interrupts.md`:下一阶段,GDT/TSS/IDT、异常入口和 trap frame。
|
- `tasks/02-cpu-interrupts.md`:下一阶段,GDT/TSS/IDT、异常入口和 trap frame。
|
||||||
|
|||||||
272
docs/agents/kernel-design.md
Normal file
272
docs/agents/kernel-design.md
Normal file
@ -0,0 +1,272 @@
|
|||||||
|
# Kernel Design Guide
|
||||||
|
|
||||||
|
本文档记录 Tianole 当前阶段的顶层内核设计约束。它不是最终架构说明,也不是 Linux 的缩小版;它的作用是让后续实现不再只围绕单个文件局部修补,而是先确认子系统边界、调用方向和生命周期规则。
|
||||||
|
|
||||||
|
当代码改动影响目录职责、公共结构体、跨子系统 API、锁语义、生命周期或启动阶段顺序时,应该同步更新本文档或对应任务文档。
|
||||||
|
|
||||||
|
## 设计原则
|
||||||
|
|
||||||
|
- 参考 Linux 的分层和长期演进方式,但不照搬 Linux 的历史复杂度。
|
||||||
|
- 入口代码只编排流程,不承载具体策略。
|
||||||
|
- 子系统通过明确 API 交互,不直接访问对方内部结构。
|
||||||
|
- 公共结构体越少越好;公共头文件暴露的是契约,不是临时实现细节。
|
||||||
|
- 当前可以是单 CPU、单地址空间、简单调度,但接口不能把这些简化写成永久事实。
|
||||||
|
- 能力先闭环,再收紧边界;收紧边界时要补文档和自测。
|
||||||
|
|
||||||
|
## 顶层目录职责
|
||||||
|
|
||||||
|
- `arch/`:架构相关代码,包括启动入口、GDT/TSS/IDT、trap/IRQ entry、上下文切换、架构 timer、页表格式、TLB 和 CPU 指令封装。
|
||||||
|
- `kernel/`:架构无关的核心内核逻辑,包括 early log 前端、panic、IRQ 分发、调度、锁、时间抽象、进程和 syscall 的长期位置。
|
||||||
|
- `mm/`:架构无关内存管理,包括物理页、heap、后续 page metadata、buddy/slab、VMA、page cache 和回收。
|
||||||
|
- `drivers/`:设备驱动和设备模型,包括 input、block、PCI、ACPI、platform、GPU、network、sound 等。
|
||||||
|
- `block/`:通用块层。具体硬件驱动在 `drivers/`,块请求调度和块设备抽象在 `block/`。
|
||||||
|
- `fs/`:VFS 和具体文件系统。VFS 不依赖 shell、ELF loader 或具体块设备。
|
||||||
|
- `include/tianole/`:架构无关公共内核 API。只有跨子系统调用方真正需要的类型和函数才能放这里。
|
||||||
|
- `arch/<arch>/include/`:架构公开 API,例如中断控制、I/O port、上下文切换声明。
|
||||||
|
- `kernel/selftest/`:启动阶段自测和当前阶段演示线程,不放进具体实现目录。
|
||||||
|
- `scripts/`:构建、检查、QEMU 启动和结构规则工具。
|
||||||
|
- `docs/`:面向人的设计、路线和约束文档。
|
||||||
|
|
||||||
|
## 调用方向
|
||||||
|
|
||||||
|
允许的主要调用方向:
|
||||||
|
|
||||||
|
- `kernel/` 可以调用 `arch_` 前缀的架构 API。
|
||||||
|
- `kernel/` 可以调用 `mm/` 提供的分配和映射 API。
|
||||||
|
- `drivers/` 可以调用 IRQ、timer、wait queue、workqueue、MM 和 bus/resource API。
|
||||||
|
- `fs/` 可以调用 `mm/`、`block/` 和锁/等待 API。
|
||||||
|
- `user/` 或 `usr/` 里的用户程序只能通过 syscall/libc/VFS 暴露的接口进入 kernel。
|
||||||
|
|
||||||
|
禁止或需要重新设计的调用方向:
|
||||||
|
|
||||||
|
- 通用层不能直接读取 x86 页表编码、PIC/PIT 端口或 IDT gate 格式。
|
||||||
|
- 驱动不能直接调用 shell、VFS 内部对象或调度器内部链表。
|
||||||
|
- shell 和用户态工具不能包含 kernel 私有头或读取 kernel 内部结构体。
|
||||||
|
- 文件系统不能直接控制具体磁盘硬件。
|
||||||
|
- keyboard/input driver 不能直接操作 terminal 或 shell。
|
||||||
|
- boot/selftest 代码不能混进核心实现文件。
|
||||||
|
|
||||||
|
## 公共头文件规则
|
||||||
|
|
||||||
|
`include/tianole/` 只能放公共契约:
|
||||||
|
|
||||||
|
- 跨子系统需要调用的函数声明。
|
||||||
|
- 调用方必须知道的 opaque handle 或稳定结构。
|
||||||
|
- 明确属于公共 ABI 的枚举、flag 和错误码。
|
||||||
|
|
||||||
|
避免放入公共头文件:
|
||||||
|
|
||||||
|
- 只被一个子系统内部使用的字段。
|
||||||
|
- 具体链表节点、缓存节点、临时统计字段。
|
||||||
|
- 架构私有 bit 编码和寄存器布局。
|
||||||
|
- 调试或 selftest 专用结构。
|
||||||
|
|
||||||
|
如果公共结构体开始泄漏太多内部字段,优先考虑:
|
||||||
|
|
||||||
|
- 把结构改成 opaque。
|
||||||
|
- 拆出私有头,例如 `kernel/sched/sched.h`。
|
||||||
|
- 提供 accessor 或 helper,而不是让调用方直接改字段。
|
||||||
|
|
||||||
|
当前允许的阶段性妥协:
|
||||||
|
|
||||||
|
- `struct thread` 和 `struct wait_queue` 仍在公共头中暴露,方便早期调度和自测推进。
|
||||||
|
- 后续收紧调度状态机时,应逐步减少外部直接写 `thread->state`、`wait_next`、`next` 等字段。
|
||||||
|
|
||||||
|
## 启动阶段边界
|
||||||
|
|
||||||
|
启动路径按阶段推进:
|
||||||
|
|
||||||
|
1. bootloader 收集 boot info、memory map、kernel image。
|
||||||
|
2. kernel entry 建立最小运行环境。
|
||||||
|
3. early log 和 panic 可用。
|
||||||
|
4. trap/IRQ 基础可用。
|
||||||
|
5. MM 基础可用:物理页、页表、heap。
|
||||||
|
6. timer、thread、scheduler、wait queue 可用。
|
||||||
|
7. input、VFS、user mode、drivers 逐步接入。
|
||||||
|
|
||||||
|
启动阶段约束:
|
||||||
|
|
||||||
|
- early log/panic 不能依赖 heap、scheduler 或 VFS。
|
||||||
|
- trap/IRQ 初始化不能依赖复杂驱动模型。
|
||||||
|
- MM 初始化前不能使用 `kmalloc()`。
|
||||||
|
- scheduler 初始化前不能 sleep 或 wait。
|
||||||
|
- 驱动初始化不能假设 shell、VFS 或用户态已经存在。
|
||||||
|
|
||||||
|
## 中断、锁和 deferred work
|
||||||
|
|
||||||
|
中断路径分层:
|
||||||
|
|
||||||
|
- arch entry 保存现场并进入 C trap/IRQ 分发。
|
||||||
|
- IRQ core 根据 IRQ number 调用注册 handler。
|
||||||
|
- 具体设备 handler 做最短路径工作。
|
||||||
|
- 复杂处理应推迟到 deferred work、workqueue 或线程上下文。
|
||||||
|
|
||||||
|
锁规则:
|
||||||
|
|
||||||
|
- 中断和普通内核路径共享的数据,先使用 `spin_lock_irqsave()` 建立单 CPU 正确语义。
|
||||||
|
- 持有不可睡眠锁时不能调用 `sched_yield()`、`sched_sleep()` 或 wait queue sleep。
|
||||||
|
- 可睡眠路径和不可睡眠路径要从 API 命名、文档或调用约束上区分。
|
||||||
|
- 后续 SMP 前,需要把当前单 CPU lock 语义整理成可扩展接口。
|
||||||
|
|
||||||
|
等待规则:
|
||||||
|
|
||||||
|
- wait queue 负责“入队、睡眠、唤醒”的同步边界。
|
||||||
|
- 条件等待遵循“检查条件、入队睡眠、醒后重新检查”的模式。
|
||||||
|
- 唤醒方先修改受保护条件,再调用 wakeup。
|
||||||
|
- 条件所属数据如果不在 wait queue 内部,必须明确由哪把锁保护。
|
||||||
|
|
||||||
|
## 调度与线程生命周期
|
||||||
|
|
||||||
|
调度子系统职责:
|
||||||
|
|
||||||
|
- run queue 维护。
|
||||||
|
- 当前线程选择和上下文切换。
|
||||||
|
- thread state 转换。
|
||||||
|
- sleep/wakeup 和 wait queue 交互。
|
||||||
|
- DEAD/ZOMBIE 线程的安全回收。
|
||||||
|
|
||||||
|
调度状态机应逐步收紧:
|
||||||
|
|
||||||
|
- `READY -> RUNNING -> READY`
|
||||||
|
- `RUNNING -> SLEEPING/WAITING`
|
||||||
|
- `SLEEPING/WAITING -> READY`
|
||||||
|
- `RUNNING -> DEAD`
|
||||||
|
- 未来加入 `ZOMBIE` 支撑 join/wait 和进程退出。
|
||||||
|
|
||||||
|
约束:
|
||||||
|
|
||||||
|
- 外部子系统不应直接修改 run queue。
|
||||||
|
- 外部子系统不应长期直接写 `thread->state`。
|
||||||
|
- 当前线程不能释放自身内核栈。
|
||||||
|
- 线程入口返回必须进入统一 exit 路径。
|
||||||
|
- IRQ 中不直接做完整线程切换;调度请求应在明确的 interrupt-exit 边界消费。
|
||||||
|
|
||||||
|
## 内存、VFS 和缓存边界
|
||||||
|
|
||||||
|
MM 层负责:
|
||||||
|
|
||||||
|
- boot memory map 转换成内核长期内存区域模型。
|
||||||
|
- 物理页分配和 page metadata。
|
||||||
|
- 内核 heap 和后续 slab/slub。
|
||||||
|
- 用户地址空间、VMA、page fault 策略。
|
||||||
|
- page cache 和内存回收。
|
||||||
|
|
||||||
|
VFS 层负责:
|
||||||
|
|
||||||
|
- superblock、inode、dentry、file 等对象边界。
|
||||||
|
- path lookup。
|
||||||
|
- open/read/write/close/readdir 等通用文件操作。
|
||||||
|
- mount、权限、时间戳和错误码语义的长期位置。
|
||||||
|
|
||||||
|
block 层负责:
|
||||||
|
|
||||||
|
- block device 抽象。
|
||||||
|
- block request 和完成状态。
|
||||||
|
- 具体硬件驱动与 VFS 之间的隔离。
|
||||||
|
|
||||||
|
约束:
|
||||||
|
|
||||||
|
- 具体文件系统不直接访问磁盘硬件。
|
||||||
|
- 具体块设备驱动不解析文件系统。
|
||||||
|
- page cache 不属于某个具体文件系统或驱动。
|
||||||
|
- ELF loader 通过 VFS 读文件,不直接读取块设备或 initramfs 私有结构。
|
||||||
|
|
||||||
|
## 设备模型与驱动边界
|
||||||
|
|
||||||
|
长期设备模型包含:
|
||||||
|
|
||||||
|
- device
|
||||||
|
- driver
|
||||||
|
- bus
|
||||||
|
- resource
|
||||||
|
- probe/remove
|
||||||
|
- IRQ/DMA/MMIO/PIO resource 管理
|
||||||
|
|
||||||
|
驱动约束:
|
||||||
|
|
||||||
|
- probe 失败必须释放已申请资源。
|
||||||
|
- 驱动不修改无关子系统内部状态。
|
||||||
|
- 驱动不能长期 busy wait;应使用 IRQ、wait queue 或 deferred work。
|
||||||
|
- QEMU 专用设备支持不能破坏真机路径。
|
||||||
|
- ACPI/PCI/Device Tree 等平台信息隔离在平台层,通用驱动消费抽象资源。
|
||||||
|
|
||||||
|
输入路径:
|
||||||
|
|
||||||
|
- keyboard driver 产生 input event。
|
||||||
|
- input core 提供队列和等待。
|
||||||
|
- terminal/tty 消费 input event 并生成字节流或行。
|
||||||
|
- shell 读取 terminal,不读取 scancode。
|
||||||
|
|
||||||
|
存储路径:
|
||||||
|
|
||||||
|
- storage driver 接入 block layer。
|
||||||
|
- block layer 服务 filesystem。
|
||||||
|
- VFS 服务 kernel loader、用户态程序和 shell。
|
||||||
|
|
||||||
|
## 用户态与 syscall 边界
|
||||||
|
|
||||||
|
用户态相关对象要分开:
|
||||||
|
|
||||||
|
- process
|
||||||
|
- thread
|
||||||
|
- address space
|
||||||
|
- open file table
|
||||||
|
- credentials
|
||||||
|
- signal state
|
||||||
|
|
||||||
|
syscall 规则:
|
||||||
|
|
||||||
|
- syscall number、参数寄存器、返回值和错误码必须稳定记录。
|
||||||
|
- 用户指针必须复制和检查,不能直接解引用。
|
||||||
|
- syscall handler 不暴露 kernel 内部结构体。
|
||||||
|
- 用户态异常终止进程或转换成后续 signal,不能默认 panic。
|
||||||
|
- `fork/exec/wait`、signal、pipe、poll/select、futex 等长期路径要在 ABI 上预留。
|
||||||
|
|
||||||
|
用户程序规则:
|
||||||
|
|
||||||
|
- shell 和工具通过 libc 或 syscall ABI 访问 kernel。
|
||||||
|
- 用户程序不包含 kernel 私有头。
|
||||||
|
- 调试信息通过 syscall、procfs/debugfs 或等价虚拟文件接口暴露。
|
||||||
|
|
||||||
|
## 测试和回归边界
|
||||||
|
|
||||||
|
测试分层:
|
||||||
|
|
||||||
|
- `kernel/selftest/`:启动阶段内核自测,验证当前内核能力。
|
||||||
|
- `scripts/checks/`:主机侧检查,例如 build、boot、trap、page fault、structure。
|
||||||
|
- `scripts/tools/`:项目结构和自定义规则工具。
|
||||||
|
|
||||||
|
规则:
|
||||||
|
|
||||||
|
- 具体实现目录不放 selftest 主体。
|
||||||
|
- 新增公共 API 要有自测或 boot check 观察点。
|
||||||
|
- 调整目录边界要更新 `docs/agents/linux-layout.md`、`code-style.md` 或本文档。
|
||||||
|
- `scripts/check.sh` 是本地和 CI 的完整回归入口。
|
||||||
|
- 只改文档至少运行 `git diff --check`。
|
||||||
|
|
||||||
|
## 设计变更流程
|
||||||
|
|
||||||
|
遇到以下情况,先更新设计或任务文档,再改代码:
|
||||||
|
|
||||||
|
- 新增顶层目录或改变目录职责。
|
||||||
|
- 公共头文件新增跨子系统结构体。
|
||||||
|
- 修改 thread、wait queue、page、inode、file、process 等核心对象生命周期。
|
||||||
|
- 新增锁规则、等待规则或 IRQ 调用约束。
|
||||||
|
- 引入新硬件路径或新驱动模型。
|
||||||
|
- 新增 syscall ABI 或用户态可见行为。
|
||||||
|
|
||||||
|
遇到以下情况,可以直接小步改代码,但完成后要同步文档:
|
||||||
|
|
||||||
|
- 当前任务文档已经明确要求的局部实现。
|
||||||
|
- 不改变 API 的内部重构。
|
||||||
|
- selftest 或 check 脚本补强。
|
||||||
|
- 修复明显 bug,且不改变子系统边界。
|
||||||
|
|
||||||
|
## 当前主线
|
||||||
|
|
||||||
|
当前主线仍是 `docs/agents/tasks/04-time-scheduler.md`:
|
||||||
|
|
||||||
|
- wait queue 内部锁已经建立。
|
||||||
|
- 下一步应收紧 thread state helper,减少外部直接写状态。
|
||||||
|
- 然后继续完善 thread lifecycle 和 interrupt-exit reschedule。
|
||||||
|
- 在这些边界稳定前,不进入 keyboard/input 代码实现。
|
||||||
@ -152,6 +152,7 @@
|
|||||||
- 已把 `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 线程的内核栈和线程对象。
|
||||||
|
- 已在调度私有头中加入 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、条件等待和超时等待。
|
||||||
|
|
||||||
@ -160,7 +161,7 @@
|
|||||||
### A. 调度状态机收紧
|
### A. 调度状态机收紧
|
||||||
|
|
||||||
- 明确合法状态转换,例如 `READY -> RUNNING -> READY`、`RUNNING -> SLEEPING/WAITING`、`SLEEPING/WAITING -> READY`、`RUNNING -> DEAD`。
|
- 明确合法状态转换,例如 `READY -> RUNNING -> READY`、`RUNNING -> SLEEPING/WAITING`、`SLEEPING/WAITING -> READY`、`RUNNING -> DEAD`。
|
||||||
- 增加状态转换辅助函数,减少外部代码直接写 `thread->state`。
|
- 继续扩大状态转换辅助函数覆盖范围,减少外部代码直接写 `thread->state`。
|
||||||
- 自测非法状态转换和重复入队问题。
|
- 自测非法状态转换和重复入队问题。
|
||||||
|
|
||||||
### B. wait queue 锁语义
|
### B. wait queue 锁语义
|
||||||
|
|||||||
@ -45,19 +45,19 @@ static struct thread *next_runnable_thread(void)
|
|||||||
|
|
||||||
thread = start;
|
thread = start;
|
||||||
while (thread != 0) {
|
while (thread != 0) {
|
||||||
if (thread->state == THREAD_READY && thread != idle_thread) {
|
if (thread_is_ready(thread) && 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 && thread != idle_thread) {
|
if (thread_is_ready(thread) && thread != idle_thread) {
|
||||||
return thread;
|
return thread;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (idle_thread != 0 && idle_thread->state == THREAD_READY) {
|
if (thread_is_ready(idle_thread)) {
|
||||||
return idle_thread;
|
return idle_thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,10 +69,8 @@ static void wake_sleeping_threads(uint64_t tick)
|
|||||||
struct thread *thread;
|
struct thread *thread;
|
||||||
|
|
||||||
for (thread = run_queue_head; thread != 0; thread = thread->next) {
|
for (thread = run_queue_head; thread != 0; thread = thread->next) {
|
||||||
if (thread->state == THREAD_SLEEPING &&
|
if (thread_is_sleeping(thread) && thread->wake_tick <= tick) {
|
||||||
thread->wake_tick <= tick) {
|
thread_set_ready(thread);
|
||||||
thread->wake_tick = 0;
|
|
||||||
thread->state = THREAD_READY;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -97,11 +95,11 @@ void sched_yield(void)
|
|||||||
|
|
||||||
schedule_locked = 1;
|
schedule_locked = 1;
|
||||||
|
|
||||||
if (prev != 0 && prev->state == THREAD_RUNNING) {
|
if (thread_is_running(prev)) {
|
||||||
prev->state = THREAD_READY;
|
thread_set_ready(prev);
|
||||||
}
|
}
|
||||||
|
|
||||||
next->state = THREAD_RUNNING;
|
thread_set_running(next);
|
||||||
current_thread = next;
|
current_thread = next;
|
||||||
schedule_locked = 0;
|
schedule_locked = 0;
|
||||||
|
|
||||||
@ -117,7 +115,7 @@ void sched_tick(uint64_t tick)
|
|||||||
{
|
{
|
||||||
wake_sleeping_threads(tick);
|
wake_sleeping_threads(tick);
|
||||||
|
|
||||||
if (current_thread != 0 && current_thread->state == THREAD_RUNNING) {
|
if (thread_is_running(current_thread)) {
|
||||||
need_resched = 1;
|
need_resched = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -141,8 +139,7 @@ void sched_sleep(uint64_t ticks)
|
|||||||
}
|
}
|
||||||
|
|
||||||
now = timer_ticks();
|
now = timer_ticks();
|
||||||
current_thread->wake_tick = now + ticks;
|
thread_set_sleeping(current_thread, now + ticks);
|
||||||
current_thread->state = THREAD_SLEEPING;
|
|
||||||
sched_yield();
|
sched_yield();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -17,6 +17,61 @@ extern int need_resched;
|
|||||||
extern struct thread *idle_thread;
|
extern struct thread *idle_thread;
|
||||||
extern struct spinlock scheduler_lock;
|
extern struct spinlock scheduler_lock;
|
||||||
|
|
||||||
|
static inline int thread_is_ready(const struct thread *thread)
|
||||||
|
{
|
||||||
|
return thread != 0 && thread->state == THREAD_READY;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int thread_is_running(const struct thread *thread)
|
||||||
|
{
|
||||||
|
return thread != 0 && thread->state == THREAD_RUNNING;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int thread_is_sleeping(const struct thread *thread)
|
||||||
|
{
|
||||||
|
return thread != 0 && thread->state == THREAD_SLEEPING;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int thread_is_waiting(const struct thread *thread)
|
||||||
|
{
|
||||||
|
return thread != 0 && thread->state == THREAD_WAITING;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int thread_is_dead(const struct thread *thread)
|
||||||
|
{
|
||||||
|
return thread != 0 && thread->state == THREAD_DEAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void thread_set_ready(struct thread *thread)
|
||||||
|
{
|
||||||
|
thread->wake_tick = 0;
|
||||||
|
thread->state = THREAD_READY;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void thread_set_running(struct thread *thread)
|
||||||
|
{
|
||||||
|
thread->state = THREAD_RUNNING;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void thread_set_sleeping(
|
||||||
|
struct thread *thread, uint64_t wake_tick)
|
||||||
|
{
|
||||||
|
thread->wake_tick = wake_tick;
|
||||||
|
thread->state = THREAD_SLEEPING;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void thread_set_waiting(struct thread *thread)
|
||||||
|
{
|
||||||
|
thread->wake_tick = 0;
|
||||||
|
thread->state = THREAD_WAITING;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void thread_set_dead(struct thread *thread)
|
||||||
|
{
|
||||||
|
thread->wake_tick = 0;
|
||||||
|
thread->state = THREAD_DEAD;
|
||||||
|
}
|
||||||
|
|
||||||
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_selftest(void);
|
void sched_selftest(void);
|
||||||
|
|||||||
@ -77,7 +77,7 @@ struct thread *kernel_thread_create(
|
|||||||
|
|
||||||
stack_top = (uintptr_t)thread->stack_base + KERNEL_STACK_SIZE;
|
stack_top = (uintptr_t)thread->stack_base + KERNEL_STACK_SIZE;
|
||||||
|
|
||||||
thread->state = THREAD_READY;
|
thread_set_ready(thread);
|
||||||
thread->entry = entry;
|
thread->entry = entry;
|
||||||
thread->arg = arg;
|
thread->arg = arg;
|
||||||
thread->stack_top = align_down_uintptr(stack_top, STACK_ALIGNMENT);
|
thread->stack_top = align_down_uintptr(stack_top, STACK_ALIGNMENT);
|
||||||
@ -110,7 +110,7 @@ void sched_reap_dead_threads(void)
|
|||||||
while (thread != 0) {
|
while (thread != 0) {
|
||||||
struct thread *next = thread->next;
|
struct thread *next = thread->next;
|
||||||
|
|
||||||
if (thread->state == THREAD_DEAD && thread != current_thread) {
|
if (thread_is_dead(thread) && thread != current_thread) {
|
||||||
if (prev != 0) {
|
if (prev != 0) {
|
||||||
prev->next = next;
|
prev->next = next;
|
||||||
} else {
|
} else {
|
||||||
@ -139,7 +139,7 @@ static void thread_trampoline(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
thread->entry(thread->arg);
|
thread->entry(thread->arg);
|
||||||
thread->state = THREAD_DEAD;
|
thread_set_dead(thread);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
sched_yield();
|
sched_yield();
|
||||||
|
|||||||
@ -60,10 +60,8 @@ static void wait_queue_remove_locked(
|
|||||||
|
|
||||||
static void wait_queue_mark_ready_locked(struct thread *thread)
|
static void wait_queue_mark_ready_locked(struct thread *thread)
|
||||||
{
|
{
|
||||||
if (thread->state == THREAD_WAITING ||
|
if (thread_is_waiting(thread) || thread_is_sleeping(thread)) {
|
||||||
thread->state == THREAD_SLEEPING) {
|
thread_set_ready(thread);
|
||||||
thread->wake_tick = 0;
|
|
||||||
thread->state = THREAD_READY;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,14 +75,14 @@ void wait_queue_sleep(struct wait_queue *queue)
|
|||||||
|
|
||||||
spin_lock_irqsave(&queue->lock, &flags);
|
spin_lock_irqsave(&queue->lock, &flags);
|
||||||
wait_queue_enqueue_locked(queue, current_thread);
|
wait_queue_enqueue_locked(queue, current_thread);
|
||||||
current_thread->state = THREAD_WAITING;
|
thread_set_waiting(current_thread);
|
||||||
spin_unlock_irqrestore(&queue->lock, flags);
|
spin_unlock_irqrestore(&queue->lock, flags);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
sched_yield();
|
sched_yield();
|
||||||
|
|
||||||
spin_lock_irqsave(&queue->lock, &flags);
|
spin_lock_irqsave(&queue->lock, &flags);
|
||||||
if (current_thread->state != THREAD_WAITING) {
|
if (!thread_is_waiting(current_thread)) {
|
||||||
spin_unlock_irqrestore(&queue->lock, flags);
|
spin_unlock_irqrestore(&queue->lock, flags);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -109,7 +107,7 @@ int wait_queue_wait(
|
|||||||
}
|
}
|
||||||
|
|
||||||
wait_queue_enqueue_locked(queue, current_thread);
|
wait_queue_enqueue_locked(queue, current_thread);
|
||||||
current_thread->state = THREAD_WAITING;
|
thread_set_waiting(current_thread);
|
||||||
spin_unlock_irqrestore(&queue->lock, flags);
|
spin_unlock_irqrestore(&queue->lock, flags);
|
||||||
|
|
||||||
sched_yield();
|
sched_yield();
|
||||||
@ -157,8 +155,7 @@ int wait_queue_wait_timeout(struct wait_queue *queue,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
current_thread->wake_tick = deadline;
|
thread_set_sleeping(current_thread, deadline);
|
||||||
current_thread->state = THREAD_SLEEPING;
|
|
||||||
wait_queue_enqueue_locked(queue, current_thread);
|
wait_queue_enqueue_locked(queue, current_thread);
|
||||||
spin_unlock_irqrestore(&queue->lock, flags);
|
spin_unlock_irqrestore(&queue->lock, flags);
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user