Skip to content

Commit

Permalink
Add trace for portal connect
Browse files Browse the repository at this point in the history
  • Loading branch information
AldaronLau committed Aug 14, 2022
1 parent 278423e commit 698d938
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 41 deletions.
6 changes: 6 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@ documentation = "https://docs.rs/ardaku"
homepage = "https://ardaku.org"
repository = "https://github.com/ardaku/ardaku"

[dependencies.log]
version = "0.4"

[dependencies.wasmi]
version = "0.14"
default-features = false
git = "https://github.com/ardaku/wasmi.git"

[dev-dependencies]
env_logger = "0.9"
75 changes: 59 additions & 16 deletions examples/demo.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,74 @@
use std::io::{self, Write};
use std::sync::Mutex;
use std::task::Poll;
use std::io::BufRead;
use ardaku::IoResult;
use log::Level;

struct System;
struct System {
buffer: Mutex<String>,
read_line: Mutex<Option<(u32, usize, usize)>>,
}

// FIXME: Use smelling_salts with whisk channel

impl ardaku::System for System {
fn sleep(&self) -> (ardaku::Event, u32) {
todo!()
}
unsafe fn sleep(&self, memory: &mut [u8], index: usize, length: usize) -> usize {
let ready_index = index;
let ready_length = length;

fn write(&self, line: &[u8]) {
let mut stdout = io::stdout();
let _ = stdout.write_all(line);
let _ = stdout.write_all(b"\n");
let _ = stdout.flush();
let stdin = std::io::stdin();
let mut handle = stdin.lock();
let mut buffer = self.buffer.lock().unwrap();
handle.read_line(&mut buffer).unwrap();
let mut read_line = self.read_line.lock().unwrap();
if let Some((read_line, index, length)) = read_line.take() {
if memory.get_mut(ready_index..ready_length).map(|x| x.len()) == Some(4) {
if let Some(buf) = memory.get_mut(index..length) {
// Write to readline buffer
let capacity = buf[0..].len();
let length = buffer.len();
/*if length > capacity {
// Need more space!
} else {
}*/
todo!();
// Write to ready list
/*let bytes = read_line.to_le_bytes();
for i in 0..4 {
ready[i] = bytes[i];
}
return 1*/
}
}
}
0
}

fn version(&self) -> u32 {
0xDEADBEEF
fn log(&self, text: &str, level: Level, target: &str) {
log::log!(target: target, level, "{text}")
}

fn reboot(&self) {
std::process::exit(0);

unsafe fn read_line(&self, ready: u32, index: usize, length: usize) {
let mut read_line = self.read_line.lock().unwrap();
*read_line = Some((ready, index, length));
}
}

fn main() -> ardaku::Result<()> {
// Setup
env_logger::init();

let app_path = std::env::args().skip(1).next().expect("Provide wasm file!");
let exe = std::fs::read(app_path).expect("Couldn't find file!");

ardaku::run(System, &exe)
// Run app
let system = System {
buffer: Mutex::new(String::with_capacity(1024)),
read_line: Mutex::new(None),
};

ardaku::run(system, &exe)
}
113 changes: 88 additions & 25 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,43 @@
extern crate alloc;

use core::mem::MaybeUninit;
use core::task::Poll;
use wasmi::core::Trap;
use wasmi::{Caller, Extern, Func, Linker, Memory, Module, Store};

/// An Ardaku event.
#[repr(u32)]
#[derive(Debug)]
pub enum Event {
/// Read UTF-32 character from stdin
Read = 0u32,
}
use log::Level;

/// The system should implement these syscalls
pub trait System {
/// Sleep until an event happens.
fn sleep(&self) -> (Event, u32);

/// Write a line of text to stdout
fn write(&self, line: &[u8]);

/// Return kernel version
fn version(&self) -> u32;

/// Reboot the system
fn reboot(&self);
/// Sleep until some event(s) happen.
///
/// # Returns
/// - Length of ready list
///
/// # Safety
/// - Undefined behavior if return value != written length of ready list
unsafe fn sleep(&self, memory: &mut [u8], index: usize, length: usize) -> usize;

/// Write a message to the logs.
fn log(&self, text: &str, level: Level, target: &str);

/// Read a line of valid UTF-8 to the buffer, not including the newline
/// character.
///
/// # Returns
/// - `Ok(num_of_bytes_read)`
/// - `Err(num_of_bytes_required)`
///
/// # Safety
/// - Undefined behavior if implementation writes invalid UTF-8.
/// - Undefined behavior if bytes written != `Ok(num_of_bytes_read)`
unsafe fn read_line(&self, ready: u32, index: usize, length: usize);
}

/// I/O Result
pub type IoResult = core::result::Result<usize, usize>;

/// Ardaku Result
pub type Result<T> = core::result::Result<T, Error>;
pub type Result<T = ()> = core::result::Result<T, Error>;

/// An error in Ardaku
#[derive(Debug)]
Expand All @@ -50,6 +59,8 @@ pub enum Error {
struct State<S: System> {
memory: MaybeUninit<Memory>,
system: S,
ready_list: (u32, u32),
portals: [bool; Portal::Max as u32 as usize],
}

/// Command
Expand All @@ -70,19 +81,56 @@ struct Connect {
portals_data: u32,
}

/// Portal IDs
#[repr(u32)]
#[derive(Debug, Copy, Clone)]
enum Portal {
/// Task spawning API
Spawn = 0,
/// Blocking task spawning API
SpawnBlocking = 1,
/// Logging API (stdout/printf)
Log = 2,
/// Developer command API (stdin/scanf)
Prompt = 3,
/// MPMC Channel API
Channel = 4,
///
Max = 5,
}

fn le_u32(slice: &[u8]) -> u32 {
u32::from_le_bytes([slice[0], slice[1], slice[2], slice[3]])
}

impl<S: System> State<S> {
/// Connect channels
fn connect(caller: &mut Caller<'_, Self>, mem: Memory, connect: Connect) {
let _bytes = mem.data_mut(caller);
todo!("{connect:?}");
let state = caller.host_data_mut();

state.ready_list = (connect.ready_capacity, connect.ready_data);

let mut offset: usize = connect.portals_data.try_into().unwrap();
for _ in 0..connect.portals_size {
let bytes = mem.data_mut(&mut *caller);
let portal = le_u32(&bytes[offset..]);
let portal = match portal {
0 => Portal::Spawn,
1 => Portal::SpawnBlocking,
2 => Portal::Log,
3 => Portal::Prompt,
4 => Portal::Channel,
5..=u32::MAX => todo!("Host trap: invalid portal"),
};
offset += 4;
let state = caller.host_data_mut();
state.portals[portal as u32 as usize] = true;
log::trace!(target: "ardaku", "Connect portal: {portal:?}");
}
}

/// Execute a command from an asynchronous request
fn execute(caller: &mut Caller<'_, Self>, mem: Memory, command: Command) {
fn execute(caller: &mut Caller<'_, Self>, mem: Memory, command: Command) -> bool {
if command.channel == 0 {
let bytes = mem.data_mut(&mut *caller);
// FIXME: Trigger a trap if doesn't match
Expand All @@ -96,6 +144,7 @@ impl<S: System> State<S> {
};

Self::connect(caller, mem, connect);
true
} else {
todo!();
}
Expand All @@ -107,11 +156,14 @@ fn ar<S>(mut caller: Caller<'_, State<S>>, size: u32, data: u32) -> u32
where
S: System + 'static,
{
log::trace!(target: "ardaku", "Syscall ({size} commands)");

let state = caller.host_data_mut();
let memory = unsafe { state.memory.assume_init_mut() }.clone();
let data: usize = data.try_into().unwrap();

let mut offset = data;
let mut ready_immediately = 0;
for _ in 0..size {
let bytes = memory.data_mut(&mut caller);
let command = Command {
Expand All @@ -122,10 +174,19 @@ where
};
offset += 16;

State::<S>::execute(&mut caller, memory, command);
ready_immediately += u32::from(u8::from(State::<S>::execute(&mut caller, memory, command)));
}

todo!("Wait for a command to complete")
let state = caller.host_data_mut();
// let bytes = memory.data_mut(&mut caller);

if ready_immediately == 0 {
unsafe {
state.system.sleep(&mut [], state.ready_list.0.try_into().unwrap(), state.ready_list.1.try_into().unwrap()).try_into().unwrap()
}
} else {
ready_immediately
}
}

/// Run an Ardaku application. `exe` must be a .wasm file.
Expand All @@ -140,6 +201,8 @@ where
State {
system,
memory: MaybeUninit::uninit(),
ready_list: (0, 0),
portals: [false; Portal::Max as u32 as usize],
},
);
let async_request = Func::wrap(&mut store, ar);
Expand Down

0 comments on commit 698d938

Please sign in to comment.