Avoid potential contention on SIGTERM while enabling terminal protocols

We no longer use RAII for enabling/disabling these, so a full object is
overkill.  Additionally this object doesn't allow us to recover from the case
where we receive SIGTERM while inside terminal_protocols_{enable,disable}.
We can simply run disable another time since they're idempotent. Untested.
This commit is contained in:
Johannes Altmanninger 2024-10-08 11:25:48 +02:00
parent a7abd83c57
commit 37c04745e6
2 changed files with 57 additions and 76 deletions

View file

@ -12,17 +12,16 @@ use crate::key::{
Key, Modifiers, Key, Modifiers,
}; };
use crate::reader::{reader_current_data, reader_test_and_clear_interrupted}; use crate::reader::{reader_current_data, reader_test_and_clear_interrupted};
use crate::threads::{iothread_port, MainThread}; use crate::threads::iothread_port;
use crate::universal_notifier::default_notifier; use crate::universal_notifier::default_notifier;
use crate::wchar::{encode_byte_to_char, prelude::*}; use crate::wchar::{encode_byte_to_char, prelude::*};
use crate::wutil::encoding::{mbrtowc, mbstate_t, zero_mbstate}; use crate::wutil::encoding::{mbrtowc, mbstate_t, zero_mbstate};
use crate::wutil::{fish_wcstol, write_to_fd}; use crate::wutil::{fish_wcstol, write_to_fd};
use std::cell::RefCell;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::ops::ControlFlow; use std::ops::ControlFlow;
use std::os::fd::RawFd; use std::os::fd::RawFd;
use std::ptr; use std::ptr;
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
// The range of key codes for inputrc-style keyboard functions. // The range of key codes for inputrc-style keyboard functions.
pub const R_END_INPUT_FUNCTIONS: usize = (ReadlineCmd::ReverseRepeatJump as usize) + 1; pub const R_END_INPUT_FUNCTIONS: usize = (ReadlineCmd::ReverseRepeatJump as usize) + 1;
@ -426,8 +425,7 @@ pub fn update_wait_on_sequence_key_ms(vars: &EnvStack) {
} }
} }
static TERMINAL_PROTOCOLS: MainThread<RefCell<Option<TerminalProtocols>>> = static TERMINAL_PROTOCOLS: AtomicBool = AtomicBool::new(false);
MainThread::new(RefCell::new(None));
pub(crate) static IS_TMUX: RelaxedAtomicBool = RelaxedAtomicBool::new(false); pub(crate) static IS_TMUX: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
pub(crate) static IN_MIDNIGHT_COMMANDER: RelaxedAtomicBool = RelaxedAtomicBool::new(false); pub(crate) static IN_MIDNIGHT_COMMANDER: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
@ -438,27 +436,10 @@ pub fn terminal_protocols_enable_ifn() {
if IN_MIDNIGHT_COMMANDER.load() { if IN_MIDNIGHT_COMMANDER.load() {
return; return;
} }
let mut term_protocols = TERMINAL_PROTOCOLS.get().borrow_mut(); if TERMINAL_PROTOCOLS.load(Ordering::Relaxed) {
if term_protocols.is_some() {
return; return;
} }
*term_protocols = Some(TerminalProtocols::new()); TERMINAL_PROTOCOLS.store(true, Ordering::Release);
}
pub(crate) fn terminal_protocols_disable_ifn() {
TERMINAL_PROTOCOLS.get().replace(None);
}
pub(crate) fn terminal_protocols_try_disable_ifn() {
if let Ok(mut term_protocols) = TERMINAL_PROTOCOLS.get().try_borrow_mut() {
*term_protocols = None;
}
}
struct TerminalProtocols {}
impl TerminalProtocols {
fn new() -> Self {
let sequences = if IN_WEZTERM.load() { let sequences = if IN_WEZTERM.load() {
"\x1b[?2004h" "\x1b[?2004h"
} else if IN_ITERM_PRE_CSI_U.load() { } else if IN_ITERM_PRE_CSI_U.load() {
@ -483,12 +464,12 @@ impl TerminalProtocols {
let _ = write_to_fd("\x1b[?1004h".as_bytes(), STDOUT_FILENO); let _ = write_to_fd("\x1b[?1004h".as_bytes(), STDOUT_FILENO);
} }
reader_current_data().map(|data| data.save_screen_state()); reader_current_data().map(|data| data.save_screen_state());
Self {}
}
} }
impl Drop for TerminalProtocols { pub(crate) fn terminal_protocols_disable_ifn() {
fn drop(&mut self) { if !TERMINAL_PROTOCOLS.load(Ordering::Acquire) {
return;
}
let sequences = if IN_WEZTERM.load() { let sequences = if IN_WEZTERM.load() {
"\x1b[?2004l" "\x1b[?2004l"
} else if IN_ITERM_PRE_CSI_U.load() { } else if IN_ITERM_PRE_CSI_U.load() {
@ -513,7 +494,7 @@ impl Drop for TerminalProtocols {
let _ = write_to_fd("\x1b[?1004l".as_bytes(), STDOUT_FILENO); let _ = write_to_fd("\x1b[?1004l".as_bytes(), STDOUT_FILENO);
} }
reader_current_data().map(|data| data.save_screen_state()); reader_current_data().map(|data| data.save_screen_state());
} TERMINAL_PROTOCOLS.store(false, Ordering::Release);
} }
fn parse_mask(mask: u32) -> Modifiers { fn parse_mask(mask: u32) -> Modifiers {

View file

@ -2,7 +2,7 @@ use std::num::NonZeroI32;
use crate::common::{exit_without_destructors, restore_term_foreground_process_group_for_exit}; use crate::common::{exit_without_destructors, restore_term_foreground_process_group_for_exit};
use crate::event::{enqueue_signal, is_signal_observed}; use crate::event::{enqueue_signal, is_signal_observed};
use crate::input_common::terminal_protocols_try_disable_ifn; use crate::input_common::terminal_protocols_disable_ifn;
use crate::nix::getpid; use crate::nix::getpid;
use crate::reader::{reader_handle_sigint, reader_sighup}; use crate::reader::{reader_handle_sigint, reader_sighup};
use crate::termsize::TermsizeContainer; use crate::termsize::TermsizeContainer;
@ -89,7 +89,7 @@ extern "C" fn fish_signal_handler(
// Handle sigterm. The only thing we do is restore the front process ID, then die. // Handle sigterm. The only thing we do is restore the front process ID, then die.
if !observed { if !observed {
restore_term_foreground_process_group_for_exit(); restore_term_foreground_process_group_for_exit();
terminal_protocols_try_disable_ifn(); terminal_protocols_disable_ifn();
// Safety: signal() and raise() are async-signal-safe. // Safety: signal() and raise() are async-signal-safe.
unsafe { unsafe {
libc::signal(libc::SIGTERM, libc::SIG_DFL); libc::signal(libc::SIGTERM, libc::SIG_DFL);