std: Move change_dir_locked to unstable. #7870

This commit is contained in:
Brian Anderson 2013-07-17 18:59:29 -07:00
parent 4beda4e582
commit 6174f9a4d9
4 changed files with 57 additions and 43 deletions

View File

@ -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));

View File

@ -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");

View File

@ -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);

View File

@ -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();
}
}