diff --git a/ctru-rs/Cargo.toml b/ctru-rs/Cargo.toml index 4635fa6..4807f32 100644 --- a/ctru-rs/Cargo.toml +++ b/ctru-rs/Cargo.toml @@ -27,6 +27,7 @@ toml = "0.5" ferris-says = "0.2.1" futures = "0.3" time = "0.3.7" +tokio = { version = "1.16", features = ["rt", "time", "sync", "macros"] } [features] default = ["romfs"] diff --git a/ctru-rs/examples/futures-tokio-basic.rs b/ctru-rs/examples/futures-tokio-basic.rs new file mode 100644 index 0000000..60753a2 --- /dev/null +++ b/ctru-rs/examples/futures-tokio-basic.rs @@ -0,0 +1,72 @@ +use ctru::console::Console; +use ctru::services::hid::KeyPad; +use ctru::services::ps::Ps; +use ctru::services::{Apt, Hid}; +use ctru::Gfx; +use std::time::Duration; + +fn main() { + ctru::init(); + let gfx = Gfx::default(); + let hid = Hid::init().expect("Couldn't obtain HID controller"); + let apt = Apt::init().expect("Couldn't obtain APT controller"); + let _ps = Ps::init().expect("Couldn't initialize PS service"); + let _console = Console::init(gfx.top_screen.borrow_mut()); + + // Give ourselves up to 30% of the system core's time + apt.set_app_cpu_time_limit(30) + .expect("Failed to enable system core"); + + println!("Starting runtime..."); + + let (exit_sender, mut exit_receiver) = tokio::sync::oneshot::channel(); + let runtime = tokio::runtime::Builder::new_current_thread() + .enable_time() + .build() + .expect("Couldn't build runtime"); + + let runtime_thread = ctru::thread::Builder::new() + // Run on the system core + .affinity(1) + // Use a bigger stack size. Default is 0x1000 but we'd easily overflow that. + .stack_size(0x200000) + .spawn(move || { + runtime.block_on(async move { + let mut wake_time = tokio::time::Instant::now() + Duration::from_secs(1); + let mut iteration = 0; + loop { + let sleep_future = tokio::time::sleep_until(wake_time); + + tokio::select! { + // Use the first available future instead of randomizing + biased; + + _ = sleep_future => { + println!("Tick {}", iteration); + iteration += 1; + wake_time += Duration::from_secs(1); + } + _ = &mut exit_receiver => break, + } + } + }); + }) + .expect("Failed to create runtime thread"); + + println!("Runtime started!"); + + while apt.main_loop() { + hid.scan_input(); + + if hid.keys_down().contains(KeyPad::KEY_START) { + println!("Shutting down..."); + let _ = exit_sender.send(()); + let _ = runtime_thread.join(); + break; + } + + gfx.flush_buffers(); + gfx.swap_buffers(); + gfx.wait_for_vblank(); + } +} diff --git a/ctru-rs/examples/thread_locals.rs b/ctru-rs/examples/thread_locals.rs new file mode 100644 index 0000000..937855a --- /dev/null +++ b/ctru-rs/examples/thread_locals.rs @@ -0,0 +1,66 @@ +use ctru::console::Console; +use ctru::services::hid::KeyPad; +use ctru::services::{Apt, Hid}; +use ctru::Gfx; +use std::cell::RefCell; + +std::thread_local! { + static MY_LOCAL: RefCell<&'static str> = RefCell::new("initial value"); +} + +fn main() { + ctru::init(); + let gfx = Gfx::default(); + gfx.top_screen.borrow_mut().set_wide_mode(true); + let hid = Hid::init().expect("Couldn't obtain HID controller"); + let apt = Apt::init().expect("Couldn't obtain APT controller"); + let _console = Console::init(gfx.top_screen.borrow_mut()); + + // Give ourselves up to 30% of the system core's time + apt.set_app_cpu_time_limit(30) + .expect("Failed to enable system core"); + + MY_LOCAL.with(|local| { + println!("Initial value on main thread: {}", local.borrow()); + *local.borrow_mut() = "second value"; + }); + MY_LOCAL.with(|local| { + println!("Value on main thread after mutation: {}", local.borrow()); + }); + + ctru::thread::Builder::new() + .affinity(1) + .spawn(move || { + MY_LOCAL.with(|local| { + println!("Initial value on second thread: {}", local.borrow()); + *local.borrow_mut() = "third value"; + }); + MY_LOCAL.with(|local| { + println!("Value on second thread after mutation: {}", local.borrow()); + }); + }) + .expect("Failed to create thread") + .join() + .expect("Failed to join on thread"); + + MY_LOCAL.with(|local| { + println!( + "Value on main thread after second thread exits: {}", + local.borrow() + ); + }); + + println!("Press Start to exit"); + + while apt.main_loop() { + hid.scan_input(); + + if hid.keys_down().contains(KeyPad::KEY_START) { + break; + } + + gfx.flush_buffers(); + gfx.swap_buffers(); + gfx.wait_for_vblank(); + } +} diff --git a/ctru-rs/src/thread.rs b/ctru-rs/src/thread.rs index 225b1f8..14d7a56 100644 --- a/ctru-rs/src/thread.rs +++ b/ctru-rs/src/thread.rs @@ -1040,7 +1040,10 @@ mod thread_info { } pub fn set(thread: Thread) { - CTRU_THREAD_INFO.with(|c| assert!(c.borrow().is_none())); - CTRU_THREAD_INFO.with(move |c| *c.borrow_mut() = Some(ThreadInfo { thread })); + CTRU_THREAD_INFO.with(move |c| { + let mut thread_info = c.borrow_mut(); + assert!(thread_info.is_none()); + *thread_info = Some(ThreadInfo { thread }); + }); } }