Skip to content

Commit

Permalink
Playtime: Shutdown async runtime when last ReaLearn instance removed
Browse files Browse the repository at this point in the history
  • Loading branch information
helgoboss committed Nov 16, 2023
1 parent 904465b commit 4598677
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 23 deletions.
1 change: 0 additions & 1 deletion main/src/infrastructure/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,3 @@ mod plugin;
mod server;
mod test;
mod ui;
mod worker;
38 changes: 38 additions & 0 deletions main/src/infrastructure/plugin/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,14 @@ use slog::{debug, Drain, Logger};
use std::cell::{Ref, RefCell};
use std::collections::HashSet;
use std::fs;
use std::future::Future;
use std::path::{Path, PathBuf};
use std::rc::{Rc, Weak};
use std::thread::JoinHandle;
use std::time::Duration;
use swell_ui::{SharedView, View, ViewManager, Window};
use tempfile::TempDir;
use tokio::runtime::Runtime;
use url::Url;

/// Queue size for sending feedback tasks to audio hook.
Expand Down Expand Up @@ -165,6 +168,7 @@ struct AwakeState {
audio_hook_handle: RegistrationHandle<RealearnAudioHook>,
accelerator_handle: RegistrationHandle<RealearnSessionAccelerator>,
async_deallocation_thread: JoinHandle<AsyncDeallocatorCommandReceiver>,
async_runtime: Runtime,
}

impl App {
Expand Down Expand Up @@ -435,6 +439,13 @@ impl App {
RealearnDeallocator::with_metrics("async_deallocation"),
sleeping_state.async_deallocation_receiver,
);
// Start async runtime
let async_runtime = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.thread_name("ReaLearn async runtime")
.worker_threads(1)
.build()
.expect("couldn't start ReaLearn async runtime");
// Activate server
if self.config.borrow().server_is_enabled() {
self.server()
Expand Down Expand Up @@ -491,6 +502,7 @@ impl App {
audio_hook_handle,
accelerator_handle,
async_deallocation_thread,
async_runtime,
};
self.state.replace(AppState::Awake(awake_state));
}
Expand Down Expand Up @@ -531,6 +543,12 @@ impl App {
session.plugin_register_remove_hook_post_command::<ActionRxHookPostCommand<Global>>();
// Server
self.server().borrow_mut().stop();
// Shutdown async runtime
tracing::info!("Shutting down async runtime...");
awake_state
.async_runtime
.shutdown_timeout(Duration::from_secs(1));
tracing::info!("Async runtime shut down successfully");
// Stop async deallocation thread
GLOBAL_ALLOCATOR.stop_async_deallocation();
let async_deallocation_receiver = awake_state
Expand Down Expand Up @@ -709,10 +727,30 @@ impl App {
audio_hook_handle: awake_state.audio_hook_handle,
accelerator_handle: awake_state.accelerator_handle,
async_deallocation_thread: awake_state.async_deallocation_thread,
async_runtime: awake_state.async_runtime,
};
self.state.replace(AppState::Awake(awake_state));
}

/// Spawns the given future on the ReaLearn async runtime.
///
/// # Panics
///
/// Panics if called in any state other than awake.
pub fn spawn_in_async_runtime<R>(
&self,
f: impl Future<Output = R> + Send + 'static,
) -> tokio::task::JoinHandle<R>
where
R: Send + 'static,
{
let state = self.state.borrow();
let AppState::Awake(state) = &*state else {
panic!("attempted to spawn future while ReaLearn in wrong state: {state:?}");
};
state.async_runtime.spawn(f)
}

// TODO-medium Return a reference to a SharedControllerManager! Clients might just want to turn
// this into a weak one.
pub fn controller_preset_manager(&self) -> SharedControllerPresetManager {
Expand Down
3 changes: 1 addition & 2 deletions main/src/infrastructure/ui/app/app_instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use crate::application::WeakSession;
use crate::infrastructure::plugin::App;
use crate::infrastructure::ui::bindings::root;
use crate::infrastructure::ui::AppHandle;
use crate::infrastructure::worker::spawn_in_main_worker;
use anyhow::{anyhow, Context, Result};
use playtime_clip_engine::proto::{
event_reply, reply, ClipEngineReceivers, Empty, EventReply, Reply,
Expand Down Expand Up @@ -197,7 +196,7 @@ impl AppInstance for StandaloneAppInstance {
running_state.common_state.app_callback = Some(callback);
// Now we can start passing events to the app callback
let mut receivers = subscribe_to_events();
let join_handle = spawn_in_main_worker(async move {
let join_handle = App::get().spawn_in_async_runtime(async move {
receivers
.keep_processing_updates(&session_id, &|event_reply| {
let reply = Reply {
Expand Down
20 changes: 0 additions & 20 deletions main/src/infrastructure/worker/mod.rs

This file was deleted.

0 comments on commit 4598677

Please sign in to comment.