Remove the notion of the "principal" environment stack

The "principal" environment stack was the one that was associated with the
"principal" parser and would dispatch changes like to TZ, etc.

This was always very suspicious, as a global; now we can remove it.
This commit is contained in:
Peter Ammon 2024-06-23 13:49:30 -07:00
parent dbf54f49ff
commit 631516398e
No known key found for this signature in database
5 changed files with 18 additions and 33 deletions

View file

@ -187,13 +187,15 @@ impl EnvStack {
} }
} }
// Creates a new EnvStack which dispatches variable changes. // Create a "sub-stack" of the given stack.
// This should be associated with the principal larser. // This shares all nodes (variable scopes) with the parent stack.
pub fn new_dispatching() -> EnvStack { // can_push_pop is always set.
pub fn create_child(&self, dispatches_var_changes: bool) -> EnvStack {
let inner = EnvMutex::new(self.inner.lock().clone());
EnvStack { EnvStack {
inner: EnvStackImpl::new(), inner,
can_push_pop: true, can_push_pop: true,
dispatches_var_changes: true, dispatches_var_changes,
} }
} }
@ -201,11 +203,6 @@ impl EnvStack {
self.inner.lock() self.inner.lock()
} }
/// Return whether we are the principal stack.
pub fn is_principal(&self) -> bool {
std::ptr::eq(self, &**Self::principal())
}
/// Helpers to get and set the proc statuses. /// Helpers to get and set the proc statuses.
/// These correspond to $status and $pipestatus. /// These correspond to $status and $pipestatus.
pub fn get_last_statuses(&self) -> Statuses { pub fn get_last_statuses(&self) -> Statuses {
@ -387,13 +384,6 @@ impl EnvStack {
}) })
} }
/// Access the principal variable stack, associated with the principal parser.
pub fn principal() -> &'static Arc<EnvStack> {
use std::sync::OnceLock;
static PRINCIPAL_STACK: OnceLock<Arc<EnvStack>> = OnceLock::new();
PRINCIPAL_STACK.get_or_init(|| Arc::new(EnvStack::new_dispatching()))
}
pub fn set_argv(&self, argv: Vec<WString>) { pub fn set_argv(&self, argv: Vec<WString>) {
self.set(L!("argv"), EnvMode::LOCAL, argv); self.set(L!("argv"), EnvMode::LOCAL, argv);
} }
@ -575,7 +565,7 @@ fn setup_path() {
pub static INHERITED_VARS: OnceCell<HashMap<WString, WString>> = OnceCell::new(); pub static INHERITED_VARS: OnceCell<HashMap<WString, WString>> = OnceCell::new();
pub fn env_init(paths: Option<&ConfigPaths>, do_uvars: bool, default_paths: bool) { pub fn env_init(paths: Option<&ConfigPaths>, do_uvars: bool, default_paths: bool) {
let vars = &**EnvStack::principal(); let vars = EnvStack::globals();
let env_iter: Vec<_> = std::env::vars_os() let env_iter: Vec<_> = std::env::vars_os()
.map(|(k, v)| (str2wcstring(k.as_bytes()), str2wcstring(v.as_bytes()))) .map(|(k, v)| (str2wcstring(k.as_bytes()), str2wcstring(v.as_bytes())))

View file

@ -300,6 +300,7 @@ struct PerprocData {
statuses: Statuses, statuses: Statuses,
} }
#[derive(Clone)]
pub struct EnvScopedImpl { pub struct EnvScopedImpl {
// A linked list of scopes. // A linked list of scopes.
locals: EnvNodeRef, locals: EnvNodeRef,
@ -690,6 +691,7 @@ impl ModResult {
} }
/// A mutable "subclass" of EnvScopedImpl. /// A mutable "subclass" of EnvScopedImpl.
#[derive(Clone)]
pub struct EnvStackImpl { pub struct EnvStackImpl {
pub base: EnvScopedImpl, pub base: EnvScopedImpl,
@ -1122,7 +1124,7 @@ pub struct EnvMutex<T> {
} }
impl<T> EnvMutex<T> { impl<T> EnvMutex<T> {
fn new(inner: T) -> Self { pub fn new(inner: T) -> Self {
Self { Self {
inner: UnsafeCell::new(inner), inner: UnsafeCell::new(inner),
} }

View file

@ -455,17 +455,10 @@ impl Parser {
pub fn principal_parser() -> &'static Parser { pub fn principal_parser() -> &'static Parser {
use std::cell::OnceCell; use std::cell::OnceCell;
static PRINCIPAL: MainThread<OnceCell<ParserRef>> = MainThread::new(OnceCell::new()); static PRINCIPAL: MainThread<OnceCell<ParserRef>> = MainThread::new(OnceCell::new());
PRINCIPAL PRINCIPAL.get().get_or_init(|| {
.get() let dispatches_var_changes = true;
// The parser is !Send/!Sync and strictly single-threaded, but we can have let env = Rc::new(EnvStack::globals().create_child(dispatches_var_changes));
// multi-threaded access to its variables stack (why, though?) so EnvStack::principal() Parser::new(env, true)
// returns an Arc<EnvStack> instead of an Rc<EnvStack>. Since the Arc<EnvStack> is
// statically allocated and always valid (not even destroyed on exit), we can safely
// transform the Arc<T> into an Rc<T> and save Parser from needing atomic ref counting
// to manage its further references.
.get_or_init(|| {
let env_rc = unsafe { Rc::from_raw(&**EnvStack::principal() as *const _) };
Parser::new(env_rc, true)
}) })
} }

View file

@ -57,7 +57,7 @@ impl Environment for PwdEnvironment {
/// Helper for test_timezone_env_vars(). /// Helper for test_timezone_env_vars().
fn return_timezone_hour(tstamp: SystemTime, timezone: &wstr) -> libc::c_int { fn return_timezone_hour(tstamp: SystemTime, timezone: &wstr) -> libc::c_int {
let vars = EnvStack::new_dispatching(); let vars = EnvStack::globals().create_child(true /* dispatches_var_changes */);
vars.set_one(L!("TZ"), EnvMode::EXPORT, timezone.to_owned()); vars.set_one(L!("TZ"), EnvMode::EXPORT, timezone.to_owned());

View file

@ -107,7 +107,7 @@ pub mod prelude {
signal_reset_handlers(); signal_reset_handlers();
// Set PWD from getcwd - fixes #5599 // Set PWD from getcwd - fixes #5599
EnvStack::principal().set_pwd_from_getcwd(); EnvStack::globals().set_pwd_from_getcwd();
}); });
reader_init() reader_init()
} }