mirror of
https://github.com/rdmsr/zag.git
synced 2026-10-29 14:38:21 +00:00
128 lines
4.0 KiB
Zig
128 lines
4.0 KiB
Zig
const std = @import("std");
|
|
const b = @import("base");
|
|
const rtl = @import("rtl");
|
|
|
|
const ke = b.ke;
|
|
const ki = ke.private;
|
|
|
|
/// Structure representing a kernel thread.
|
|
pub const Thread = struct {
|
|
/// Thread priority classes.
|
|
/// Realtime: Highest priority, aggressively scheduled.
|
|
/// Batch: Normal priority.
|
|
/// Idle: For idle and background threads.
|
|
pub const Priority = struct {
|
|
pub const Class = enum(u8) {
|
|
Realtime,
|
|
Batch,
|
|
Idle,
|
|
};
|
|
|
|
pub const idle = 0;
|
|
pub const low_batch = 1;
|
|
pub const high_batch = 32;
|
|
pub const batch_range = high_batch - low_batch + 1;
|
|
pub const realtime = 33;
|
|
pub const max = 63;
|
|
/// In the mid-range of batch threads
|
|
pub const default = 16;
|
|
/// Interactive threads have a slightly higher priority
|
|
pub const interactive = 20;
|
|
|
|
pub fn class_from_prio(prio: u8) Class {
|
|
if (prio >= realtime and prio <= max) return .Realtime;
|
|
if (prio >= low_batch and prio <= high_batch) return .Batch;
|
|
if (prio == idle) return .Idle;
|
|
|
|
unreachable;
|
|
}
|
|
};
|
|
|
|
/// Thread state.
|
|
pub const State = enum(u8) {
|
|
/// The thread is ready to run.
|
|
Ready,
|
|
/// The thread is currently running.
|
|
Running,
|
|
/// The thread is currently sleeping.
|
|
Blocked,
|
|
/// The thread has exited and is waiting to be reaped.
|
|
Zombie,
|
|
/// The thread has exited.
|
|
Terminated,
|
|
};
|
|
/// Implementation-dependent context.
|
|
context: ki.impl.ThreadContext,
|
|
/// Thread lock.
|
|
lock: ke.SpinLock,
|
|
/// Niceness value.
|
|
nice: i8,
|
|
/// Priority value of the thread.
|
|
priority: u8,
|
|
/// Priority class of the thread.
|
|
priority_class: Priority.Class,
|
|
/// When the thread started sleeping.
|
|
sleep_start: u64,
|
|
/// Ticks spent voluntarily sleeping recently.
|
|
sleep_time: u64,
|
|
/// Ticks spent running recently.
|
|
run_time: u64,
|
|
/// Whether the thread is interactive or not.
|
|
interactive: bool,
|
|
/// Whether the thread is pinned to this CPU.
|
|
/// If it is pinned, then it can't be moved across another CPU.
|
|
pinned: bool,
|
|
/// Current state of the thread.
|
|
state: State,
|
|
/// Linkage into a scheduler run queue.
|
|
runq_link: rtl.List.Entry,
|
|
/// Last CPU this thread ran on.
|
|
last_cpu: ?u32,
|
|
/// Run queue this thread is in
|
|
runq: ?*ki.sched.RunQueue,
|
|
/// Index into the run queue this thread is currently in.
|
|
/// Only valid when `runq` is non-null.
|
|
runq_idx: u8,
|
|
/// Current wait status.
|
|
wait_status: std.atomic.Value(ki.wait.Status),
|
|
waitblocks: [4]ki.wait.WaitBlock,
|
|
|
|
/// Timer used for timeouts.
|
|
timer: ke.Timer,
|
|
|
|
/// Initialize a thread.
|
|
/// - `stack`: Address of the **base** of the stack on which the initial context for the thread is built
|
|
/// - `stack_size`: Size of the stack
|
|
/// - `entry`: Entry point of the thread
|
|
/// - `arg`: Extraneous argument to be passed to `entry`
|
|
pub fn init(thread: *Thread, stack: b.VAddr, stack_size: usize, entry: *const fn (?*anyopaque) void, arg: ?*anyopaque) void {
|
|
thread.* = .{
|
|
.context = .init(stack, stack_size, entry, arg),
|
|
.lock = .init(),
|
|
.nice = 0,
|
|
.priority = Thread.Priority.default,
|
|
.priority_class = Thread.Priority.Class.Batch,
|
|
.sleep_start = 0,
|
|
.sleep_time = 0,
|
|
.run_time = 0,
|
|
.interactive = false,
|
|
.pinned = false,
|
|
.state = .Ready,
|
|
.runq_link = .{},
|
|
.last_cpu = null,
|
|
.runq = null,
|
|
.runq_idx = 0,
|
|
.wait_status = .init(.InProgress),
|
|
.waitblocks = undefined,
|
|
.timer = undefined,
|
|
};
|
|
|
|
thread.timer.init();
|
|
}
|
|
};
|
|
|
|
comptime {
|
|
if (!@hasDecl(ki.impl, "ThreadContext")) @compileError("impl must provide ThreadContext");
|
|
if (!@hasDecl(ki.impl.ThreadContext, "init")) @compileError("ThreadContext must have init()");
|
|
}
|