mirror of
https://github.com/wez/wezterm.git
synced 2024-12-23 21:32:13 +03:00
mux: switch RefCell to RwLock internally
This is a step towards making it Send+Sync. I'm a little cagey about this in the long term, as there are some mux operations that may technically require multiple fields to be locked for their duration: allowing free-threaded access may introduce some subtle (or not so subtle!) interleaving conditions where the overall mux state is not yet consistent. I'm thinking of prune_dead_windows kicking in while the mux is in the middle of being manipulated. I did try an initial pass of just moving everything under one lock, but there is already quite a lot of mixed read/write access to different aspects of the mux. We'll see what bubbles up later!
This commit is contained in:
parent
696148941c
commit
920ee853b3
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -2950,6 +2950,7 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
"luahelper",
|
"luahelper",
|
||||||
"mux",
|
"mux",
|
||||||
|
"parking_lot 0.12.1",
|
||||||
"portable-pty",
|
"portable-pty",
|
||||||
"smol",
|
"smol",
|
||||||
"termwiz",
|
"termwiz",
|
||||||
|
@ -13,6 +13,7 @@ wezterm-term = { path = "../../term" }
|
|||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
luahelper = { path = "../../luahelper" }
|
luahelper = { path = "../../luahelper" }
|
||||||
|
parking_lot = "0.12"
|
||||||
portable-pty = { path = "../../pty" }
|
portable-pty = { path = "../../pty" }
|
||||||
smol = "1.2"
|
smol = "1.2"
|
||||||
termwiz = { path = "../../termwiz" }
|
termwiz = { path = "../../termwiz" }
|
||||||
|
@ -8,7 +8,6 @@ use mux::tab::{SplitDirection, SplitRequest, SplitSize, Tab, TabId};
|
|||||||
use mux::window::{Window, WindowId};
|
use mux::window::{Window, WindowId};
|
||||||
use mux::Mux;
|
use mux::Mux;
|
||||||
use portable_pty::CommandBuilder;
|
use portable_pty::CommandBuilder;
|
||||||
use std::cell::{Ref, RefMut};
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use wezterm_dynamic::{FromDynamic, ToDynamic};
|
use wezterm_dynamic::{FromDynamic, ToDynamic};
|
||||||
@ -67,7 +66,7 @@ pub fn register(lua: &Lua) -> anyhow::Result<()> {
|
|||||||
lua.create_function(|_, window_id: WindowId| {
|
lua.create_function(|_, window_id: WindowId| {
|
||||||
let mux = get_mux()?;
|
let mux = get_mux()?;
|
||||||
let window = MuxWindow(window_id);
|
let window = MuxWindow(window_id);
|
||||||
window.resolve(&mux)?;
|
let _resolved = window.resolve(&mux)?;
|
||||||
Ok(window)
|
Ok(window)
|
||||||
})?,
|
})?,
|
||||||
)?;
|
)?;
|
||||||
|
@ -1,15 +1,19 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
use parking_lot::{MappedRwLockReadGuard, MappedRwLockWriteGuard};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct MuxWindow(pub WindowId);
|
pub struct MuxWindow(pub WindowId);
|
||||||
|
|
||||||
impl MuxWindow {
|
impl MuxWindow {
|
||||||
pub fn resolve<'a>(&self, mux: &'a Rc<Mux>) -> mlua::Result<Ref<'a, Window>> {
|
pub fn resolve<'a>(&self, mux: &'a Rc<Mux>) -> mlua::Result<MappedRwLockReadGuard<'a, Window>> {
|
||||||
mux.get_window(self.0)
|
mux.get_window(self.0)
|
||||||
.ok_or_else(|| mlua::Error::external(format!("window id {} not found in mux", self.0)))
|
.ok_or_else(|| mlua::Error::external(format!("window id {} not found in mux", self.0)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_mut<'a>(&self, mux: &'a Rc<Mux>) -> mlua::Result<RefMut<'a, Window>> {
|
pub fn resolve_mut<'a>(
|
||||||
|
&self,
|
||||||
|
mux: &'a Rc<Mux>,
|
||||||
|
) -> mlua::Result<MappedRwLockWriteGuard<'a, Window>> {
|
||||||
mux.get_window_mut(self.0)
|
mux.get_window_mut(self.0)
|
||||||
.ok_or_else(|| mlua::Error::external(format!("window id {} not found in mux", self.0)))
|
.ok_or_else(|| mlua::Error::external(format!("window id {} not found in mux", self.0)))
|
||||||
}
|
}
|
||||||
|
179
mux/src/lib.rs
179
mux/src/lib.rs
@ -11,9 +11,12 @@ use filedescriptor::{poll, pollfd, socketpair, AsRawSocketDescriptor, FileDescri
|
|||||||
use libc::{SOL_SOCKET, SO_RCVBUF, SO_SNDBUF};
|
use libc::{SOL_SOCKET, SO_RCVBUF, SO_SNDBUF};
|
||||||
use log::error;
|
use log::error;
|
||||||
use metrics::histogram;
|
use metrics::histogram;
|
||||||
|
use parking_lot::{
|
||||||
|
MappedRwLockReadGuard, MappedRwLockWriteGuard, RwLock, RwLockReadGuard, RwLockWriteGuard,
|
||||||
|
};
|
||||||
use percent_encoding::percent_decode_str;
|
use percent_encoding::percent_decode_str;
|
||||||
use portable_pty::{CommandBuilder, ExitStatus, PtySize};
|
use portable_pty::{CommandBuilder, ExitStatus, PtySize};
|
||||||
use std::cell::{Ref, RefCell, RefMut};
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
@ -81,17 +84,17 @@ pub enum MuxNotification {
|
|||||||
static SUB_ID: AtomicUsize = AtomicUsize::new(0);
|
static SUB_ID: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
|
||||||
pub struct Mux {
|
pub struct Mux {
|
||||||
tabs: RefCell<HashMap<TabId, Arc<Tab>>>,
|
tabs: RwLock<HashMap<TabId, Arc<Tab>>>,
|
||||||
panes: RefCell<HashMap<PaneId, Arc<dyn Pane>>>,
|
panes: RwLock<HashMap<PaneId, Arc<dyn Pane>>>,
|
||||||
windows: RefCell<HashMap<WindowId, Window>>,
|
windows: RwLock<HashMap<WindowId, Window>>,
|
||||||
default_domain: RefCell<Option<Arc<dyn Domain>>>,
|
default_domain: RwLock<Option<Arc<dyn Domain>>>,
|
||||||
domains: RefCell<HashMap<DomainId, Arc<dyn Domain>>>,
|
domains: RwLock<HashMap<DomainId, Arc<dyn Domain>>>,
|
||||||
domains_by_name: RefCell<HashMap<String, Arc<dyn Domain>>>,
|
domains_by_name: RwLock<HashMap<String, Arc<dyn Domain>>>,
|
||||||
subscribers: RefCell<HashMap<usize, Box<dyn Fn(MuxNotification) -> bool>>>,
|
subscribers: RwLock<HashMap<usize, Box<dyn Fn(MuxNotification) -> bool>>>,
|
||||||
banner: RefCell<Option<String>>,
|
banner: RwLock<Option<String>>,
|
||||||
clients: RefCell<HashMap<ClientId, ClientInfo>>,
|
clients: RwLock<HashMap<ClientId, ClientInfo>>,
|
||||||
identity: RefCell<Option<Arc<ClientId>>>,
|
identity: RwLock<Option<Arc<ClientId>>>,
|
||||||
num_panes_by_workspace: RefCell<HashMap<String, usize>>,
|
num_panes_by_workspace: RwLock<HashMap<String, usize>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
const BUFSIZE: usize = 1024 * 1024;
|
const BUFSIZE: usize = 1024 * 1024;
|
||||||
@ -374,52 +377,52 @@ impl Mux {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
tabs: RefCell::new(HashMap::new()),
|
tabs: RwLock::new(HashMap::new()),
|
||||||
panes: RefCell::new(HashMap::new()),
|
panes: RwLock::new(HashMap::new()),
|
||||||
windows: RefCell::new(HashMap::new()),
|
windows: RwLock::new(HashMap::new()),
|
||||||
default_domain: RefCell::new(default_domain),
|
default_domain: RwLock::new(default_domain),
|
||||||
domains_by_name: RefCell::new(domains_by_name),
|
domains_by_name: RwLock::new(domains_by_name),
|
||||||
domains: RefCell::new(domains),
|
domains: RwLock::new(domains),
|
||||||
subscribers: RefCell::new(HashMap::new()),
|
subscribers: RwLock::new(HashMap::new()),
|
||||||
banner: RefCell::new(None),
|
banner: RwLock::new(None),
|
||||||
clients: RefCell::new(HashMap::new()),
|
clients: RwLock::new(HashMap::new()),
|
||||||
identity: RefCell::new(None),
|
identity: RwLock::new(None),
|
||||||
num_panes_by_workspace: RefCell::new(HashMap::new()),
|
num_panes_by_workspace: RwLock::new(HashMap::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn recompute_pane_count(&self) {
|
fn recompute_pane_count(&self) {
|
||||||
let mut count = HashMap::new();
|
let mut count = HashMap::new();
|
||||||
for window in self.windows.borrow().values() {
|
for window in self.windows.read().values() {
|
||||||
let workspace = window.get_workspace();
|
let workspace = window.get_workspace();
|
||||||
for tab in window.iter() {
|
for tab in window.iter() {
|
||||||
*count.entry(workspace.to_string()).or_insert(0) += tab.count_panes();
|
*count.entry(workspace.to_string()).or_insert(0) += tab.count_panes();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*self.num_panes_by_workspace.borrow_mut() = count;
|
*self.num_panes_by_workspace.write() = count;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn client_had_input(&self, client_id: &ClientId) {
|
pub fn client_had_input(&self, client_id: &ClientId) {
|
||||||
if let Some(info) = self.clients.borrow_mut().get_mut(client_id) {
|
if let Some(info) = self.clients.write().get_mut(client_id) {
|
||||||
info.update_last_input();
|
info.update_last_input();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn record_input_for_current_identity(&self) {
|
pub fn record_input_for_current_identity(&self) {
|
||||||
if let Some(ident) = self.identity.borrow().as_ref() {
|
if let Some(ident) = self.identity.read().as_ref() {
|
||||||
self.client_had_input(ident);
|
self.client_had_input(ident);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn record_focus_for_current_identity(&self, pane_id: PaneId) {
|
pub fn record_focus_for_current_identity(&self, pane_id: PaneId) {
|
||||||
if let Some(ident) = self.identity.borrow().as_ref() {
|
if let Some(ident) = self.identity.read().as_ref() {
|
||||||
self.record_focus_for_client(ident, pane_id);
|
self.record_focus_for_client(ident, pane_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn record_focus_for_client(&self, client_id: &ClientId, pane_id: PaneId) {
|
pub fn record_focus_for_client(&self, client_id: &ClientId, pane_id: PaneId) {
|
||||||
let mut prior = None;
|
let mut prior = None;
|
||||||
if let Some(info) = self.clients.borrow_mut().get_mut(client_id) {
|
if let Some(info) = self.clients.write().get_mut(client_id) {
|
||||||
prior = info.focused_pane_id;
|
prior = info.focused_pane_id;
|
||||||
info.update_focused_pane(pane_id);
|
info.update_focused_pane(pane_id);
|
||||||
}
|
}
|
||||||
@ -440,13 +443,13 @@ impl Mux {
|
|||||||
|
|
||||||
pub fn register_client(&self, client_id: Arc<ClientId>) {
|
pub fn register_client(&self, client_id: Arc<ClientId>) {
|
||||||
self.clients
|
self.clients
|
||||||
.borrow_mut()
|
.write()
|
||||||
.insert((*client_id).clone(), ClientInfo::new(client_id));
|
.insert((*client_id).clone(), ClientInfo::new(client_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter_clients(&self) -> Vec<ClientInfo> {
|
pub fn iter_clients(&self) -> Vec<ClientInfo> {
|
||||||
self.clients
|
self.clients
|
||||||
.borrow()
|
.read()
|
||||||
.values()
|
.values()
|
||||||
.map(|info| info.clone())
|
.map(|info| info.clone())
|
||||||
.collect()
|
.collect()
|
||||||
@ -457,7 +460,7 @@ impl Mux {
|
|||||||
pub fn iter_workspaces(&self) -> Vec<String> {
|
pub fn iter_workspaces(&self) -> Vec<String> {
|
||||||
let mut names: Vec<String> = self
|
let mut names: Vec<String> = self
|
||||||
.windows
|
.windows
|
||||||
.borrow()
|
.read()
|
||||||
.values()
|
.values()
|
||||||
.map(|w| w.get_workspace().to_string())
|
.map(|w| w.get_workspace().to_string())
|
||||||
.collect();
|
.collect();
|
||||||
@ -480,11 +483,11 @@ impl Mux {
|
|||||||
/// Returns the effective active workspace name
|
/// Returns the effective active workspace name
|
||||||
pub fn active_workspace(&self) -> String {
|
pub fn active_workspace(&self) -> String {
|
||||||
self.identity
|
self.identity
|
||||||
.borrow()
|
.read()
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|ident| {
|
.and_then(|ident| {
|
||||||
self.clients
|
self.clients
|
||||||
.borrow()
|
.read()
|
||||||
.get(&ident)
|
.get(&ident)
|
||||||
.and_then(|info| info.active_workspace.clone())
|
.and_then(|info| info.active_workspace.clone())
|
||||||
})
|
})
|
||||||
@ -494,14 +497,14 @@ impl Mux {
|
|||||||
/// Returns the effective active workspace name for a given client
|
/// Returns the effective active workspace name for a given client
|
||||||
pub fn active_workspace_for_client(&self, ident: &Arc<ClientId>) -> String {
|
pub fn active_workspace_for_client(&self, ident: &Arc<ClientId>) -> String {
|
||||||
self.clients
|
self.clients
|
||||||
.borrow()
|
.read()
|
||||||
.get(&ident)
|
.get(&ident)
|
||||||
.and_then(|info| info.active_workspace.clone())
|
.and_then(|info| info.active_workspace.clone())
|
||||||
.unwrap_or_else(|| DEFAULT_WORKSPACE.to_string())
|
.unwrap_or_else(|| DEFAULT_WORKSPACE.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_active_workspace_for_client(&self, ident: &Arc<ClientId>, workspace: &str) {
|
pub fn set_active_workspace_for_client(&self, ident: &Arc<ClientId>, workspace: &str) {
|
||||||
let mut clients = self.clients.borrow_mut();
|
let mut clients = self.clients.write();
|
||||||
if let Some(info) = clients.get_mut(&ident) {
|
if let Some(info) = clients.get_mut(&ident) {
|
||||||
info.active_workspace.replace(workspace.to_string());
|
info.active_workspace.replace(workspace.to_string());
|
||||||
self.notify(MuxNotification::ActiveWorkspaceChanged(ident.clone()));
|
self.notify(MuxNotification::ActiveWorkspaceChanged(ident.clone()));
|
||||||
@ -510,7 +513,7 @@ impl Mux {
|
|||||||
|
|
||||||
/// Assigns the active workspace name for the current identity
|
/// Assigns the active workspace name for the current identity
|
||||||
pub fn set_active_workspace(&self, workspace: &str) {
|
pub fn set_active_workspace(&self, workspace: &str) {
|
||||||
if let Some(ident) = self.identity.borrow().clone() {
|
if let Some(ident) = self.identity.read().clone() {
|
||||||
self.set_active_workspace_for_client(&ident, workspace);
|
self.set_active_workspace_for_client(&ident, workspace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -526,16 +529,16 @@ impl Mux {
|
|||||||
|
|
||||||
/// Replace the identity, returning the prior identity
|
/// Replace the identity, returning the prior identity
|
||||||
pub fn replace_identity(&self, id: Option<Arc<ClientId>>) -> Option<Arc<ClientId>> {
|
pub fn replace_identity(&self, id: Option<Arc<ClientId>>) -> Option<Arc<ClientId>> {
|
||||||
std::mem::replace(&mut *self.identity.borrow_mut(), id)
|
std::mem::replace(&mut *self.identity.write(), id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the active identity
|
/// Returns the active identity
|
||||||
pub fn active_identity(&self) -> Option<Arc<ClientId>> {
|
pub fn active_identity(&self) -> Option<Arc<ClientId>> {
|
||||||
self.identity.borrow().clone()
|
self.identity.read().clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unregister_client(&self, client_id: &ClientId) {
|
pub fn unregister_client(&self, client_id: &ClientId) {
|
||||||
self.clients.borrow_mut().remove(client_id);
|
self.clients.write().remove(client_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn subscribe<F>(&self, subscriber: F)
|
pub fn subscribe<F>(&self, subscriber: F)
|
||||||
@ -544,12 +547,12 @@ impl Mux {
|
|||||||
{
|
{
|
||||||
let sub_id = SUB_ID.fetch_add(1, Ordering::Relaxed);
|
let sub_id = SUB_ID.fetch_add(1, Ordering::Relaxed);
|
||||||
self.subscribers
|
self.subscribers
|
||||||
.borrow_mut()
|
.write()
|
||||||
.insert(sub_id, Box::new(subscriber));
|
.insert(sub_id, Box::new(subscriber));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn notify(&self, notification: MuxNotification) {
|
pub fn notify(&self, notification: MuxNotification) {
|
||||||
let mut subscribers = self.subscribers.borrow_mut();
|
let mut subscribers = self.subscribers.write();
|
||||||
subscribers.retain(|_, notify| notify(notification.clone()));
|
subscribers.retain(|_, notify| notify(notification.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -567,34 +570,30 @@ impl Mux {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn default_domain(&self) -> Arc<dyn Domain> {
|
pub fn default_domain(&self) -> Arc<dyn Domain> {
|
||||||
self.default_domain
|
self.default_domain.read().as_ref().map(Arc::clone).unwrap()
|
||||||
.borrow()
|
|
||||||
.as_ref()
|
|
||||||
.map(Arc::clone)
|
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_default_domain(&self, domain: &Arc<dyn Domain>) {
|
pub fn set_default_domain(&self, domain: &Arc<dyn Domain>) {
|
||||||
*self.default_domain.borrow_mut() = Some(Arc::clone(domain));
|
*self.default_domain.write() = Some(Arc::clone(domain));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_domain(&self, id: DomainId) -> Option<Arc<dyn Domain>> {
|
pub fn get_domain(&self, id: DomainId) -> Option<Arc<dyn Domain>> {
|
||||||
self.domains.borrow().get(&id).cloned()
|
self.domains.read().get(&id).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_domain_by_name(&self, name: &str) -> Option<Arc<dyn Domain>> {
|
pub fn get_domain_by_name(&self, name: &str) -> Option<Arc<dyn Domain>> {
|
||||||
self.domains_by_name.borrow().get(name).cloned()
|
self.domains_by_name.read().get(name).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_domain(&self, domain: &Arc<dyn Domain>) {
|
pub fn add_domain(&self, domain: &Arc<dyn Domain>) {
|
||||||
if self.default_domain.borrow().is_none() {
|
if self.default_domain.read().is_none() {
|
||||||
*self.default_domain.borrow_mut() = Some(Arc::clone(domain));
|
*self.default_domain.write() = Some(Arc::clone(domain));
|
||||||
}
|
}
|
||||||
self.domains
|
self.domains
|
||||||
.borrow_mut()
|
.write()
|
||||||
.insert(domain.domain_id(), Arc::clone(domain));
|
.insert(domain.domain_id(), Arc::clone(domain));
|
||||||
self.domains_by_name
|
self.domains_by_name
|
||||||
.borrow_mut()
|
.write()
|
||||||
.insert(domain.domain_name().to_string(), Arc::clone(domain));
|
.insert(domain.domain_name().to_string(), Arc::clone(domain));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -619,15 +618,15 @@ impl Mux {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_pane(&self, pane_id: PaneId) -> Option<Arc<dyn Pane>> {
|
pub fn get_pane(&self, pane_id: PaneId) -> Option<Arc<dyn Pane>> {
|
||||||
self.panes.borrow().get(&pane_id).map(Arc::clone)
|
self.panes.read().get(&pane_id).map(Arc::clone)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_tab(&self, tab_id: TabId) -> Option<Arc<Tab>> {
|
pub fn get_tab(&self, tab_id: TabId) -> Option<Arc<Tab>> {
|
||||||
self.tabs.borrow().get(&tab_id).map(Arc::clone)
|
self.tabs.read().get(&tab_id).map(Arc::clone)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_pane(&self, pane: &Arc<dyn Pane>) -> Result<(), Error> {
|
pub fn add_pane(&self, pane: &Arc<dyn Pane>) -> Result<(), Error> {
|
||||||
if self.panes.borrow().contains_key(&pane.pane_id()) {
|
if self.panes.read().contains_key(&pane.pane_id()) {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -639,12 +638,10 @@ impl Mux {
|
|||||||
let downloader: Arc<dyn DownloadHandler> = Arc::new(MuxDownloader {});
|
let downloader: Arc<dyn DownloadHandler> = Arc::new(MuxDownloader {});
|
||||||
pane.set_download_handler(&downloader);
|
pane.set_download_handler(&downloader);
|
||||||
|
|
||||||
self.panes
|
self.panes.write().insert(pane.pane_id(), Arc::clone(pane));
|
||||||
.borrow_mut()
|
|
||||||
.insert(pane.pane_id(), Arc::clone(pane));
|
|
||||||
let pane_id = pane.pane_id();
|
let pane_id = pane.pane_id();
|
||||||
if let Some(reader) = pane.reader()? {
|
if let Some(reader) = pane.reader()? {
|
||||||
let banner = self.banner.borrow().clone();
|
let banner = self.banner.read().clone();
|
||||||
let pane = Arc::clone(pane);
|
let pane = Arc::clone(pane);
|
||||||
thread::spawn(move || read_from_pane_pty(pane, banner, reader));
|
thread::spawn(move || read_from_pane_pty(pane, banner, reader));
|
||||||
}
|
}
|
||||||
@ -654,12 +651,12 @@ impl Mux {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_tab_no_panes(&self, tab: &Arc<Tab>) {
|
pub fn add_tab_no_panes(&self, tab: &Arc<Tab>) {
|
||||||
self.tabs.borrow_mut().insert(tab.tab_id(), Arc::clone(tab));
|
self.tabs.write().insert(tab.tab_id(), Arc::clone(tab));
|
||||||
self.recompute_pane_count();
|
self.recompute_pane_count();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_tab_and_active_pane(&self, tab: &Arc<Tab>) -> Result<(), Error> {
|
pub fn add_tab_and_active_pane(&self, tab: &Arc<Tab>) -> Result<(), Error> {
|
||||||
self.tabs.borrow_mut().insert(tab.tab_id(), Arc::clone(tab));
|
self.tabs.write().insert(tab.tab_id(), Arc::clone(tab));
|
||||||
let pane = tab
|
let pane = tab
|
||||||
.get_active_pane()
|
.get_active_pane()
|
||||||
.ok_or_else(|| anyhow!("tab MUST have an active pane"))?;
|
.ok_or_else(|| anyhow!("tab MUST have an active pane"))?;
|
||||||
@ -668,7 +665,7 @@ impl Mux {
|
|||||||
|
|
||||||
fn remove_pane_internal(&self, pane_id: PaneId) {
|
fn remove_pane_internal(&self, pane_id: PaneId) {
|
||||||
log::debug!("removing pane {}", pane_id);
|
log::debug!("removing pane {}", pane_id);
|
||||||
if let Some(pane) = self.panes.borrow_mut().remove(&pane_id).clone() {
|
if let Some(pane) = self.panes.write().remove(&pane_id).clone() {
|
||||||
log::debug!("killing pane {}", pane_id);
|
log::debug!("killing pane {}", pane_id);
|
||||||
pane.kill();
|
pane.kill();
|
||||||
self.recompute_pane_count();
|
self.recompute_pane_count();
|
||||||
@ -679,9 +676,9 @@ impl Mux {
|
|||||||
fn remove_tab_internal(&self, tab_id: TabId) -> Option<Arc<Tab>> {
|
fn remove_tab_internal(&self, tab_id: TabId) -> Option<Arc<Tab>> {
|
||||||
log::debug!("remove_tab_internal tab {}", tab_id);
|
log::debug!("remove_tab_internal tab {}", tab_id);
|
||||||
|
|
||||||
let tab = self.tabs.borrow_mut().remove(&tab_id)?;
|
let tab = self.tabs.write().remove(&tab_id)?;
|
||||||
|
|
||||||
if let Ok(mut windows) = self.windows.try_borrow_mut() {
|
if let Some(mut windows) = self.windows.try_write() {
|
||||||
for w in windows.values_mut() {
|
for w in windows.values_mut() {
|
||||||
w.remove_by_id(tab_id);
|
w.remove_by_id(tab_id);
|
||||||
}
|
}
|
||||||
@ -702,11 +699,11 @@ impl Mux {
|
|||||||
|
|
||||||
fn remove_window_internal(&self, window_id: WindowId) {
|
fn remove_window_internal(&self, window_id: WindowId) {
|
||||||
log::debug!("remove_window_internal {}", window_id);
|
log::debug!("remove_window_internal {}", window_id);
|
||||||
let domains: Vec<Arc<dyn Domain>> = self.domains.borrow().values().cloned().collect();
|
let domains: Vec<Arc<dyn Domain>> = self.domains.read().values().cloned().collect();
|
||||||
for dom in domains {
|
for dom in domains {
|
||||||
dom.local_window_is_closing(window_id);
|
dom.local_window_is_closing(window_id);
|
||||||
}
|
}
|
||||||
let window = self.windows.borrow_mut().remove(&window_id);
|
let window = self.windows.write().remove(&window_id);
|
||||||
if let Some(window) = window {
|
if let Some(window) = window {
|
||||||
for tab in window.iter() {
|
for tab in window.iter() {
|
||||||
self.remove_tab_internal(tab.tab_id());
|
self.remove_tab_internal(tab.tab_id());
|
||||||
@ -732,14 +729,14 @@ impl Mux {
|
|||||||
log::trace!("prune_dead_windows: Activity::count={}", Activity::count());
|
log::trace!("prune_dead_windows: Activity::count={}", Activity::count());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let live_tab_ids: Vec<TabId> = self.tabs.borrow().keys().cloned().collect();
|
let live_tab_ids: Vec<TabId> = self.tabs.read().keys().cloned().collect();
|
||||||
let mut dead_windows = vec![];
|
let mut dead_windows = vec![];
|
||||||
let dead_tab_ids: Vec<TabId>;
|
let dead_tab_ids: Vec<TabId>;
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut windows = match self.windows.try_borrow_mut() {
|
let mut windows = match self.windows.try_write() {
|
||||||
Ok(w) => w,
|
Some(w) => w,
|
||||||
Err(_) => {
|
None => {
|
||||||
// It's ok if our caller already locked it; we can prune later.
|
// It's ok if our caller already locked it; we can prune later.
|
||||||
log::trace!("prune_dead_windows: self.windows already borrowed");
|
log::trace!("prune_dead_windows: self.windows already borrowed");
|
||||||
return;
|
return;
|
||||||
@ -755,7 +752,7 @@ impl Mux {
|
|||||||
|
|
||||||
dead_tab_ids = self
|
dead_tab_ids = self
|
||||||
.tabs
|
.tabs
|
||||||
.borrow()
|
.read()
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|(&id, tab)| if tab.is_dead() { Some(id) } else { None })
|
.filter_map(|(&id, tab)| if tab.is_dead() { Some(id) } else { None })
|
||||||
.collect();
|
.collect();
|
||||||
@ -784,20 +781,20 @@ impl Mux {
|
|||||||
self.prune_dead_windows();
|
self.prune_dead_windows();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_window(&self, window_id: WindowId) -> Option<Ref<Window>> {
|
pub fn get_window(&self, window_id: WindowId) -> Option<MappedRwLockReadGuard<Window>> {
|
||||||
if !self.windows.borrow().contains_key(&window_id) {
|
if !self.windows.read().contains_key(&window_id) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
Some(Ref::map(self.windows.borrow(), |windows| {
|
Some(RwLockReadGuard::map(self.windows.read(), |windows| {
|
||||||
windows.get(&window_id).unwrap()
|
windows.get(&window_id).unwrap()
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_window_mut(&self, window_id: WindowId) -> Option<RefMut<Window>> {
|
pub fn get_window_mut(&self, window_id: WindowId) -> Option<MappedRwLockWriteGuard<Window>> {
|
||||||
if !self.windows.borrow().contains_key(&window_id) {
|
if !self.windows.read().contains_key(&window_id) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
Some(RefMut::map(self.windows.borrow_mut(), |windows| {
|
Some(RwLockWriteGuard::map(self.windows.write(), |windows| {
|
||||||
windows.get_mut(&window_id).unwrap()
|
windows.get_mut(&window_id).unwrap()
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@ -810,7 +807,7 @@ impl Mux {
|
|||||||
pub fn new_empty_window(&self, workspace: Option<String>) -> MuxWindowBuilder {
|
pub fn new_empty_window(&self, workspace: Option<String>) -> MuxWindowBuilder {
|
||||||
let window = Window::new(workspace);
|
let window = Window::new(workspace);
|
||||||
let window_id = window.window_id();
|
let window_id = window.window_id();
|
||||||
self.windows.borrow_mut().insert(window_id, window);
|
self.windows.write().insert(window_id, window);
|
||||||
MuxWindowBuilder {
|
MuxWindowBuilder {
|
||||||
window_id,
|
window_id,
|
||||||
activity: Some(Activity::new()),
|
activity: Some(Activity::new()),
|
||||||
@ -832,7 +829,7 @@ impl Mux {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn window_containing_tab(&self, tab_id: TabId) -> Option<WindowId> {
|
pub fn window_containing_tab(&self, tab_id: TabId) -> Option<WindowId> {
|
||||||
for w in self.windows.borrow().values() {
|
for w in self.windows.read().values() {
|
||||||
for t in w.iter() {
|
for t in w.iter() {
|
||||||
if t.tab_id() == tab_id {
|
if t.tab_id() == tab_id {
|
||||||
return Some(w.window_id());
|
return Some(w.window_id());
|
||||||
@ -843,13 +840,13 @@ impl Mux {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.panes.borrow().is_empty()
|
self.panes.read().is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_workspace_empty(&self, workspace: &str) -> bool {
|
pub fn is_workspace_empty(&self, workspace: &str) -> bool {
|
||||||
*self
|
*self
|
||||||
.num_panes_by_workspace
|
.num_panes_by_workspace
|
||||||
.borrow()
|
.read()
|
||||||
.get(workspace)
|
.get(workspace)
|
||||||
.unwrap_or(&0)
|
.unwrap_or(&0)
|
||||||
== 0
|
== 0
|
||||||
@ -862,7 +859,7 @@ impl Mux {
|
|||||||
|
|
||||||
pub fn iter_panes(&self) -> Vec<Arc<dyn Pane>> {
|
pub fn iter_panes(&self) -> Vec<Arc<dyn Pane>> {
|
||||||
self.panes
|
self.panes
|
||||||
.borrow()
|
.read()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(_, v)| Arc::clone(v))
|
.map(|(_, v)| Arc::clone(v))
|
||||||
.collect()
|
.collect()
|
||||||
@ -871,7 +868,7 @@ impl Mux {
|
|||||||
pub fn iter_windows_in_workspace(&self, workspace: &str) -> Vec<WindowId> {
|
pub fn iter_windows_in_workspace(&self, workspace: &str) -> Vec<WindowId> {
|
||||||
let mut windows: Vec<WindowId> = self
|
let mut windows: Vec<WindowId> = self
|
||||||
.windows
|
.windows
|
||||||
.borrow()
|
.read()
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|(k, w)| {
|
.filter_map(|(k, w)| {
|
||||||
if w.get_workspace() == workspace {
|
if w.get_workspace() == workspace {
|
||||||
@ -887,16 +884,16 @@ impl Mux {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter_windows(&self) -> Vec<WindowId> {
|
pub fn iter_windows(&self) -> Vec<WindowId> {
|
||||||
self.windows.borrow().keys().cloned().collect()
|
self.windows.read().keys().cloned().collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter_domains(&self) -> Vec<Arc<dyn Domain>> {
|
pub fn iter_domains(&self) -> Vec<Arc<dyn Domain>> {
|
||||||
self.domains.borrow().values().cloned().collect()
|
self.domains.read().values().cloned().collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_pane_id(&self, pane_id: PaneId) -> Option<(DomainId, WindowId, TabId)> {
|
pub fn resolve_pane_id(&self, pane_id: PaneId) -> Option<(DomainId, WindowId, TabId)> {
|
||||||
let mut ids = None;
|
let mut ids = None;
|
||||||
for tab in self.tabs.borrow().values() {
|
for tab in self.tabs.read().values() {
|
||||||
for p in tab.iter_panes_ignoring_zoom() {
|
for p in tab.iter_panes_ignoring_zoom() {
|
||||||
if p.pane.pane_id() == pane_id {
|
if p.pane.pane_id() == pane_id {
|
||||||
ids = Some((tab.tab_id(), p.pane.domain_id()));
|
ids = Some((tab.tab_id(), p.pane.domain_id()));
|
||||||
@ -911,14 +908,14 @@ impl Mux {
|
|||||||
|
|
||||||
pub fn domain_was_detached(&self, domain: DomainId) {
|
pub fn domain_was_detached(&self, domain: DomainId) {
|
||||||
let mut dead_panes = vec![];
|
let mut dead_panes = vec![];
|
||||||
for pane in self.panes.borrow().values() {
|
for pane in self.panes.read().values() {
|
||||||
if pane.domain_id() == domain {
|
if pane.domain_id() == domain {
|
||||||
dead_panes.push(pane.pane_id());
|
dead_panes.push(pane.pane_id());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut windows = self.windows.borrow_mut();
|
let mut windows = self.windows.write();
|
||||||
for (_, win) in windows.iter_mut() {
|
for (_, win) in windows.iter_mut() {
|
||||||
for tab in win.iter() {
|
for tab in win.iter() {
|
||||||
tab.kill_panes_in_domain(domain);
|
tab.kill_panes_in_domain(domain);
|
||||||
@ -935,7 +932,7 @@ impl Mux {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_banner(&self, banner: Option<String>) {
|
pub fn set_banner(&self, banner: Option<String>) {
|
||||||
*self.banner.borrow_mut() = banner;
|
*self.banner.write() = banner;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_spawn_tab_domain(
|
pub fn resolve_spawn_tab_domain(
|
||||||
|
Loading…
Reference in New Issue
Block a user