diff --git a/src/libcore/os.rs b/src/libcore/os.rs index ff3253a8223f..2de7ecf7dff1 100644 --- a/src/libcore/os.rs +++ b/src/libcore/os.rs @@ -139,169 +139,101 @@ pub mod win32 { } } -pub fn getenv(n: &str) -> Option<~str> { - global_env::getenv(n) -} +/* +Accessing environment variables is not generally threadsafe. +This uses a per-runtime lock to serialize access. +XXX: It would probably be appropriate to make this a real global +*/ +fn with_env_lock(f: &fn() -> T) -> T { + use private::global::global_data_clone_create; + use private::{Exclusive, exclusive}; -pub fn setenv(n: &str, v: &str) { - global_env::setenv(n, v) + struct SharedValue(()); + type ValueMutex = Exclusive; + fn key(_: ValueMutex) { } + + unsafe { + let lock: ValueMutex = global_data_clone_create(key, || { + ~exclusive(SharedValue(())) + }); + + lock.with_imm(|_| f() ) + } } pub fn env() -> ~[(~str,~str)] { - global_env::env() + extern mod rustrt { + unsafe fn rust_env_pairs() -> ~[~str]; + } + + unsafe { + do with_env_lock { + let mut pairs = ~[]; + for vec::each(rustrt::rust_env_pairs()) |p| { + let vs = str::splitn_char(*p, '=', 1u); + assert vec::len(vs) == 2u; + pairs.push((copy vs[0], copy vs[1])); + } + move pairs + } + } } -mod global_env { - //! Internal module for serializing access to getenv/setenv - use either; - use libc; - use oldcomm; - use option::Option; - use private; - use str; - use task; - - extern mod rustrt { - unsafe fn rust_global_env_chan_ptr() -> *libc::uintptr_t; - } - - enum Msg { - MsgGetEnv(~str, oldcomm::Chan>), - MsgSetEnv(~str, ~str, oldcomm::Chan<()>), - MsgEnv(oldcomm::Chan<~[(~str,~str)]>) - } - - pub fn getenv(n: &str) -> Option<~str> { - let env_ch = get_global_env_chan(); - let po = oldcomm::Port(); - oldcomm::send(env_ch, MsgGetEnv(str::from_slice(n), - oldcomm::Chan(&po))); - oldcomm::recv(po) - } - - pub fn setenv(n: &str, v: &str) { - let env_ch = get_global_env_chan(); - let po = oldcomm::Port(); - oldcomm::send(env_ch, MsgSetEnv(str::from_slice(n), - str::from_slice(v), - oldcomm::Chan(&po))); - oldcomm::recv(po) - } - - pub fn env() -> ~[(~str,~str)] { - let env_ch = get_global_env_chan(); - let po = oldcomm::Port(); - oldcomm::send(env_ch, MsgEnv(oldcomm::Chan(&po))); - oldcomm::recv(po) - } - - fn get_global_env_chan() -> oldcomm::Chan { - unsafe { - let global_ptr = rustrt::rust_global_env_chan_ptr(); - private::chan_from_global_ptr(global_ptr, || { - // FIXME (#2621): This would be a good place to use a very - // small foreign stack - task::task().sched_mode(task::SingleThreaded).unlinked() - }, global_env_task) +#[cfg(unix)] +pub fn getenv(n: &str) -> Option<~str> { + unsafe { + do with_env_lock { + let s = str::as_c_str(n, |s| libc::getenv(s)); + if ptr::null::() == cast::reinterpret_cast(&s) { + option::None::<~str> + } else { + let s = cast::reinterpret_cast(&s); + option::Some::<~str>(str::raw::from_buf(s)) + } } } +} - fn global_env_task(msg_po: oldcomm::Port) { - unsafe { - do private::weaken_task |weak_po| { - loop { - match oldcomm::select2(msg_po, weak_po) { - either::Left(MsgGetEnv(ref n, resp_ch)) => { - oldcomm::send(resp_ch, impl_::getenv(*n)) - } - either::Left(MsgSetEnv(ref n, ref v, resp_ch)) => { - oldcomm::send(resp_ch, impl_::setenv(*n, *v)) - } - either::Left(MsgEnv(resp_ch)) => { - oldcomm::send(resp_ch, impl_::env()) - } - either::Right(_) => break - } +#[cfg(windows)] +pub fn getenv(n: &str) -> Option<~str> { + unsafe { + do with_env_lock { + use os::win32::{as_utf16_p, fill_utf16_buf_and_decode}; + do as_utf16_p(n) |u| { + do fill_utf16_buf_and_decode() |buf, sz| { + libc::GetEnvironmentVariableW(u, buf, sz) } } } } +} - mod impl_ { - use cast; - use libc; - use option::Option; - use option; - use ptr; - use str; - use vec; - extern mod rustrt { - unsafe fn rust_env_pairs() -> ~[~str]; - } - - pub fn env() -> ~[(~str,~str)] { - unsafe { - let mut pairs = ~[]; - for vec::each(rustrt::rust_env_pairs()) |p| { - let vs = str::splitn_char(*p, '=', 1u); - assert vec::len(vs) == 2u; - pairs.push((copy vs[0], copy vs[1])); - } - move pairs - } - } - - #[cfg(unix)] - pub fn getenv(n: &str) -> Option<~str> { - unsafe { - let s = str::as_c_str(n, |s| libc::getenv(s)); - return if ptr::null::() == cast::reinterpret_cast(&s) { - option::None::<~str> - } else { - let s = cast::reinterpret_cast(&s); - option::Some::<~str>(str::raw::from_buf(s)) - }; - } - } - - #[cfg(windows)] - pub fn getenv(n: &str) -> Option<~str> { - unsafe { - use os::win32::{as_utf16_p, fill_utf16_buf_and_decode}; - do as_utf16_p(n) |u| { - do fill_utf16_buf_and_decode() |buf, sz| { - libc::GetEnvironmentVariableW(u, buf, sz) - } +#[cfg(unix)] +pub fn setenv(n: &str, v: &str) { + unsafe { + do with_env_lock { + do str::as_c_str(n) |nbuf| { + do str::as_c_str(v) |vbuf| { + libc::funcs::posix01::unistd::setenv(nbuf, vbuf, 1); } } } + } +} - #[cfg(unix)] - pub fn setenv(n: &str, v: &str) { - unsafe { - do str::as_c_str(n) |nbuf| { - do str::as_c_str(v) |vbuf| { - libc::funcs::posix01::unistd::setenv(nbuf, vbuf, 1); - } +#[cfg(windows)] +pub fn setenv(n: &str, v: &str) { + unsafe { + do with_env_lock { + use os::win32::as_utf16_p; + do as_utf16_p(n) |nbuf| { + do as_utf16_p(v) |vbuf| { + libc::SetEnvironmentVariableW(nbuf, vbuf); } } } - - - #[cfg(windows)] - pub fn setenv(n: &str, v: &str) { - unsafe { - use os::win32::as_utf16_p; - do as_utf16_p(n) |nbuf| { - do as_utf16_p(v) |vbuf| { - libc::SetEnvironmentVariableW(nbuf, vbuf); - } - } - } - } - } } diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp index a5e1260d4a55..327337f441d8 100644 --- a/src/rt/rust_builtin.cpp +++ b/src/rt/rust_builtin.cpp @@ -870,12 +870,6 @@ rust_task_unweaken(rust_port_id chan) { task->kernel->unweaken_task(chan); } -extern "C" CDECL uintptr_t* -rust_global_env_chan_ptr() { - rust_task *task = rust_get_current_task(); - return task->kernel->get_global_env_chan(); -} - extern "C" void rust_task_inhibit_kill(rust_task *task) { task->inhibit_kill(); diff --git a/src/rt/rust_kernel.cpp b/src/rt/rust_kernel.cpp index d270ac076331..7e3428788411 100644 --- a/src/rt/rust_kernel.cpp +++ b/src/rt/rust_kernel.cpp @@ -35,7 +35,6 @@ rust_kernel::rust_kernel(rust_env *env) : osmain_driver(NULL), non_weak_tasks(0), global_loop_chan(0), - global_env_chan(0), at_exit_runner(NULL), at_exit_started(false), env(env), diff --git a/src/rt/rust_kernel.h b/src/rt/rust_kernel.h index f90ecf01a7b3..477e59d1b3e6 100644 --- a/src/rt/rust_kernel.h +++ b/src/rt/rust_kernel.h @@ -131,8 +131,6 @@ class rust_kernel { // Used to communicate with the process-side, global libuv loop uintptr_t global_loop_chan; - // Used to serialize access to getenv/setenv - uintptr_t global_env_chan; lock_and_signal at_exit_lock; spawn_fn at_exit_runner; @@ -193,7 +191,6 @@ public: bool send_to_port(rust_port_id chan, void *sptr); uintptr_t* get_global_loop() { return &global_loop_chan; } - uintptr_t* get_global_env_chan() { return &global_env_chan; } void register_exit_function(spawn_fn runner, fn_env_pair *f); }; diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index 5be823d8fded..dd84e5ff6e7c 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -174,7 +174,6 @@ rust_dbg_do_nothing rust_dbg_breakpoint rust_osmain_sched_id rust_compare_and_swap_ptr -rust_global_env_chan_ptr rust_port_take rust_port_drop rust_port_task