about summary refs log tree commit diff
path: root/src/libcore
diff options
context:
space:
mode:
authorBrian Anderson <banderson@mozilla.com>2013-01-19 22:54:29 -0800
committerBrian Anderson <banderson@mozilla.com>2013-01-23 17:35:34 -0800
commitfb9299346af9b951890db80e47eb65625997f160 (patch)
treec048d87d7ad93562335e9505ed747ef3d86eb142 /src/libcore
parent8852279a9ecac970e30b6d92d7efdcbd5485769c (diff)
core: Convert getenv/setenv to use a mutex
This much simpler implementation uses a global mutex
and eliminates the kernel environment channel.
Diffstat (limited to 'src/libcore')
-rw-r--r--src/libcore/os.rs204
1 files changed, 68 insertions, 136 deletions
diff --git a/src/libcore/os.rs b/src/libcore/os.rs
index ff3253a8223..2de7ecf7dff 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<T>(f: &fn() -> T) -> T {
+    use private::global::global_data_clone_create;
+    use private::{Exclusive, exclusive};
+
+    struct SharedValue(());
+    type ValueMutex = Exclusive<SharedValue>;
+    fn key(_: ValueMutex) { }
 
-pub fn setenv(n: &str, v: &str) {
-    global_env::setenv(n, v)
-}
+    unsafe {
+        let lock: ValueMutex = global_data_clone_create(key, || {
+            ~exclusive(SharedValue(()))
+        });
 
-pub fn env() -> ~[(~str,~str)] {
-    global_env::env()
+        lock.with_imm(|_| f() )
+    }
 }
 
-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;
-
+pub fn env() -> ~[(~str,~str)] {
     extern mod rustrt {
-        unsafe fn rust_global_env_chan_ptr() -> *libc::uintptr_t;
-    }
-
-    enum Msg {
-        MsgGetEnv(~str, oldcomm::Chan<Option<~str>>),
-        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)
+        unsafe fn rust_env_pairs() -> ~[~str];
     }
 
-    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<Msg> {
-        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)
-        }
-    }
-
-    fn global_env_task(msg_po: oldcomm::Port<Msg>) {
-        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
-                    }
-                }
+    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 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::<u8>() == cast::reinterpret_cast(&s) {
-                    option::None::<~str>
-                } else {
-                    let s = cast::reinterpret_cast(&s);
-                    option::Some::<~str>(str::raw::from_buf(s))
-                };
+#[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::<u8>() == 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(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)
                 }
             }
         }
+    }
+}
 
 
-        #[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(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(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);
-                    }
+#[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);
                 }
             }
         }
-
     }
 }