Co-Authored-By: Eric Holk <eric@zed.dev> In app drop we had been calling `.close()` on the executors. This caused problems with the BackgroundExecutor on Linux because it raced with concurrent work: If task A was running and about to poll task B, the poll to task B would panic with "Task polled after completion". This didn't really matter (because the app was shutting down anyway) but inflated our panic metrics on Linux. It turns out that the call to `.close()` is not needed. It was added to prevent foreground tasks being scheduled after the app was dropped; but on all platforms the App run method does not return until after the ForegroundExecutor is stopped (so no further tasks will run anyway). The background case is more interesting. In test code it didn't matter (the background executor is simulated on the main thread so tests can't leak tasks); in app code it also didn't really make a difference. When `fn main` returns (which it does immediately after the app is dropped) all the background threads will be cancelled anyway. Further confounding debugging, it turns out that the App does not get dropped on macOS and Windows due to a reference cycle; so this was only happening on Linux where the app quit callback is dropped instead of retained after being called. (Fix in #50985) Release Notes: - N/A --------- Co-authored-by: Eric Holk <eric@zed.dev>
78 lines
2.6 KiB
Rust
78 lines
2.6 KiB
Rust
pub mod components;
|
|
mod jupyter_settings;
|
|
pub mod kernels;
|
|
pub mod notebook;
|
|
mod outputs;
|
|
mod repl_editor;
|
|
mod repl_sessions_ui;
|
|
mod repl_settings;
|
|
mod repl_store;
|
|
mod session;
|
|
|
|
use std::{sync::Arc, time::Duration};
|
|
|
|
use async_dispatcher::{Dispatcher, Runnable, set_dispatcher};
|
|
use gpui::{App, PlatformDispatcher, Priority, RunnableMeta};
|
|
use project::Fs;
|
|
pub use runtimelib::ExecutionState;
|
|
|
|
pub use crate::jupyter_settings::JupyterSettings;
|
|
pub use crate::kernels::{Kernel, KernelSpecification, KernelStatus, PythonEnvKernelSpecification};
|
|
pub use crate::repl_editor::*;
|
|
pub use crate::repl_sessions_ui::{
|
|
ClearCurrentOutput, ClearOutputs, Interrupt, ReplSessionsPage, Restart, Run, Sessions, Shutdown,
|
|
};
|
|
pub use crate::repl_settings::ReplSettings;
|
|
pub use crate::repl_store::ReplStore;
|
|
pub use crate::session::Session;
|
|
|
|
pub const KERNEL_DOCS_URL: &str = "https://zed.dev/docs/repl#changing-kernels";
|
|
|
|
pub fn init(fs: Arc<dyn Fs>, cx: &mut App) {
|
|
set_dispatcher(zed_dispatcher(cx));
|
|
repl_sessions_ui::init(cx);
|
|
ReplStore::init(fs, cx);
|
|
}
|
|
|
|
fn zed_dispatcher(cx: &mut App) -> impl Dispatcher {
|
|
struct ZedDispatcher {
|
|
dispatcher: Arc<dyn PlatformDispatcher>,
|
|
}
|
|
|
|
// PlatformDispatcher is _super_ close to the same interface we put in
|
|
// async-dispatcher, except for the task label in dispatch. Later we should
|
|
// just make that consistent so we have this dispatcher ready to go for
|
|
// other crates in Zed.
|
|
impl Dispatcher for ZedDispatcher {
|
|
#[track_caller]
|
|
fn dispatch(&self, runnable: Runnable) {
|
|
let location = core::panic::Location::caller();
|
|
let (wrapper, task) = async_task::Builder::new()
|
|
.metadata(RunnableMeta { location })
|
|
.spawn(|_| async move { runnable.run() }, {
|
|
let dispatcher = self.dispatcher.clone();
|
|
move |r| dispatcher.dispatch(r, Priority::default())
|
|
});
|
|
wrapper.schedule();
|
|
task.detach();
|
|
}
|
|
|
|
#[track_caller]
|
|
fn dispatch_after(&self, duration: Duration, runnable: Runnable) {
|
|
let location = core::panic::Location::caller();
|
|
let (wrapper, task) = async_task::Builder::new()
|
|
.metadata(RunnableMeta { location })
|
|
.spawn(|_| async move { runnable.run() }, {
|
|
let dispatcher = self.dispatcher.clone();
|
|
move |r| dispatcher.dispatch_after(duration, r)
|
|
});
|
|
wrapper.schedule();
|
|
task.detach();
|
|
}
|
|
}
|
|
|
|
ZedDispatcher {
|
|
dispatcher: cx.background_executor().dispatcher().clone(),
|
|
}
|
|
}
|