refactor: move async runtime into kernel-util
This commit is contained in:
parent
2da98eaaa8
commit
e78784d96d
@ -7,4 +7,7 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
yggdrasil-abi = { git = "https://git.alnyan.me/yggdrasil/yggdrasil-abi.git" }
|
||||
|
||||
log = "0.4.20"
|
||||
futures-util = { version = "0.3.28", default-features = false, features = ["alloc", "async-await"] }
|
||||
crossbeam-queue = { version = "0.3.8", default-features = false, features = ["alloc"] }
|
||||
|
@ -1,6 +1,12 @@
|
||||
use yggdrasil_abi::error::Error;
|
||||
use core::time::Duration;
|
||||
|
||||
use crate::mem::{address::PhysicalAddress, device::RawDeviceMemoryMapping};
|
||||
use alloc::{string::String, sync::Arc};
|
||||
use yggdrasil_abi::{error::Error, process::ExitCode};
|
||||
|
||||
use crate::{
|
||||
mem::{address::PhysicalAddress, device::RawDeviceMemoryMapping},
|
||||
thread::{CurrentThread, Thread},
|
||||
};
|
||||
|
||||
extern "Rust" {
|
||||
pub fn __acquire_irq_guard() -> bool;
|
||||
@ -19,4 +25,18 @@ extern "Rust" {
|
||||
count: usize,
|
||||
) -> Result<RawDeviceMemoryMapping, Error>;
|
||||
pub fn __unmap_device_pages(mapping: &RawDeviceMemoryMapping);
|
||||
|
||||
// SAFETY: Both the kernel-side and api-side Threads are sized and Arc<___> has the same value
|
||||
// for them
|
||||
pub fn __create_kthread(
|
||||
name: String,
|
||||
func: extern "C" fn(usize) -> !,
|
||||
arg: usize,
|
||||
) -> Result<Arc<Thread>, Error>;
|
||||
pub fn __enqueue(t: &Arc<Thread>);
|
||||
pub fn __current_thread() -> CurrentThread;
|
||||
pub fn __suspend_current(t: &CurrentThread) -> Result<(), Error>;
|
||||
pub fn __exit_current(t: &CurrentThread, code: ExitCode) -> !;
|
||||
|
||||
pub fn __monotonic_timestamp() -> Result<Duration, Error>;
|
||||
}
|
||||
|
@ -5,7 +5,9 @@
|
||||
const_trait_impl,
|
||||
effects,
|
||||
slice_ptr_get,
|
||||
strict_provenance
|
||||
strict_provenance,
|
||||
never_type,
|
||||
let_chains
|
||||
)]
|
||||
|
||||
extern crate alloc;
|
||||
@ -13,7 +15,9 @@ extern crate alloc;
|
||||
pub(crate) mod api;
|
||||
|
||||
pub mod mem;
|
||||
pub mod runtime;
|
||||
pub mod sync;
|
||||
pub mod thread;
|
||||
pub mod util;
|
||||
|
||||
#[repr(C)]
|
||||
|
65
lib/kernel-util/src/runtime/executor.rs
Normal file
65
lib/kernel-util/src/runtime/executor.rs
Normal file
@ -0,0 +1,65 @@
|
||||
use core::task::{Context, Poll};
|
||||
|
||||
use alloc::{boxed::Box, format, sync::Arc};
|
||||
use futures_util::{task::waker_ref, Future};
|
||||
use yggdrasil_abi::error::Error;
|
||||
|
||||
use crate::thread::Thread;
|
||||
|
||||
use super::{
|
||||
task::{Task, Termination},
|
||||
task_queue,
|
||||
};
|
||||
|
||||
/// Pushes a task into the executor's queue
|
||||
pub fn enqueue(task: Arc<Task>) -> Result<(), Error> {
|
||||
task_queue::push_task(task)
|
||||
}
|
||||
|
||||
/// Spawns a background worker to execute the tasks from the global queue
|
||||
pub fn spawn_async_worker(index: usize) -> Result<(), Error> {
|
||||
let name = format!("[async-worker-{}]", index);
|
||||
|
||||
Thread::spawn(name, move || {
|
||||
loop {
|
||||
let task = task_queue::pop_task().unwrap(); // queue.block_pop().unwrap();
|
||||
let mut future_slot = task.future.lock();
|
||||
|
||||
if let Some(mut future) = future_slot.take() {
|
||||
let waker = waker_ref(&task);
|
||||
let context = &mut Context::from_waker(&waker);
|
||||
|
||||
if future.as_mut().poll(context).is_pending() {
|
||||
*future_slot = Some(future);
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Creates a new task for the [Future] and queues it for execution in background
|
||||
pub fn spawn<T: Termination, F: Future<Output = T> + Send + 'static>(
|
||||
future: F,
|
||||
) -> Result<(), Error> {
|
||||
enqueue(Task::new(future))
|
||||
}
|
||||
|
||||
/// Runs a [Future] to its completion on the current thread
|
||||
pub fn run_to_completion<'a, T, F: Future<Output = T> + Send + 'a>(future: F) -> Result<T, Error> {
|
||||
let thread = Thread::current();
|
||||
let mut future = Box::pin(future);
|
||||
|
||||
loop {
|
||||
let waker = waker_ref(&thread);
|
||||
let context = &mut Context::from_waker(&waker);
|
||||
|
||||
match future.as_mut().poll(context) {
|
||||
Poll::Ready(value) => break Ok(value),
|
||||
Poll::Pending => {
|
||||
if let Err(error) = thread.suspend() {
|
||||
break Err(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
8
lib/kernel-util/src/runtime/macros.rs
Normal file
8
lib/kernel-util/src/runtime/macros.rs
Normal file
@ -0,0 +1,8 @@
|
||||
#[macro_export]
|
||||
macro_rules! block {
|
||||
($($stmt:tt)*) => {
|
||||
$crate::runtime::run_to_completion(alloc::boxed::Box::pin(async move {
|
||||
$($stmt)*
|
||||
}))
|
||||
};
|
||||
}
|
54
lib/kernel-util/src/runtime/mod.rs
Normal file
54
lib/kernel-util/src/runtime/mod.rs
Normal file
@ -0,0 +1,54 @@
|
||||
use core::{
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
mod executor;
|
||||
mod task;
|
||||
mod task_queue;
|
||||
mod waker;
|
||||
|
||||
pub use executor::{run_to_completion, spawn, spawn_async_worker};
|
||||
use futures_util::Future;
|
||||
pub use task_queue::init_task_queue;
|
||||
pub use waker::QueueWaker;
|
||||
|
||||
use crate::api;
|
||||
|
||||
static SLEEP_WAKER: QueueWaker = QueueWaker::new();
|
||||
|
||||
/// Suspends the task until given duration passes
|
||||
pub fn sleep(duration: Duration) -> impl Future<Output = ()> {
|
||||
struct SleepFuture {
|
||||
deadline: Duration,
|
||||
}
|
||||
|
||||
impl Future for SleepFuture {
|
||||
type Output = ();
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
SLEEP_WAKER.register(cx.waker());
|
||||
let now = unsafe { api::__monotonic_timestamp() }.unwrap();
|
||||
if now >= self.deadline {
|
||||
SLEEP_WAKER.remove(cx.waker());
|
||||
Poll::Ready(())
|
||||
} else {
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let now = unsafe { api::__monotonic_timestamp() }.unwrap();
|
||||
let deadline = now + duration;
|
||||
|
||||
SleepFuture { deadline }
|
||||
}
|
||||
|
||||
/// Updates the runtime's time
|
||||
pub fn tick(_now: Duration) {
|
||||
SLEEP_WAKER.wake_all();
|
||||
}
|
46
lib/kernel-util/src/runtime/task.rs
Normal file
46
lib/kernel-util/src/runtime/task.rs
Normal file
@ -0,0 +1,46 @@
|
||||
use core::fmt;
|
||||
|
||||
use alloc::sync::Arc;
|
||||
use futures_util::{future::BoxFuture, task::ArcWake, Future, FutureExt};
|
||||
|
||||
use crate::sync::IrqSafeSpinlock;
|
||||
|
||||
use super::executor;
|
||||
|
||||
pub trait Termination {
|
||||
fn print(&self);
|
||||
}
|
||||
|
||||
pub struct Task {
|
||||
pub(super) future: IrqSafeSpinlock<Option<BoxFuture<'static, ()>>>,
|
||||
}
|
||||
|
||||
impl ArcWake for Task {
|
||||
fn wake_by_ref(arc_self: &Arc<Self>) {
|
||||
executor::enqueue(arc_self.clone()).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
impl Task {
|
||||
pub fn new<T: Termination, F: Future<Output = T> + Send + 'static>(future: F) -> Arc<Self> {
|
||||
let future = IrqSafeSpinlock::new(Some(
|
||||
async move {
|
||||
future.await.print();
|
||||
}
|
||||
.boxed(),
|
||||
));
|
||||
Arc::new(Self { future })
|
||||
}
|
||||
}
|
||||
|
||||
impl Termination for () {
|
||||
fn print(&self) {}
|
||||
}
|
||||
|
||||
impl<T, E: fmt::Debug> Termination for Result<T, E> {
|
||||
fn print(&self) {
|
||||
if let Err(error) = self {
|
||||
log::error!("A task finished with an error: {:?}", error);
|
||||
}
|
||||
}
|
||||
}
|
70
lib/kernel-util/src/runtime/task_queue.rs
Normal file
70
lib/kernel-util/src/runtime/task_queue.rs
Normal file
@ -0,0 +1,70 @@
|
||||
use alloc::sync::Arc;
|
||||
use crossbeam_queue::ArrayQueue;
|
||||
use yggdrasil_abi::error::Error;
|
||||
|
||||
use crate::{sync::IrqGuard, thread::Thread, util::OneTimeInit};
|
||||
|
||||
use super::task::Task;
|
||||
|
||||
pub(super) static TASK_QUEUE: OneTimeInit<TaskQueue> = OneTimeInit::new();
|
||||
|
||||
pub(super) struct TaskQueue {
|
||||
// Queue of workers waiting for an item
|
||||
pending_workers: ArrayQueue<Arc<Thread>>,
|
||||
task_queue: ArrayQueue<Arc<Task>>,
|
||||
}
|
||||
|
||||
impl TaskQueue {
|
||||
pub fn new(task_capacity: usize) -> Self {
|
||||
assert!(task_capacity > 0);
|
||||
Self {
|
||||
pending_workers: ArrayQueue::new(16),
|
||||
task_queue: ArrayQueue::new(task_capacity),
|
||||
}
|
||||
}
|
||||
|
||||
fn wakeup_one(&self) {
|
||||
if let Some(worker) = self.pending_workers.pop() {
|
||||
worker.enqueue();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enqueue(&self, task: Arc<Task>) -> Result<(), Error> {
|
||||
let _irq = IrqGuard::acquire();
|
||||
if self.task_queue.push(task).is_err() {
|
||||
todo!();
|
||||
}
|
||||
self.wakeup_one();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn dequeue(&self) -> Result<Arc<Task>, Error> {
|
||||
let thread = Thread::current();
|
||||
// assert!(ArchitectureImpl::interrupt_mask());
|
||||
loop {
|
||||
if let Some(task) = self.task_queue.pop() {
|
||||
return Ok(task);
|
||||
}
|
||||
|
||||
if self.pending_workers.push(thread.clone()).is_err() {
|
||||
panic!("Pending worker queue overflow");
|
||||
}
|
||||
|
||||
// This must not fail. Signals must not be raised.
|
||||
thread.suspend().unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Initializes the global async/await task queue
|
||||
pub fn init_task_queue() {
|
||||
TASK_QUEUE.init(TaskQueue::new(128));
|
||||
}
|
||||
|
||||
pub(super) fn push_task(task: Arc<Task>) -> Result<(), Error> {
|
||||
TASK_QUEUE.get().enqueue(task)
|
||||
}
|
||||
|
||||
pub(super) fn pop_task() -> Result<Arc<Task>, Error> {
|
||||
TASK_QUEUE.get().dequeue()
|
||||
}
|
72
lib/kernel-util/src/runtime/waker.rs
Normal file
72
lib/kernel-util/src/runtime/waker.rs
Normal file
@ -0,0 +1,72 @@
|
||||
use core::task::Waker;
|
||||
|
||||
use alloc::collections::VecDeque;
|
||||
|
||||
use crate::sync::IrqSafeSpinlock;
|
||||
|
||||
/// Async/await primitive to suspend and wake up tasks waiting on some shared resource
|
||||
pub struct QueueWaker {
|
||||
queue: IrqSafeSpinlock<VecDeque<Waker>>,
|
||||
}
|
||||
|
||||
impl QueueWaker {
|
||||
/// Constructs an empty [QueueWaker]
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
queue: IrqSafeSpinlock::new(VecDeque::new()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Registers a [Waker] reference to be waken up by this [QueueWaker]
|
||||
pub fn register(&self, waker: &Waker) {
|
||||
let mut queue = self.queue.lock();
|
||||
|
||||
if queue.iter().any(|other| other.will_wake(waker)) {
|
||||
return;
|
||||
}
|
||||
|
||||
queue.push_back(waker.clone());
|
||||
}
|
||||
|
||||
/// Removes a [Waker] reference from this [QueueWaker]
|
||||
pub fn remove(&self, waker: &Waker) -> bool {
|
||||
let mut queue = self.queue.lock();
|
||||
let mut index = 0;
|
||||
let mut removed = false;
|
||||
|
||||
while index < queue.len() {
|
||||
if queue[index].will_wake(waker) {
|
||||
removed = true;
|
||||
queue.remove(index);
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
|
||||
removed
|
||||
}
|
||||
|
||||
/// Wakes up up to `limit` tasks waiting on this queue
|
||||
pub fn wake_some(&self, limit: usize) -> usize {
|
||||
let mut queue = self.queue.lock();
|
||||
let mut count = 0;
|
||||
|
||||
while count < limit
|
||||
&& let Some(item) = queue.pop_front()
|
||||
{
|
||||
item.wake();
|
||||
count += 1;
|
||||
}
|
||||
|
||||
count
|
||||
}
|
||||
|
||||
/// Wakes up a single task waiting on this queue
|
||||
pub fn wake_one(&self) -> bool {
|
||||
self.wake_some(1) != 0
|
||||
}
|
||||
|
||||
/// Wakes up all tasks waiting on this queue
|
||||
pub fn wake_all(&self) -> usize {
|
||||
self.wake_some(usize::MAX)
|
||||
}
|
||||
}
|
102
lib/kernel-util/src/thread.rs
Normal file
102
lib/kernel-util/src/thread.rs
Normal file
@ -0,0 +1,102 @@
|
||||
use core::{fmt, ops::Deref};
|
||||
|
||||
use alloc::{boxed::Box, string::String, sync::Arc};
|
||||
use futures_util::task::ArcWake;
|
||||
use yggdrasil_abi::{error::Error, process::ExitCode};
|
||||
|
||||
use crate::{api, sync::IrqGuard};
|
||||
|
||||
#[repr(C)]
|
||||
pub(crate) struct Thread(!);
|
||||
#[repr(C)]
|
||||
pub(crate) struct CurrentThread(Arc<Thread>, IrqGuard);
|
||||
|
||||
/// Conversion trait to allow multiple kernel closure return types
|
||||
pub trait Termination {
|
||||
/// Converts the closure return type into [ExitCode]
|
||||
fn into_exit_code(self) -> ExitCode;
|
||||
}
|
||||
|
||||
impl<T, E: fmt::Debug> Termination for Result<T, E> {
|
||||
fn into_exit_code(self) -> ExitCode {
|
||||
match self {
|
||||
Ok(_) => ExitCode::SUCCESS,
|
||||
Err(err) => {
|
||||
log::warn!("Kernel thread failed: {:?}", err);
|
||||
ExitCode::Exited(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Termination for ExitCode {
|
||||
fn into_exit_code(self) -> ExitCode {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Termination for () {
|
||||
fn into_exit_code(self) -> ExitCode {
|
||||
ExitCode::SUCCESS
|
||||
}
|
||||
}
|
||||
|
||||
impl Thread {
|
||||
pub fn spawn<S: Into<String>, F: FnOnce() + Send + 'static>(
|
||||
name: S,
|
||||
f: F,
|
||||
) -> Result<(), Error> {
|
||||
extern "C" fn closure_wrapper<F: FnOnce() + Send + 'static>(closure_addr: usize) -> ! {
|
||||
let closure = unsafe { Box::from_raw(closure_addr as *mut F) };
|
||||
let result = closure();
|
||||
Thread::current().exit(result.into_exit_code());
|
||||
unreachable!();
|
||||
}
|
||||
|
||||
let closure = Box::new(f);
|
||||
log::debug!("closure: {:p}", closure);
|
||||
let thread = unsafe {
|
||||
api::__create_kthread(
|
||||
name.into(),
|
||||
closure_wrapper::<F>,
|
||||
Box::into_raw(closure) as usize,
|
||||
)
|
||||
}?;
|
||||
|
||||
thread.enqueue();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn current() -> CurrentThread {
|
||||
unsafe { api::__current_thread() }
|
||||
}
|
||||
|
||||
pub fn enqueue(self: &Arc<Self>) {
|
||||
unsafe { api::__enqueue(self) }
|
||||
}
|
||||
}
|
||||
|
||||
impl CurrentThread {
|
||||
pub fn suspend(&self) -> Result<(), Error> {
|
||||
unsafe { api::__suspend_current(self) }
|
||||
}
|
||||
|
||||
pub fn exit(&self, code: ExitCode) {
|
||||
unsafe { api::__exit_current(self, code) }
|
||||
}
|
||||
}
|
||||
|
||||
impl ArcWake for Thread {
|
||||
fn wake_by_ref(arc_self: &Arc<Self>) {
|
||||
arc_self.clone().enqueue()
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for CurrentThread {
|
||||
type Target = Arc<Thread>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
//! Provides architecture/platform-specific implementation details
|
||||
|
||||
use core::time::Duration;
|
||||
|
||||
use abi::error::Error;
|
||||
|
||||
/// Returns an absolute address to the given symbol
|
||||
@ -264,3 +266,8 @@ fn __map_device_pages(
|
||||
fn __unmap_device_pages(mapping: &RawDeviceMemoryMapping) {
|
||||
unsafe { ARCHITECTURE.unmap_device_memory(mapping) }
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
fn __monotonic_timestamp() -> Result<Duration, Error> {
|
||||
ARCHITECTURE.monotonic_timer().monotonic_timestamp()
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
//! x86-64 boot and entry functions
|
||||
use core::{arch::global_asm, sync::atomic::Ordering};
|
||||
|
||||
use kernel_util::runtime;
|
||||
use tock_registers::interfaces::Writeable;
|
||||
use yboot_proto::{
|
||||
v1::{FramebufferOption, MemoryMap},
|
||||
@ -12,7 +13,6 @@ use crate::{
|
||||
fs::devfs,
|
||||
kernel_main, kernel_secondary_main,
|
||||
mem::KERNEL_VIRT_OFFSET,
|
||||
task::runtime,
|
||||
};
|
||||
|
||||
use super::{cpuid::init_cpuid, exception, ARCHITECTURE};
|
||||
|
@ -2,17 +2,14 @@ use core::time::Duration;
|
||||
|
||||
use abi::error::Error;
|
||||
use device_api::{interrupt::InterruptHandler, timer::MonotonicTimestampProviderDevice, Device};
|
||||
use kernel_util::sync::IrqSafeSpinlock;
|
||||
use kernel_util::{runtime, sync::IrqSafeSpinlock};
|
||||
|
||||
use crate::{
|
||||
arch::{
|
||||
x86_64::{
|
||||
intrinsics::{IoPort, IoPortAccess},
|
||||
IrqNumber,
|
||||
},
|
||||
Architecture, ARCHITECTURE,
|
||||
use crate::arch::{
|
||||
x86_64::{
|
||||
intrinsics::{IoPort, IoPortAccess},
|
||||
IrqNumber,
|
||||
},
|
||||
task::runtime,
|
||||
Architecture, ARCHITECTURE,
|
||||
};
|
||||
|
||||
const FREQUENCY: u32 = 1193180;
|
||||
|
@ -5,9 +5,9 @@ use core::time::Duration;
|
||||
use abi::{error::Error, primitive_enum};
|
||||
use alloc::{vec, vec::Vec};
|
||||
use bitflags::bitflags;
|
||||
use kernel_util::{sync::IrqSafeSpinlock, util::StaticVector};
|
||||
use kernel_util::{runtime, sync::IrqSafeSpinlock, util::StaticVector};
|
||||
|
||||
use crate::{debug::DebugSink, task::runtime};
|
||||
use crate::debug::DebugSink;
|
||||
|
||||
const CONSOLE_ROW_LEN: usize = 80;
|
||||
const MAX_CSI_ARGS: usize = 8;
|
||||
|
@ -9,6 +9,7 @@ use kernel_util::{
|
||||
address::{FromRaw, IntoRaw, PhysicalAddress},
|
||||
device::{DeviceMemoryIo, DeviceMemoryIoMut},
|
||||
},
|
||||
runtime,
|
||||
sync::IrqSafeSpinlock,
|
||||
util::OneTimeInit,
|
||||
};
|
||||
@ -31,7 +32,6 @@ use crate::{
|
||||
drive::NvmeDrive,
|
||||
queue::{CompletionQueueEntry, SubmissionQueueEntry},
|
||||
},
|
||||
task::runtime,
|
||||
};
|
||||
|
||||
use self::{
|
||||
|
@ -17,12 +17,11 @@ use kernel_util::{
|
||||
address::{AsPhysicalAddress, IntoRaw, PhysicalAddress},
|
||||
PageBox,
|
||||
},
|
||||
runtime::QueueWaker,
|
||||
sync::IrqSafeSpinlock,
|
||||
};
|
||||
use static_assertions::const_assert;
|
||||
|
||||
use crate::task::runtime::QueueWaker;
|
||||
|
||||
use super::{
|
||||
command::{Command, Request},
|
||||
error::NvmeError,
|
||||
|
@ -1,10 +1 @@
|
||||
//! Timer device utilities
|
||||
|
||||
use core::time::Duration;
|
||||
|
||||
use crate::task::runtime;
|
||||
|
||||
/// Global system timer tick handler
|
||||
pub fn tick(now: Duration) {
|
||||
runtime::tick(now);
|
||||
}
|
||||
|
@ -15,12 +15,13 @@ use crate::{
|
||||
#[cfg(feature = "fb_console")]
|
||||
pub mod combined {
|
||||
//! Combined console + keyboard terminal device
|
||||
use crate::{block, task::process::ProcessId};
|
||||
use crate::task::process::ProcessId;
|
||||
use abi::{
|
||||
error::Error,
|
||||
io::{DeviceRequest, TerminalSize},
|
||||
};
|
||||
use device_api::{input::KeyboardConsumer, serial::SerialDevice};
|
||||
use kernel_util::block;
|
||||
use vfs::CharDevice;
|
||||
// use vfs::CharDevice;
|
||||
|
||||
|
@ -28,7 +28,8 @@ pub fn kinit() -> Result<(), Error> {
|
||||
|
||||
#[cfg(feature = "fb_console")]
|
||||
{
|
||||
use crate::{device::display::console::update_consoles_task, task::runtime};
|
||||
use crate::device::display::console::update_consoles_task;
|
||||
use kernel_util::runtime;
|
||||
|
||||
runtime::spawn(async move {
|
||||
update_consoles_task().await;
|
||||
|
@ -8,19 +8,17 @@ use abi::{
|
||||
syscall::SyscallFunction,
|
||||
};
|
||||
use alloc::sync::Arc;
|
||||
use kernel_util::sync::IrqSafeSpinlockGuard;
|
||||
use kernel_util::{block, runtime, sync::IrqSafeSpinlockGuard};
|
||||
use vfs::{IoContext, NodeRef, Read, Seek, Write};
|
||||
use yggdrasil_abi::{error::SyscallResult, io::MountOptions};
|
||||
|
||||
use crate::{
|
||||
block,
|
||||
debug::LogLevel,
|
||||
fs,
|
||||
mem::{phys, table::MapAttributes},
|
||||
proc::{self, io::ProcessIo, random},
|
||||
task::{
|
||||
process::{Process, ProcessId},
|
||||
runtime,
|
||||
thread::Thread,
|
||||
},
|
||||
};
|
||||
@ -134,10 +132,12 @@ fn syscall_handler(func: SyscallFunction, args: &[u64]) -> Result<usize, Error>
|
||||
let file = io.ioctx().open(at, path, opts, mode)?;
|
||||
|
||||
// TODO NO_CTTY?
|
||||
if process.session_terminal().is_none() &&
|
||||
let Some(node) = file.node() && node.is_terminal() {
|
||||
debugln!("Session terminal set for #{}: {}", process.id(), path);
|
||||
process.set_session_terminal(node.clone());
|
||||
if process.session_terminal().is_none()
|
||||
&& let Some(node) = file.node()
|
||||
&& node.is_terminal()
|
||||
{
|
||||
debugln!("Session terminal set for #{}: {}", process.id(), path);
|
||||
process.set_session_terminal(node.clone());
|
||||
}
|
||||
|
||||
let fd = io.place_file(file)?;
|
||||
|
@ -1,10 +1,9 @@
|
||||
//! Platform-specific task context manipulation interfaces
|
||||
|
||||
use core::fmt;
|
||||
|
||||
use abi::{arch::SavedFrame, error::Error, process::ExitCode};
|
||||
use abi::{arch::SavedFrame, error::Error};
|
||||
use alloc::boxed::Box;
|
||||
use cfg_if::cfg_if;
|
||||
use kernel_util::thread::Termination;
|
||||
|
||||
use crate::task::thread::Thread;
|
||||
|
||||
@ -18,36 +17,6 @@ cfg_if! {
|
||||
}
|
||||
}
|
||||
|
||||
/// Conversion trait to allow multiple kernel closure return types
|
||||
pub trait Termination {
|
||||
/// Converts the closure return type into [ExitCode]
|
||||
fn into_exit_code(self) -> ExitCode;
|
||||
}
|
||||
|
||||
impl<T, E: fmt::Debug> Termination for Result<T, E> {
|
||||
fn into_exit_code(self) -> ExitCode {
|
||||
match self {
|
||||
Ok(_) => ExitCode::SUCCESS,
|
||||
Err(err) => {
|
||||
warnln!("Kernel thread failed: {:?}", err);
|
||||
ExitCode::Exited(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Termination for ExitCode {
|
||||
fn into_exit_code(self) -> ExitCode {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Termination for () {
|
||||
fn into_exit_code(self) -> ExitCode {
|
||||
ExitCode::SUCCESS
|
||||
}
|
||||
}
|
||||
|
||||
/// Interface for task state save/restore mechanisms
|
||||
pub trait TaskFrame {
|
||||
/// Creates a "snapshot" of a exception/syscall frame
|
||||
|
@ -4,18 +4,17 @@
|
||||
|
||||
use abi::error::Error;
|
||||
use alloc::{string::String, vec::Vec};
|
||||
use kernel_util::sync::SpinFence;
|
||||
use kernel_util::{runtime, sync::SpinFence, thread::Termination};
|
||||
|
||||
use crate::{
|
||||
arch::{Architecture, ArchitectureImpl},
|
||||
task::{sched::CpuQueue, thread::Thread},
|
||||
};
|
||||
|
||||
use self::context::{TaskContextImpl, Termination};
|
||||
use self::context::TaskContextImpl;
|
||||
|
||||
pub mod context;
|
||||
pub mod process;
|
||||
pub mod runtime;
|
||||
pub mod sched;
|
||||
pub mod sync;
|
||||
pub mod thread;
|
||||
|
@ -14,7 +14,7 @@ use abi::{
|
||||
};
|
||||
use alloc::{collections::BTreeMap, string::String, sync::Arc, vec::Vec};
|
||||
use futures_util::Future;
|
||||
use kernel_util::sync::IrqSafeSpinlock;
|
||||
use kernel_util::{runtime::QueueWaker, sync::IrqSafeSpinlock};
|
||||
use vfs::NodeRef;
|
||||
|
||||
use crate::{
|
||||
@ -24,7 +24,6 @@ use crate::{
|
||||
};
|
||||
|
||||
use super::{
|
||||
runtime::QueueWaker,
|
||||
sync::UserspaceMutex,
|
||||
thread::{Thread, ThreadId},
|
||||
TaskContext,
|
||||
|
@ -1,5 +1,51 @@
|
||||
//! Async/await runtime implementation
|
||||
|
||||
// use core::{
|
||||
// pin::Pin,
|
||||
// task::{Context, Poll},
|
||||
// time::Duration,
|
||||
// };
|
||||
//
|
||||
// use futures_util::Future;
|
||||
//
|
||||
// use crate::arch::{Architecture, ARCHITECTURE};
|
||||
//
|
||||
// mod executor;
|
||||
// mod macros;
|
||||
// mod task;
|
||||
// mod task_queue;
|
||||
// mod waker;
|
||||
//
|
||||
// pub use executor::{run_to_completion, spawn, spawn_async_worker};
|
||||
// pub use task_queue::init_task_queue;
|
||||
// pub use waker::QueueWaker;
|
||||
//
|
||||
// /// [Future] implementation that wraps a poll-function
|
||||
// pub struct PollFn<F> {
|
||||
// f: F,
|
||||
// }
|
||||
//
|
||||
// impl<T, F> Future for PollFn<F>
|
||||
// where
|
||||
// F: FnMut(&mut Context) -> Poll<T>,
|
||||
// {
|
||||
// type Output = T;
|
||||
//
|
||||
// fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
// #[allow(clippy::needless_borrow)]
|
||||
// (unsafe { &mut self.get_unchecked_mut().f })(cx)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /// Constructs a [PollFn] from given poll-function
|
||||
// pub fn poll_fn<T, F>(f: F) -> PollFn<F>
|
||||
// where
|
||||
// F: FnMut(&mut Context) -> Poll<T>,
|
||||
// {
|
||||
// PollFn { f }
|
||||
// }
|
||||
//
|
||||
|
||||
use core::{
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
@ -7,80 +53,6 @@ use core::{
|
||||
};
|
||||
|
||||
use futures_util::Future;
|
||||
use kernel_util::runtime::QueueWaker;
|
||||
|
||||
use crate::arch::{Architecture, ARCHITECTURE};
|
||||
|
||||
mod executor;
|
||||
mod macros;
|
||||
mod task;
|
||||
mod task_queue;
|
||||
mod waker;
|
||||
|
||||
pub use executor::{run_to_completion, spawn, spawn_async_worker};
|
||||
pub use task_queue::init_task_queue;
|
||||
pub use waker::QueueWaker;
|
||||
|
||||
/// [Future] implementation that wraps a poll-function
|
||||
pub struct PollFn<F> {
|
||||
f: F,
|
||||
}
|
||||
|
||||
impl<T, F> Future for PollFn<F>
|
||||
where
|
||||
F: FnMut(&mut Context) -> Poll<T>,
|
||||
{
|
||||
type Output = T;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
#[allow(clippy::needless_borrow)]
|
||||
(unsafe { &mut self.get_unchecked_mut().f })(cx)
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs a [PollFn] from given poll-function
|
||||
pub fn poll_fn<T, F>(f: F) -> PollFn<F>
|
||||
where
|
||||
F: FnMut(&mut Context) -> Poll<T>,
|
||||
{
|
||||
PollFn { f }
|
||||
}
|
||||
|
||||
static SLEEP_WAKER: QueueWaker = QueueWaker::new();
|
||||
|
||||
/// Suspends the task until given duration passes
|
||||
pub fn sleep(duration: Duration) -> impl Future<Output = ()> {
|
||||
struct SleepFuture {
|
||||
deadline: Duration,
|
||||
}
|
||||
|
||||
impl Future for SleepFuture {
|
||||
type Output = ();
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
SLEEP_WAKER.register(cx.waker());
|
||||
let now = ARCHITECTURE
|
||||
.monotonic_timer()
|
||||
.monotonic_timestamp()
|
||||
.unwrap();
|
||||
if now >= self.deadline {
|
||||
SLEEP_WAKER.remove(cx.waker());
|
||||
Poll::Ready(())
|
||||
} else {
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let now = ARCHITECTURE
|
||||
.monotonic_timer()
|
||||
.monotonic_timestamp()
|
||||
.unwrap();
|
||||
let deadline = now + duration;
|
||||
|
||||
SleepFuture { deadline }
|
||||
}
|
||||
|
||||
/// Updates the runtime's time
|
||||
pub fn tick(_now: Duration) {
|
||||
SLEEP_WAKER.wake_all();
|
||||
}
|
||||
|
@ -8,8 +8,7 @@ use core::{
|
||||
|
||||
use alloc::sync::Arc;
|
||||
use futures_util::Future;
|
||||
|
||||
use super::runtime::QueueWaker;
|
||||
use kernel_util::runtime::QueueWaker;
|
||||
|
||||
/// User-space mutex (like BSD/Linux's futex) data structure
|
||||
pub struct UserspaceMutex {
|
||||
|
@ -20,17 +20,18 @@ use alloc::{
|
||||
};
|
||||
use atomic_enum::atomic_enum;
|
||||
use futures_util::{task::ArcWake, Future};
|
||||
use kernel_util::sync::{IrqGuard, IrqSafeSpinlock};
|
||||
use kernel_util::{
|
||||
block,
|
||||
runtime::QueueWaker,
|
||||
sync::{IrqGuard, IrqSafeSpinlock},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
block,
|
||||
mem::{process::ProcessAddressSpace, ForeignPointer},
|
||||
task::{context::TaskContextImpl, Cpu},
|
||||
};
|
||||
|
||||
use super::{
|
||||
context::TaskFrame, process::Process, runtime::QueueWaker, sched::CpuQueue, TaskContext,
|
||||
};
|
||||
use super::{context::TaskFrame, process::Process, sched::CpuQueue, TaskContext};
|
||||
|
||||
/// Represents the states a thread can be at some point in time
|
||||
#[atomic_enum]
|
||||
@ -56,6 +57,7 @@ pub enum ThreadId {
|
||||
}
|
||||
|
||||
/// Wrapper which guarantees the thread referred to is the current one on the current CPU
|
||||
#[repr(C)]
|
||||
pub struct CurrentThread(Arc<Thread>, IrqGuard);
|
||||
|
||||
struct SignalEntry {
|
||||
@ -545,3 +547,36 @@ impl fmt::Display for ThreadId {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// External API
|
||||
|
||||
#[no_mangle]
|
||||
fn __create_kthread(
|
||||
name: String,
|
||||
func: extern "C" fn(usize) -> !,
|
||||
arg: usize,
|
||||
) -> Result<Arc<Thread>, Error> {
|
||||
let context = TaskContext::kernel(func, arg)?;
|
||||
Ok(Thread::new_kthread(name, context))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
fn __enqueue(t: &Arc<Thread>) {
|
||||
t.enqueue_somewhere();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
fn __current_thread() -> CurrentThread {
|
||||
Thread::current()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
fn __suspend_current(t: &CurrentThread) -> Result<(), Error> {
|
||||
t.suspend()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
fn __exit_current(t: &CurrentThread, code: ExitCode) -> ! {
|
||||
t.exit(code);
|
||||
unreachable!();
|
||||
}
|
||||
|
@ -8,8 +8,7 @@ use core::{
|
||||
use alloc::sync::Arc;
|
||||
use crossbeam_queue::ArrayQueue;
|
||||
use futures_util::Future;
|
||||
|
||||
use crate::task::runtime::QueueWaker;
|
||||
use kernel_util::runtime::QueueWaker;
|
||||
|
||||
/// Asynchronous queue
|
||||
pub struct AsyncQueue<T> {
|
||||
|
@ -8,9 +8,7 @@ use core::{
|
||||
use abi::error::Error;
|
||||
use alloc::sync::Arc;
|
||||
use futures_util::Future;
|
||||
use kernel_util::sync::IrqSafeSpinlock;
|
||||
|
||||
use crate::task::runtime::QueueWaker;
|
||||
use kernel_util::{runtime::QueueWaker, sync::IrqSafeSpinlock};
|
||||
|
||||
/// Ring buffer base
|
||||
pub struct RingBuffer<T, const N: usize> {
|
||||
|
Loading…
x
Reference in New Issue
Block a user