use core::ptr;
use tg_kernel_context::LocalContext;
use tg_syscall::{Caller, SyscallId};
const SYSCALL_RECORD_CAPACITY: usize = 16;
#[derive(Clone, Copy)]
struct SyscallCounterSlot {
id: SyscallId,
count: usize,
}
impl SyscallCounterSlot {
const ZERO: Self = Self {
id: SyscallId(0),
count: 0,
};
}
static mut CURRENT_TASK: *mut TaskControlBlock = ptr::null_mut();
pub struct TaskControlBlock {
ctx: LocalContext,
pub finish: bool,
stack: [usize; 1024],
syscall_counters: [SyscallCounterSlot; SYSCALL_RECORD_CAPACITY],
}
pub enum SchedulingEvent {
None,
Yield,
Exit(usize),
UnsupportedSyscall(SyscallId),
}
impl TaskControlBlock {
pub const ZERO: Self = Self {
ctx: LocalContext::empty(),
finish: false,
stack: [0; 1024],
syscall_counters: [SyscallCounterSlot::ZERO; SYSCALL_RECORD_CAPACITY],
};
pub fn init(&mut self, entry: usize) {
self.stack.fill(0);
self.finish = false;
self.syscall_counters.fill(SyscallCounterSlot::ZERO);
self.ctx = LocalContext::user(entry);
*self.ctx.sp_mut() = self.stack.as_ptr() as usize + core::mem::size_of_val(&self.stack);
}
#[inline]
pub unsafe fn execute(&mut self) {
unsafe { self.ctx.execute() };
}
pub fn handle_syscall(&mut self) -> SchedulingEvent {
use SchedulingEvent as Event;
use tg_syscall::{SyscallId as Id, SyscallResult as Ret};
let id = self.ctx.a(7).into();
let args = [
self.ctx.a(0),
self.ctx.a(1),
self.ctx.a(2),
self.ctx.a(3),
self.ctx.a(4),
self.ctx.a(5),
];
self.record_syscall(id);
set_current_task(self as *mut _);
let result = tg_syscall::handle(Caller { entity: 0, flow: 0 }, id, args);
set_current_task(ptr::null_mut());
match result {
Ret::Done(ret) => match id {
Id::EXIT => Event::Exit(self.ctx.a(0)),
Id::SCHED_YIELD => {
*self.ctx.a_mut(0) = ret as _;
self.ctx.move_next(); Event::Yield
}
_ => {
*self.ctx.a_mut(0) = ret as _;
self.ctx.move_next(); Event::None
}
},
Ret::Unsupported(_) => Event::UnsupportedSyscall(id),
}
}
fn record_syscall(&mut self, id: SyscallId) {
for slot in &mut self.syscall_counters {
if slot.count != 0 && slot.id == id {
slot.count += 1;
return;
}
}
for slot in &mut self.syscall_counters {
if slot.count == 0 {
*slot = SyscallCounterSlot { id, count: 1 };
return;
}
}
}
pub(super) fn syscall_count(&self, id: usize) -> usize {
self.syscall_counters
.iter()
.find(|slot| slot.count != 0 && slot.id.0 == id)
.map_or(0, |slot| slot.count)
}
}
#[inline]
fn set_current_task(task: *mut TaskControlBlock) {
unsafe { CURRENT_TASK = task };
}
pub(super) fn current_task() -> Option<&'static mut TaskControlBlock> {
let task = unsafe { CURRENT_TASK };
if task.is_null() {
None
} else {
Some(unsafe { &mut *task })
}
}