task scheduler weirdness

This commit is contained in:
koniifer 2024-11-26 19:32:19 +00:00
parent 1b3dc153e8
commit 685c6f0b20
5 changed files with 85 additions and 88 deletions

View file

@ -33,7 +33,7 @@ unsafe fn x86_in<T: x86_64::instructions::port::PortRead>(address: u16) -> T {
} }
#[inline(always)] #[inline(always)]
pub fn handler(vm: &mut Vm) { pub fn handler(vm: &mut Vm, pid: &usize) {
let ecall_number = vm.registers[2].cast::<u64>(); let ecall_number = vm.registers[2].cast::<u64>();
match ecall_number { match ecall_number {
@ -209,7 +209,6 @@ pub fn handler(vm: &mut Vm) {
let buffer_id = vm.registers[3].cast::<u64>(); let buffer_id = vm.registers[3].cast::<u64>();
let map_ptr = vm.registers[4].cast::<u64>(); let map_ptr = vm.registers[4].cast::<u64>();
let max_length = vm.registers[5].cast::<u64>(); let max_length = vm.registers[5].cast::<u64>();
let mut buffs = IPC_BUFFERS.lock(); let mut buffs = IPC_BUFFERS.lock();
let buff: &mut IpcBuffer = match buffs.get_mut(&buffer_id) { let buff: &mut IpcBuffer = match buffs.get_mut(&buffer_id) {
Some(buff) => buff, Some(buff) => buff,

View file

@ -65,7 +65,12 @@ impl<'p> Future for ExecThread {
return Poll::Ready(Err(err)); return Poll::Ready(Err(err));
} }
Ok(VmRunOk::End) => return Poll::Ready(Ok(())), Ok(VmRunOk::End) => return Poll::Ready(Ok(())),
Ok(VmRunOk::Ecall) => ecah::handler(&mut self.vm), Ok(VmRunOk::Ecall) => ecah::handler(
&mut self.vm,
cx.ext()
.downcast_ref()
.expect("PID did not exist in Context"),
),
Ok(VmRunOk::Timer) => (), Ok(VmRunOk::Timer) => (),
Ok(VmRunOk::Breakpoint) => { Ok(VmRunOk::Breakpoint) => {
log::error!( log::error!(

View file

@ -122,7 +122,7 @@ pub fn kmain(_cmdline: &str, boot_modules: BootModules) -> ! {
if cmd_len > 0 { if cmd_len > 0 {
thr.set_arguments(cmd.as_ptr() as u64, cmd_len); thr.set_arguments(cmd.as_ptr() as u64, cmd_len);
} }
executor.spawn(Box::pin(async move { executor.spawn(Box::pin(async {
if let Err(e) = thr.await { if let Err(e) = thr.await {
log::error!("{e:?}"); log::error!("{e:?}");
} }

View file

@ -10,9 +10,11 @@
abi_x86_interrupt, abi_x86_interrupt,
lazy_get, lazy_get,
alloc_error_handler, alloc_error_handler,
local_waker,
context_ext,
ptr_sub_ptr, ptr_sub_ptr,
naked_functions, naked_functions,
pointer_is_aligned_to, pointer_is_aligned_to
)] )]
#![allow(dead_code, internal_features, static_mut_refs)] #![allow(dead_code, internal_features, static_mut_refs)]
extern crate alloc; extern crate alloc;
@ -35,8 +37,7 @@ mod utils;
// #[cfg(feature = "tests")] // #[cfg(feature = "tests")]
mod ktest; mod ktest;
use alloc::string::ToString; use {alloc::string::ToString, versioning::Version};
use versioning::Version;
/// Kernel's version /// Kernel's version
pub const VERSION: Version = Version { pub const VERSION: Version = Version {

View file

@ -3,7 +3,8 @@ use {
core::{ core::{
future::Future, future::Future,
pin::Pin, pin::Pin,
task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, sync::atomic::{AtomicBool, Ordering},
task::{Context, ContextBuilder, Poll, RawWaker, RawWakerVTable, Waker},
}, },
crossbeam_queue::SegQueue, crossbeam_queue::SegQueue,
slab::Slab, slab::Slab,
@ -14,7 +15,6 @@ pub fn yield_now() -> impl Future<Output = ()> {
impl Future for YieldNow { impl Future for YieldNow {
type Output = (); type Output = ();
#[inline(always)]
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if self.0 { if self.0 {
Poll::Ready(()) Poll::Ready(())
@ -29,53 +29,70 @@ pub fn yield_now() -> impl Future<Output = ()> {
YieldNow(false) YieldNow(false)
} }
pub trait Process: Future<Output = ()> + Send {}
impl<T: Future<Output = ()> + Send> Process for T {}
pub struct Executor { pub struct Executor {
tasks: Slab<Task>, tasks: Slab<Task>,
task_queue: Arc<TaskQueue>, task_queue: Arc<SegQueue<usize>>,
} }
impl Executor { impl Executor {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
tasks: Slab::new(), tasks: Slab::new(),
task_queue: Arc::new(TaskQueue::new()), task_queue: Arc::new(SegQueue::new()),
} }
} }
#[inline] pub fn spawn(&mut self, future: Pin<Box<dyn Process>>) -> usize {
pub fn spawn(&mut self, future: Pin<Box<dyn Future<Output = ()> + Send>>) -> usize {
let id = self.tasks.insert(Task::new(future)); let id = self.tasks.insert(Task::new(future));
self.task_queue.queue.push(id); self.task_queue.push(id);
id id
} }
pub fn pause(&mut self, id: usize) {
if let Some(task) = self.tasks.get(id) {
task.set_paused(true);
}
}
pub fn unpause(&mut self, id: usize) {
if let Some(task) = self.tasks.get(id) {
task.set_paused(false);
self.task_queue.push(id);
}
}
pub fn run(&mut self) { pub fn run(&mut self) {
let mut task_batch = [0; 32]; let mut task_batch = [0; 32];
loop {
let mut batch_len = 0; let mut batch_len = 0;
loop { while let Some(id) = self.task_queue.pop() {
self.task_queue.batch_pop(&mut task_batch, &mut batch_len); task_batch[batch_len] = id;
batch_len += 1;
if batch_len == task_batch.len() {
break;
}
}
if batch_len == 0 { if batch_len == 0 {
if self.task_queue.is_empty() {
break; break;
} else { }
for &(mut id) in &task_batch[..batch_len] {
if let Some(task) = self.tasks.get_mut(id) {
if task.is_paused() {
continue; continue;
} }
}
for &id in &task_batch[..batch_len] { let waker = create_waker(id, Arc::clone(&self.task_queue));
if let Some(task) = self.tasks.get_mut(id) { let mut cx = ContextBuilder::from_waker(&waker).ext(&mut id).build();
let waker = task
.waker
.get_or_insert_with(|| TaskWaker::new(id, Arc::clone(&self.task_queue)));
let waker = unsafe { Waker::from_raw(TaskWaker::into_raw_waker(waker)) };
let mut cx = Context::from_waker(&waker);
if let Poll::Ready(()) = task.poll(&mut cx) { if let Poll::Ready(()) = task.poll(&mut cx) {
self.tasks.remove(id); self.tasks.remove(id);
self.task_queue.free_tasks.push(id);
} }
} }
} }
@ -84,95 +101,70 @@ impl Executor {
} }
struct Task { struct Task {
future: Pin<Box<dyn Future<Output = ()> + Send>>, future: Pin<Box<dyn Process>>,
waker: Option<TaskWaker>, paused: AtomicBool,
} }
impl Task { impl Task {
#[inline(always)] fn new(future: Pin<Box<dyn Process>>) -> Self {
pub fn new(future: Pin<Box<dyn Future<Output = ()> + Send>>) -> Self {
Self { Self {
future, future,
waker: None, paused: AtomicBool::new(false),
} }
} }
#[inline(always)]
fn poll(&mut self, cx: &mut Context) -> Poll<()> { fn poll(&mut self, cx: &mut Context) -> Poll<()> {
self.future.as_mut().poll(cx) self.future.as_mut().poll(cx)
} }
fn is_paused(&self) -> bool {
self.paused.load(Ordering::Acquire)
}
fn set_paused(&self, paused: bool) {
self.paused.store(paused, Ordering::Release)
}
} }
fn create_waker(task_id: usize, task_queue: Arc<SegQueue<usize>>) -> Waker {
let data = Box::new(TaskWaker {
task_id,
task_queue,
});
let raw_waker = RawWaker::new(Box::into_raw(data) as *const (), &VTABLE);
unsafe { Waker::from_raw(raw_waker) }
}
#[derive(Clone)]
struct TaskWaker { struct TaskWaker {
id: usize, task_id: usize,
task_queue: Arc<TaskQueue>, task_queue: Arc<SegQueue<usize>>,
} }
impl TaskWaker { impl TaskWaker {
#[inline(always)]
fn new(id: usize, task_queue: Arc<TaskQueue>) -> Self {
Self { id, task_queue }
}
#[inline(always)]
fn wake(&self) { fn wake(&self) {
self.task_queue.queue.push(self.id); self.task_queue.push(self.task_id);
}
fn into_raw_waker(waker: &TaskWaker) -> RawWaker {
let ptr = waker as *const TaskWaker;
RawWaker::new(ptr.cast(), &VTABLE)
} }
} }
const VTABLE: RawWakerVTable = RawWakerVTable::new(clone_raw, wake_raw, wake_by_ref_raw, drop_raw); const VTABLE: RawWakerVTable = RawWakerVTable::new(clone_raw, wake_raw, wake_by_ref_raw, drop_raw);
unsafe fn clone_raw(ptr: *const ()) -> RawWaker { unsafe fn clone_raw(ptr: *const ()) -> RawWaker {
let waker = &*(ptr as *const TaskWaker); let task_waker = Box::from_raw(ptr as *mut TaskWaker);
TaskWaker::into_raw_waker(waker) let raw_waker = RawWaker::new(Box::into_raw(task_waker.clone()) as *const (), &VTABLE);
raw_waker
} }
unsafe fn wake_raw(ptr: *const ()) { unsafe fn wake_raw(ptr: *const ()) {
let waker = &*(ptr as *const TaskWaker); let task_waker = Box::from_raw(ptr as *mut TaskWaker);
waker.wake(); task_waker.wake();
} }
unsafe fn wake_by_ref_raw(ptr: *const ()) { unsafe fn wake_by_ref_raw(ptr: *const ()) {
let waker = &*(ptr as *const TaskWaker); let task_waker = &*(ptr as *const TaskWaker);
waker.wake(); task_waker.wake();
} }
unsafe fn drop_raw(_: *const ()) {} unsafe fn drop_raw(ptr: *const ()) {
drop(Box::from_raw(ptr as *mut TaskWaker));
struct TaskQueue {
queue: SegQueue<usize>,
next_task: usize,
free_tasks: SegQueue<usize>,
}
impl TaskQueue {
fn new() -> Self {
Self {
queue: SegQueue::new(),
next_task: 0,
free_tasks: SegQueue::new(),
}
}
#[inline(always)]
fn batch_pop(&self, output: &mut [usize], len: &mut usize) {
*len = 0;
while let Some(id) = self.queue.pop() {
output[*len] = id;
*len += 1;
if *len == output.len() {
break;
}
}
}
#[inline(always)]
fn is_empty(&self) -> bool {
self.queue.is_empty()
}
} }