diff --git a/src/common/errors.rs b/src/common/errors.rs index 9801428c..d0b748ab 100644 --- a/src/common/errors.rs +++ b/src/common/errors.rs @@ -1,7 +1,7 @@ //! Error context system based on a thread-local representation of the call stack, itself based on //! the instructions that are sent between threads. -use super::{AppInstruction, OPENCALLS}; +use super::{AppInstruction, ASYNCOPENCALLS, OPENCALLS}; use crate::pty_bus::PtyInstruction; use crate::screen::ScreenInstruction; @@ -72,6 +72,12 @@ pub fn handle_panic( } } +pub fn get_current_ctx() -> ErrorContext { + ASYNCOPENCALLS + .try_with(|ctx| *ctx.borrow()) + .unwrap_or_else(|_| OPENCALLS.with(|ctx| *ctx.borrow())) +} + /// A representation of the call stack. #[derive(Clone, Copy)] pub struct ErrorContext { @@ -95,7 +101,9 @@ impl ErrorContext { break; } } - OPENCALLS.with(|ctx| *ctx.borrow_mut() = *self); + ASYNCOPENCALLS + .try_with(|ctx| *ctx.borrow_mut() = *self) + .unwrap_or_else(|_| OPENCALLS.with(|ctx| *ctx.borrow_mut() = *self)); } } diff --git a/src/common/input/handler.rs b/src/common/input/handler.rs index 44065c67..0afcab10 100644 --- a/src/common/input/handler.rs +++ b/src/common/input/handler.rs @@ -58,9 +58,6 @@ impl InputHandler { fn handle_input(&mut self) { let mut err_ctx = OPENCALLS.with(|ctx| *ctx.borrow()); err_ctx.add_call(ContextType::StdinHandler); - self.send_pty_instructions.update(err_ctx); - self.send_app_instructions.update(err_ctx); - self.send_screen_instructions.update(err_ctx); let keybinds = self.config.keybinds.clone(); let alt_left_bracket = vec![27, 91]; loop { diff --git a/src/common/mod.rs b/src/common/mod.rs index 2466aecf..19f8e4bc 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -25,9 +25,13 @@ use crate::cli::CliArgs; use crate::common::input::config::Config; use crate::layout::Layout; use crate::panes::PaneId; +use async_std::task_local; use command_is_executing::CommandIsExecuting; use directories_next::ProjectDirs; -use errors::{AppContext, ContextType, ErrorContext, PluginContext, PtyContext, ScreenContext}; +use errors::{ + get_current_ctx, AppContext, ContextType, ErrorContext, PluginContext, PtyContext, + ScreenContext, +}; use input::handler::input_loop; use os_input_output::OsApi; use pty_bus::{PtyBus, PtyInstruction}; @@ -72,32 +76,23 @@ enum SenderType { /// synchronously or asynchronously depending on the underlying [`SenderType`]. #[derive(Clone)] pub struct SenderWithContext { - err_ctx: ErrorContext, sender: SenderType, } impl SenderWithContext { - fn new(err_ctx: ErrorContext, sender: SenderType) -> Self { - Self { err_ctx, sender } + fn new(sender: SenderType) -> Self { + Self { sender } } /// Sends an event, along with the current [`ErrorContext`], on this /// [`SenderWithContext`]'s channel. pub fn send(&self, event: T) -> Result<(), mpsc::SendError<(T, ErrorContext)>> { + let err_ctx = get_current_ctx(); match self.sender { - SenderType::Sender(ref s) => s.send((event, self.err_ctx)), - SenderType::SyncSender(ref s) => s.send((event, self.err_ctx)), + SenderType::Sender(ref s) => s.send((event, err_ctx)), + SenderType::SyncSender(ref s) => s.send((event, err_ctx)), } } - - /// Updates this [`SenderWithContext`]'s [`ErrorContext`]. This is the way one adds - /// a call to the error context. - /// - /// Updating [`ErrorContext`]s works in this way so that these contexts are only ever - /// allocated on the stack (which is thread-specific), and not on the heap. - pub fn update(&mut self, new_ctx: ErrorContext) { - self.err_ctx = new_ctx; - } } unsafe impl Send for SenderWithContext {} @@ -109,6 +104,12 @@ thread_local!( static OPENCALLS: RefCell = RefCell::default() ); +task_local! { + /// A key to some thread local storage (TLS) that holds a representation of the task's call + /// stack in the form of an [`ErrorContext`]. + static ASYNCOPENCALLS: RefCell = RefCell::default() +} + /// Instructions related to the entire application. #[derive(Clone)] pub enum AppInstruction { @@ -140,25 +141,23 @@ pub fn start(mut os_input: Box, opts: CliArgs) { let (send_screen_instructions, receive_screen_instructions): ChannelWithContext< ScreenInstruction, > = mpsc::channel(); - let err_ctx = OPENCALLS.with(|ctx| *ctx.borrow()); - let mut send_screen_instructions = - SenderWithContext::new(err_ctx, SenderType::Sender(send_screen_instructions)); + let send_screen_instructions = + SenderWithContext::new(SenderType::Sender(send_screen_instructions)); let (send_pty_instructions, receive_pty_instructions): ChannelWithContext = mpsc::channel(); - let mut send_pty_instructions = - SenderWithContext::new(err_ctx, SenderType::Sender(send_pty_instructions)); + let send_pty_instructions = SenderWithContext::new(SenderType::Sender(send_pty_instructions)); let (send_plugin_instructions, receive_plugin_instructions): ChannelWithContext< PluginInstruction, > = mpsc::channel(); let send_plugin_instructions = - SenderWithContext::new(err_ctx, SenderType::Sender(send_plugin_instructions)); + SenderWithContext::new(SenderType::Sender(send_plugin_instructions)); let (send_app_instructions, receive_app_instructions): SyncChannelWithContext = mpsc::sync_channel(0); let send_app_instructions = - SenderWithContext::new(err_ctx, SenderType::SyncSender(send_app_instructions)); + SenderWithContext::new(SenderType::SyncSender(send_app_instructions)); let mut pty_bus = PtyBus::new( receive_pty_instructions, @@ -195,7 +194,6 @@ pub fn start(mut os_input: Box, opts: CliArgs) { .recv() .expect("failed to receive event on channel"); err_ctx.add_call(ContextType::Pty(PtyContext::from(&event))); - pty_bus.send_screen_instructions.update(err_ctx); match event { PtyInstruction::SpawnTerminal(file_to_open) => { let pid = pty_bus.spawn_terminal(file_to_open); @@ -272,8 +270,6 @@ pub fn start(mut os_input: Box, opts: CliArgs) { .recv() .expect("failed to receive event on channel"); err_ctx.add_call(ContextType::Screen(ScreenContext::from(&event))); - screen.send_app_instructions.update(err_ctx); - screen.send_pty_instructions.update(err_ctx); match event { ScreenInstruction::PtyBytes(pid, vte_bytes) => { let active_tab = screen.get_active_tab_mut().unwrap(); @@ -433,9 +429,9 @@ pub fn start(mut os_input: Box, opts: CliArgs) { let wasm_thread = thread::Builder::new() .name("wasm".to_string()) .spawn({ - let mut send_pty_instructions = send_pty_instructions.clone(); - let mut send_screen_instructions = send_screen_instructions.clone(); - let mut send_app_instructions = send_app_instructions.clone(); + let send_pty_instructions = send_pty_instructions.clone(); + let send_screen_instructions = send_screen_instructions.clone(); + let send_app_instructions = send_app_instructions.clone(); let store = Store::default(); let mut plugin_id = 0; @@ -445,9 +441,6 @@ pub fn start(mut os_input: Box, opts: CliArgs) { .recv() .expect("failed to receive event on channel"); err_ctx.add_call(ContextType::Plugin(PluginContext::from(&event))); - send_screen_instructions.update(err_ctx); - send_pty_instructions.update(err_ctx); - send_app_instructions.update(err_ctx); match event { PluginInstruction::Load(pid_tx, path) => { let project_dirs = @@ -556,16 +549,14 @@ pub fn start(mut os_input: Box, opts: CliArgs) { .name("ipc_server".to_string()) .spawn({ use std::io::Read; - let mut send_pty_instructions = send_pty_instructions.clone(); - let mut send_screen_instructions = send_screen_instructions.clone(); + let send_pty_instructions = send_pty_instructions.clone(); + let send_screen_instructions = send_screen_instructions.clone(); move || { std::fs::remove_file(ZELLIJ_IPC_PIPE).ok(); let listener = std::os::unix::net::UnixListener::bind(ZELLIJ_IPC_PIPE) .expect("could not listen on ipc socket"); let mut err_ctx = OPENCALLS.with(|ctx| *ctx.borrow()); err_ctx.add_call(ContextType::IpcServer); - send_pty_instructions.update(err_ctx); - send_screen_instructions.update(err_ctx); for stream in listener.incoming() { match stream { @@ -637,8 +628,6 @@ pub fn start(mut os_input: Box, opts: CliArgs) { .expect("failed to receive app instruction on channel"); err_ctx.add_call(ContextType::App(AppContext::from(&app_instruction))); - send_screen_instructions.update(err_ctx); - send_pty_instructions.update(err_ctx); match app_instruction { AppInstruction::Exit => { break; diff --git a/src/common/pty_bus.rs b/src/common/pty_bus.rs index 2cab8ae8..28ae62f2 100644 --- a/src/common/pty_bus.rs +++ b/src/common/pty_bus.rs @@ -8,11 +8,11 @@ use ::std::sync::mpsc::Receiver; use ::std::time::{Duration, Instant}; use std::path::PathBuf; -use super::{ScreenInstruction, SenderWithContext, OPENCALLS}; +use super::{ScreenInstruction, SenderWithContext}; use crate::os_input_output::OsApi; use crate::utils::logging::debug_to_file; use crate::{ - errors::{ContextType, ErrorContext}, + errors::{get_current_ctx, ContextType, ErrorContext}, panes::PaneId, }; use crate::{layout::Layout, wasm_vm::PluginInstruction}; @@ -89,15 +89,14 @@ pub struct PtyBus { fn stream_terminal_bytes( pid: RawFd, - mut send_screen_instructions: SenderWithContext, + send_screen_instructions: SenderWithContext, os_input: Box, debug: bool, ) -> JoinHandle<()> { - let mut err_ctx = OPENCALLS.with(|ctx| *ctx.borrow()); + let mut err_ctx = get_current_ctx(); task::spawn({ async move { err_ctx.add_call(ContextType::AsyncTask); - send_screen_instructions.update(err_ctx); let mut terminal_bytes = ReadFromPid::new(&pid, os_input); let mut last_byte_receive_time: Option = None;