about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/os.rs40
1 files changed, 26 insertions, 14 deletions
diff --git a/src/libstd/os.rs b/src/libstd/os.rs
index 4bfd3bbcd3f..fb5be0494ef 100644
--- a/src/libstd/os.rs
+++ b/src/libstd/os.rs
@@ -869,26 +869,38 @@ pub fn change_dir(p: &Path) -> bool {
 /// CWD to what it was before, returning true.
 /// Returns false if the directory doesn't exist or if the directory change
 /// is otherwise unsuccessful.
+/// FIXME #7870 This probably shouldn't be part of the public API
 pub fn change_dir_locked(p: &Path, action: &fn()) -> bool {
-    use unstable::global::global_data_clone_create;
-    use unstable::sync::{Exclusive, exclusive};
-
-    fn key(_: Exclusive<()>) { }
+    use task;
+    use unstable::finally::Finally;
 
     unsafe {
-        let result = global_data_clone_create(key, || { ~exclusive(()) });
-
-        do result.with_imm() |_| {
-            let old_dir = os::getcwd();
-            if change_dir(p) {
-                action();
-                change_dir(&old_dir)
-            }
-            else {
-                false
+        // This is really sketchy. Using a pthread mutex so descheduling
+        // in the `action` callback can cause deadlock. Doing it in
+        // `task::atomically` to try to avoid that, but ... I don't know
+        // this is all bogus.
+        return do task::atomically {
+            rust_take_change_dir_lock();
+
+            do (||{
+                let old_dir = os::getcwd();
+                if change_dir(p) {
+                    action();
+                    change_dir(&old_dir)
+                }
+                else {
+                    false
+                }
+            }).finally {
+                rust_drop_change_dir_lock();
             }
         }
     }
+
+    extern {
+        fn rust_take_change_dir_lock();
+        fn rust_drop_change_dir_lock();
+    }
 }
 
 /// Copies a file from one location to another