diff --git a/src/libextra/tempfile.rs b/src/libextra/tempfile.rs index f8948f41101..c5fb4b9292e 100644 --- a/src/libextra/tempfile.rs +++ b/src/libextra/tempfile.rs @@ -48,10 +48,11 @@ mod tests { fn recursive_mkdir_rel() { use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; use std::os; + use std::unstable::change_dir_locked; let root = mkdtemp(&os::tmpdir(), "recursive_mkdir_rel"). expect("recursive_mkdir_rel"); - assert!(do os::change_dir_locked(&root) { + assert!(do change_dir_locked(&root) { let path = Path("frob"); debug!("recursive_mkdir_rel: Making: %s in cwd %s [%?]", path.to_str(), os::getcwd().to_str(), @@ -78,10 +79,11 @@ mod tests { fn recursive_mkdir_rel_2() { use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; use std::os; + use std::unstable::change_dir_locked; let root = mkdtemp(&os::tmpdir(), "recursive_mkdir_rel_2"). expect("recursive_mkdir_rel_2"); - assert!(do os::change_dir_locked(&root) { + assert!(do change_dir_locked(&root) { let path = Path("./frob/baz"); debug!("recursive_mkdir_rel_2: Making: %s in cwd %s [%?]", path.to_str(), os::getcwd().to_str(), os::path_exists(&path)); diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs index e6cda8286aa..286b1f84802 100644 --- a/src/librustpkg/tests.rs +++ b/src/librustpkg/tests.rs @@ -791,12 +791,14 @@ fn rust_path_test() { #[test] fn rust_path_contents() { + use std::unstable::change_dir_locked; + let dir = mkdtemp(&os::tmpdir(), "rust_path").expect("rust_path_contents failed"); let abc = &dir.push("A").push("B").push("C"); assert!(os::mkdir_recursive(&abc.push(".rust"), U_RWX)); assert!(os::mkdir_recursive(&abc.pop().push(".rust"), U_RWX)); assert!(os::mkdir_recursive(&abc.pop().pop().push(".rust"), U_RWX)); - assert!(do os::change_dir_locked(&dir.push("A").push("B").push("C")) { + assert!(do change_dir_locked(&dir.push("A").push("B").push("C")) { let p = rust_path(); let cwd = os::getcwd().push(".rust"); let parent = cwd.pop().pop().push(".rust"); diff --git a/src/libstd/os.rs b/src/libstd/os.rs index fb5be0494ef..5981926fce3 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -863,46 +863,6 @@ pub fn change_dir(p: &Path) -> bool { } } -/// Changes the current working directory to the specified -/// path while acquiring a global lock, then calls `action`. -/// If the change is successful, releases the lock and restores the -/// 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 task; - use unstable::finally::Finally; - - unsafe { - // 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 pub fn copy_file(from: &Path, to: &Path) -> bool { return do_copy_file(from, to); diff --git a/src/libstd/unstable/mod.rs b/src/libstd/unstable/mod.rs index c7e88b7e161..e6313a10db1 100644 --- a/src/libstd/unstable/mod.rs +++ b/src/libstd/unstable/mod.rs @@ -79,3 +79,53 @@ extern { fn rust_raw_thread_start(f: &(&fn())) -> *raw_thread; fn rust_raw_thread_join_delete(thread: *raw_thread); } + + +/// Changes the current working directory to the specified +/// path while acquiring a global lock, then calls `action`. +/// If the change is successful, releases the lock and restores the +/// CWD to what it was before, returning true. +/// Returns false if the directory doesn't exist or if the directory change +/// is otherwise unsuccessful. +/// +/// This is used by test cases to avoid cwd races. +/// +/// # Safety Note +/// +/// This uses a pthread mutex so descheduling in the action callback +/// can lead to deadlock. Calling change_dir_locked recursively will +/// also deadlock. +pub fn change_dir_locked(p: &Path, action: &fn()) -> bool { + use os; + use os::change_dir; + use task; + use unstable::finally::Finally; + + unsafe { + // 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(); + } +}