diff options
| author | Brooks Rady <b.j.rady@gmail.com> | 2020-11-26 10:36:27 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-11-26 10:36:27 +0000 |
| commit | 1586a705d2b36669ee4045b35377d8ddd591ccef (patch) | |
| tree | 5ceedf618ff09c25ff316fa9fae80fea2787fcd4 /src | |
| parent | hotfix(logging): atomically create tmp folders (diff) | |
| parent | fix(tests): improve atomic data access (diff) | |
| download | sl0ppij-1586a705d2b36669ee4045b35377d8ddd591ccef.tar.gz sl0ppij-1586a705d2b36669ee4045b35377d8ddd591ccef.tar.xz sl0ppij-1586a705d2b36669ee4045b35377d8ddd591ccef.zip | |
feat(tiles): initial WASM integration
The first steps towards WASM module integration
Diffstat (limited to 'src')
| -rw-r--r-- | src/main.rs | 108 | ||||
| -rw-r--r-- | src/tests/fakes.rs | 31 |
2 files changed, 132 insertions, 7 deletions
diff --git a/src/main.rs b/src/main.rs index 04e5d8de..105f3863 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,15 +11,19 @@ mod screen; mod terminal_pane; mod utils; -use std::io::{Read, Write}; +use std::io::{self, Read, Write}; use std::os::unix::net::UnixStream; use std::path::PathBuf; use std::sync::mpsc::{channel, Receiver, Sender}; +use std::sync::{Arc, Mutex}; use std::thread; use serde::{Deserialize, Serialize}; use structopt::StructOpt; +use wasmer::{Exports, Function, Instance, Module, Store, Value}; +use wasmer_wasi::WasiState; + use crate::command_is_executing::CommandIsExecuting; use crate::input::input_loop; use crate::layout::Layout; @@ -253,6 +257,108 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: Opt) { .unwrap(), ); + // Here be dragons! This is very much a work in progress, and isn't quite functional + // yet. It's being left out of the tests because is slows them down massively (by + // recompiling a WASM module for every single test). Stay tuned for more updates! + #[cfg(not(test))] + active_threads.push( + thread::Builder::new() + .name("wasm".to_string()) + .spawn(move || { + // TODO: Clone shared state here + move || -> Result<(), Box<dyn std::error::Error>> { + let store = Store::default(); + + println!("Compiling module..."); + // FIXME: Switch to a higher performance compiler (`Store::default()`) and cache this on disk + // I could use `(de)serialize_to_file()` for that + let module = if let Ok(m) = Module::from_file(&store, "strider.wasm") { + m + } else { + return Ok(()); // Just abort this thread quietly if the WASM isn't found + }; + + // FIXME: Upstream the `Pipe` struct + //let output = fluff::Pipe::new(); + //let input = fluff::Pipe::new(); + let mut wasi_env = WasiState::new("mosaic") + .env("CLICOLOR_FORCE", "1") + .preopen(|p| { + p.directory(".") // TODO: Change this to a more meaningful dir + .alias(".") + .read(true) + .write(true) + .create(true) + })? + //.stdin(Box::new(input)) + //.stdout(Box::new(output)) + .finalize()?; + + let mut import_object = wasi_env.import_object(&module)?; + // FIXME: Upstream an `ImportObject` merge method + let mut host_exports = Exports::new(); + /* host_exports.insert( + "host_open_file", + Function::new_native_with_env(&store, Arc::clone(&wasi_env.state), host_open_file), + ); */ + fn noop() {} + host_exports.insert("host_open_file", Function::new_native(&store, noop)); + import_object.register("mosaic", host_exports); + let instance = Instance::new(&module, &import_object)?; + + // WASI requires to explicitly set the memory for the `WasiEnv` + wasi_env.set_memory(instance.exports.get_memory("memory")?.clone()); + + let start = instance.exports.get_function("_start")?; + let handle_key = instance.exports.get_function("handle_key")?; + let draw = instance.exports.get_function("draw")?; + + // This eventually calls the `.init()` method + start.call(&[])?; + + loop { + break; + //let (cols, rows) = terminal::size()?; + //draw.call(&[Value::I32(rows as i32), Value::I32(cols as i32)])?; + + // FIXME: This downcasting mess needs to be abstracted away + /* let mut state = wasi_env.state(); + let wasi_file = state.fs.stdout_mut()?.as_mut().unwrap(); + let output: &mut fluff::Pipe = wasi_file.downcast_mut().unwrap(); + // Needed because raw mode doesn't implicitly return to the start of the line + write!( + io::stdout(), + "{}\n\r", + output.to_string().lines().collect::<Vec<_>>().join("\n\r") + )?; + output.clear(); + + let wasi_file = state.fs.stdin_mut()?.as_mut().unwrap(); + let input: &mut fluff::Pipe = wasi_file.downcast_mut().unwrap(); + input.clear(); */ + + /* match event::read()? { + Event::Key(KeyEvent { + code: KeyCode::Char('q'), + .. + }) => break, + Event::Key(e) => { + writeln!(input, "{}\r", serde_json::to_string(&e)?)?; + drop(state); + // Need to release the implicit `state` mutex or I deadlock! + handle_key.call(&[])?; + } + _ => (), + } */ + } + debug_log_to_file("WASM module loaded and exited cleanly :)".to_string())?; + Ok(()) + }() + .unwrap() + }) + .unwrap(), + ); + // TODO: currently we don't push this into active_threads // because otherwise the app will hang. Need to fix this so it both // listens to the ipc-bus and is able to quit cleanly diff --git a/src/tests/fakes.rs b/src/tests/fakes.rs index 22370d98..0afba192 100644 --- a/src/tests/fakes.rs +++ b/src/tests/fakes.rs @@ -3,6 +3,7 @@ use ::std::collections::HashMap; use ::std::io::{Read, Write}; use ::std::os::unix::io::RawFd; use ::std::path::PathBuf; +use ::std::sync::atomic::{AtomicBool, Ordering}; use ::std::sync::{Arc, Mutex}; use ::std::time::{Duration, Instant}; @@ -24,14 +25,20 @@ pub struct FakeStdinReader { pub input_chars: Vec<[u8; 10]>, pub read_position: usize, last_snapshot_time: Arc<Mutex<Instant>>, + started_reading_from_pty: Arc<AtomicBool>, } impl FakeStdinReader { - pub fn new(input_chars: Vec<[u8; 10]>, last_snapshot_time: Arc<Mutex<Instant>>) -> Self { + pub fn new( + input_chars: Vec<[u8; 10]>, + last_snapshot_time: Arc<Mutex<Instant>>, + started_reading_from_pty: Arc<AtomicBool>, + ) -> Self { FakeStdinReader { input_chars, read_position: 0, last_snapshot_time, + started_reading_from_pty, } } } @@ -39,11 +46,15 @@ impl FakeStdinReader { impl Read for FakeStdinReader { fn read(&mut self, buf: &mut [u8]) -> Result<usize, std::io::Error> { loop { - let last_snapshot_time = { *self.last_snapshot_time.lock().unwrap() }; - if last_snapshot_time.elapsed() > MIN_TIME_BETWEEN_SNAPSHOTS { - break; + if self.started_reading_from_pty.load(Ordering::Acquire) == false { + ::std::thread::sleep(MIN_TIME_BETWEEN_SNAPSHOTS); } else { - ::std::thread::sleep(MIN_TIME_BETWEEN_SNAPSHOTS - last_snapshot_time.elapsed()); + let last_snapshot_time = { *self.last_snapshot_time.lock().unwrap() }; + if last_snapshot_time.elapsed() > MIN_TIME_BETWEEN_SNAPSHOTS { + break; + } else { + ::std::thread::sleep(MIN_TIME_BETWEEN_SNAPSHOTS - last_snapshot_time.elapsed()); + } } } let read_position = self.read_position; @@ -120,6 +131,7 @@ pub struct FakeInputOutput { win_sizes: Arc<Mutex<HashMap<RawFd, PositionAndSize>>>, possible_tty_inputs: HashMap<u16, Bytes>, last_snapshot_time: Arc<Mutex<Instant>>, + started_reading_from_pty: Arc<AtomicBool>, } impl FakeInputOutput { @@ -137,6 +149,7 @@ impl FakeInputOutput { io_events: Arc::new(Mutex::new(vec![])), win_sizes: Arc::new(Mutex::new(win_sizes)), possible_tty_inputs: get_possible_tty_inputs(), + started_reading_from_pty: Arc::new(AtomicBool::new(false)), } } pub fn with_tty_inputs(mut self, tty_inputs: HashMap<u16, Bytes>) -> Self { @@ -200,6 +213,7 @@ impl OsApi for FakeInputOutput { // them fail ::std::thread::sleep(::std::time::Duration::from_millis(25)); } else if attempts_left == 0 { + self.started_reading_from_pty.store(true, Ordering::Release); return Ok(0); } let mut read_buffers = self.read_buffers.lock().unwrap(); @@ -213,6 +227,7 @@ impl OsApi for FakeInputOutput { if bytes_read > bytes.read_position { bytes.set_read_position(bytes_read); } + self.started_reading_from_pty.store(true, Ordering::Release); return Ok(bytes_read); } None => { @@ -245,7 +260,11 @@ impl OsApi for FakeInputOutput { input_chars.push(*bytes); } } - let reader = FakeStdinReader::new(input_chars, self.last_snapshot_time.clone()); + let reader = FakeStdinReader::new( + input_chars, + self.last_snapshot_time.clone(), + self.started_reading_from_pty.clone(), + ); Box::new(reader) } fn get_stdout_writer(&self) -> Box<dyn Write> { |
