diff options
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/os.rs | 40 |
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 |
