-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement single threaded task scheduler for WebAssembly (#496)
* Add hello_wasm example * Implement single threaded task scheduler for WebAssembly
- Loading branch information
Showing
12 changed files
with
285 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
use std::{ | ||
future::Future, | ||
mem, | ||
pin::Pin, | ||
sync::{Arc, Mutex}, | ||
}; | ||
|
||
/// Used to create a TaskPool | ||
#[derive(Debug, Default, Clone)] | ||
pub struct TaskPoolBuilder {} | ||
|
||
impl TaskPoolBuilder { | ||
/// Creates a new TaskPoolBuilder instance | ||
pub fn new() -> Self { | ||
Self::default() | ||
} | ||
|
||
pub fn num_threads(self, _num_threads: usize) -> Self { | ||
self | ||
} | ||
|
||
pub fn stack_size(self, _stack_size: usize) -> Self { | ||
self | ||
} | ||
|
||
pub fn thread_name(self, _thread_name: String) -> Self { | ||
self | ||
} | ||
|
||
pub fn build(self) -> TaskPool { | ||
TaskPool::new_internal() | ||
} | ||
} | ||
|
||
/// A thread pool for executing tasks. Tasks are futures that are being automatically driven by | ||
/// the pool on threads owned by the pool. In this case - main thread only. | ||
#[derive(Debug, Default, Clone)] | ||
pub struct TaskPool {} | ||
|
||
impl TaskPool { | ||
/// Create a `TaskPool` with the default configuration. | ||
pub fn new() -> Self { | ||
TaskPoolBuilder::new().build() | ||
} | ||
|
||
#[allow(unused_variables)] | ||
fn new_internal() -> Self { | ||
Self {} | ||
} | ||
|
||
/// Return the number of threads owned by the task pool | ||
pub fn thread_num(&self) -> usize { | ||
1 | ||
} | ||
|
||
/// Allows spawning non-`static futures on the thread pool. The function takes a callback, | ||
/// passing a scope object into it. The scope object provided to the callback can be used | ||
/// to spawn tasks. This function will await the completion of all tasks before returning. | ||
/// | ||
/// This is similar to `rayon::scope` and `crossbeam::scope` | ||
pub fn scope<'scope, F, T>(&self, f: F) -> Vec<T> | ||
where | ||
F: FnOnce(&mut Scope<'scope, T>) + 'scope + Send, | ||
T: Send + 'static, | ||
{ | ||
let executor = async_executor::LocalExecutor::new(); | ||
|
||
let executor: &async_executor::LocalExecutor = &executor; | ||
let executor: &'scope async_executor::LocalExecutor = unsafe { mem::transmute(executor) }; | ||
|
||
let mut scope = Scope { | ||
executor, | ||
results: Vec::new(), | ||
}; | ||
|
||
f(&mut scope); | ||
|
||
// Loop until all tasks are done | ||
while executor.try_tick() {} | ||
|
||
scope | ||
.results | ||
.iter() | ||
.map(|result| result.lock().unwrap().take().unwrap()) | ||
.collect() | ||
} | ||
} | ||
|
||
pub struct Scope<'scope, T> { | ||
executor: &'scope async_executor::LocalExecutor, | ||
// Vector to gather results of all futures spawned during scope run | ||
results: Vec<Arc<Mutex<Option<T>>>>, | ||
} | ||
|
||
impl<'scope, T: Send + 'static> Scope<'scope, T> { | ||
pub fn spawn<Fut: Future<Output = T> + 'scope + Send>(&mut self, f: Fut) { | ||
let result = Arc::new(Mutex::new(None)); | ||
self.results.push(result.clone()); | ||
let f = async move { | ||
result.lock().unwrap().replace(f.await); | ||
}; | ||
|
||
// SAFETY: This function blocks until all futures complete, so we do not read/write the | ||
// data from futures outside of the 'scope lifetime. However, rust has no way of knowing | ||
// this so we must convert to 'static here to appease the compiler as it is unable to | ||
// validate safety. | ||
let fut: Pin<Box<dyn Future<Output = ()> + 'scope>> = Box::pin(f); | ||
let fut: Pin<Box<dyn Future<Output = ()> + 'static>> = unsafe { mem::transmute(fut) }; | ||
|
||
self.executor.spawn(fut).detach(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
target/ |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
extern crate console_error_panic_hook; | ||
use bevy::{app::ScheduleRunnerPlugin, prelude::*}; | ||
use std::{panic, time::Duration}; | ||
|
||
fn main() { | ||
panic::set_hook(Box::new(console_error_panic_hook::hook)); | ||
console_log::init_with_level(log::Level::Debug).expect("cannot initialize console_log"); | ||
|
||
App::build() | ||
.add_plugin(ScheduleRunnerPlugin::run_loop(Duration::from_secs_f64( | ||
1.0 / 60.0, | ||
))) | ||
.add_startup_system(hello_world_system.system()) | ||
.add_system(counter.system()) | ||
.run(); | ||
} | ||
|
||
fn hello_world_system() { | ||
log::info!("hello wasm"); | ||
} | ||
|
||
fn counter(mut state: Local<CounterState>) { | ||
if state.count % 60 == 0 { | ||
log::info!("counter system: {}", state.count); | ||
} | ||
state.count += 1; | ||
} | ||
|
||
#[derive(Default)] | ||
struct CounterState { | ||
count: u32, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
extern crate console_error_panic_hook; | ||
use bevy::prelude::*; | ||
use std::panic; | ||
|
||
fn main() { | ||
panic::set_hook(Box::new(console_error_panic_hook::hook)); | ||
console_log::init_with_level(log::Level::Debug).expect("cannot initialize console_log"); | ||
|
||
App::build().add_system(hello_wasm_system.system()).run(); | ||
} | ||
|
||
fn hello_wasm_system() { | ||
log::info!("hello wasm"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<html> | ||
<head> | ||
<meta charset="UTF-8" /> | ||
</head> | ||
<script type="module"> | ||
import init from './target/headless_wasm.js' | ||
init() | ||
</script> | ||
</html> |