about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-07-22 15:40:36 -0700
committerbors <bors@rust-lang.org>2013-07-22 15:40:36 -0700
commit73921f91a326e51118077ff3fd5c5c6196ff7c3a (patch)
tree23b03c59e5ea158fc0db7095cf94393c0f4546a1 /src/libstd
parent9ed82fbb43804ebc7e06daca5812079630ec8952 (diff)
parent407bffb33e59db9c2ed0c0c5a6533f2ab88743e0 (diff)
downloadrust-73921f91a326e51118077ff3fd5c5c6196ff7c3a.tar.gz
rust-73921f91a326e51118077ff3fd5c5c6196ff7c3a.zip
auto merge of #7883 : brson/rust/rm-std-net, r=graydon
This removes all the code from libextra that depends on libuv. After that it removes three runtime features that existed to support the global uv loop: weak tasks, runtime-global variables, and at_exit handlers.

The networking code doesn't have many users besides servo, so shouldn't have much fallout. The timer code though is useful and will probably break out-of-tree code until the new scheduler lands, but I expect that to be soon.

It also incidentally moves `os::change_dir_locked` to `std::unstable`. This is a function used by test cases to avoid cwd races and in my opinion shouldn't be public (#7870).

Closes #7251 and #7870
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/os.rs28
-rw-r--r--src/libstd/unstable/at_exit.rs100
-rw-r--r--src/libstd/unstable/global.rs281
-rw-r--r--src/libstd/unstable/mod.rs54
-rw-r--r--src/libstd/unstable/weak_task.rs211
5 files changed, 50 insertions, 624 deletions
diff --git a/src/libstd/os.rs b/src/libstd/os.rs
index 4bfd3bbcd3f..5981926fce3 100644
--- a/src/libstd/os.rs
+++ b/src/libstd/os.rs
@@ -863,34 +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.
-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<()>) { }
-
-    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
-            }
-        }
-    }
-}
-
 /// 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/at_exit.rs b/src/libstd/unstable/at_exit.rs
deleted file mode 100644
index 20ddf941a7b..00000000000
--- a/src/libstd/unstable/at_exit.rs
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use cast;
-use libc::size_t;
-use rand::RngUtil;
-use rand;
-use sys;
-use task;
-use vec;
-
-#[cfg(test)] use uint;
-
-/**
-Register a function to be run during runtime shutdown.
-
-After all non-weak tasks have exited, registered exit functions will
-execute, in random order, on the primary scheduler. Each function runs
-in its own unsupervised task.
-*/
-pub fn at_exit(f: ~fn()) {
-    unsafe {
-        let runner: &fn(*ExitFunctions) = exit_runner;
-        let runner_pair: sys::Closure = cast::transmute(runner);
-        let runner_ptr = runner_pair.code;
-        let runner_ptr = cast::transmute(runner_ptr);
-        rustrt::rust_register_exit_function(runner_ptr, ~f);
-    }
-}
-
-// NB: The double pointer indirection here is because ~fn() is a fat
-// pointer and due to FFI problems I am more comfortable making the
-// interface use a normal pointer
-mod rustrt {
-    use libc::c_void;
-
-    extern {
-        pub fn rust_register_exit_function(runner: *c_void, f: ~~fn());
-    }
-}
-
-struct ExitFunctions {
-    // The number of exit functions
-    count: size_t,
-    // The buffer of exit functions
-    start: *~~fn()
-}
-
-fn exit_runner(exit_fns: *ExitFunctions) {
-    let exit_fns = unsafe { &*exit_fns };
-    let count = (*exit_fns).count;
-    let start = (*exit_fns).start;
-
-    // NB: from_buf memcpys from the source, which will
-    // give us ownership of the array of functions
-    let mut exit_fns_vec = unsafe { vec::from_buf(start, count as uint) };
-    // Let's not make any promises about execution order
-    let mut rng = rand::rng();
-    rng.shuffle_mut(exit_fns_vec);
-
-    debug!("running %u exit functions", exit_fns_vec.len());
-
-    while !exit_fns_vec.is_empty() {
-        match exit_fns_vec.pop() {
-            ~f => {
-                let mut task = task::task();
-                task.supervised();
-                task.spawn(f);
-            }
-        }
-    }
-}
-
-#[test]
-fn test_at_exit() {
-    let i = 10;
-    do at_exit {
-        debug!("at_exit1");
-        assert_eq!(i, 10);
-    }
-}
-
-#[test]
-fn test_at_exit_many() {
-    let i = 10;
-    for uint::range(20, 100) |j| {
-        do at_exit {
-            debug!("at_exit2");
-            assert_eq!(i, 10);
-            assert!(j > i);
-        }
-    }
-}
diff --git a/src/libstd/unstable/global.rs b/src/libstd/unstable/global.rs
deleted file mode 100644
index af28879f739..00000000000
--- a/src/libstd/unstable/global.rs
+++ /dev/null
@@ -1,281 +0,0 @@
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-/*!
-Global data
-
-An interface for creating and retrieving values with global
-(per-runtime) scope.
-
-Global values are stored in a map and protected by a single global
-mutex. Operations are provided for accessing and cloning the value
-under the mutex.
-
-Because all globals go through a single mutex, they should be used
-sparingly.  The interface is intended to be used with clonable,
-atomically reference counted synchronization types, like ARCs, in
-which case the value should be cached locally whenever possible to
-avoid hitting the mutex.
-*/
-
-use cast::{transmute};
-use clone::Clone;
-use kinds::Send;
-use libc::{c_void, intptr_t};
-use option::{Option, Some, None};
-use ops::Drop;
-use unstable::sync::{Exclusive, exclusive};
-use unstable::at_exit::at_exit;
-use unstable::intrinsics::atomic_cxchg;
-use hashmap::HashMap;
-use sys::Closure;
-
-#[cfg(test)] use unstable::sync::{UnsafeAtomicRcBox};
-#[cfg(test)] use task::spawn;
-#[cfg(test)] use uint;
-
-pub type GlobalDataKey<'self,T> = &'self fn(v: T);
-
-pub unsafe fn global_data_clone_create<T:Send + Clone>(
-    key: GlobalDataKey<T>, create: &fn() -> ~T) -> T {
-    /*!
-     * Clone a global value or, if it has not been created,
-     * first construct the value then return a clone.
-     *
-     * # Safety note
-     *
-     * Both the clone operation and the constructor are
-     * called while the global lock is held. Recursive
-     * use of the global interface in either of these
-     * operations will result in deadlock.
-     */
-    global_data_clone_create_(key_ptr(key), create)
-}
-
-unsafe fn global_data_clone_create_<T:Send + Clone>(
-    key: uint, create: &fn() -> ~T) -> T {
-
-    let mut clone_value: Option<T> = None;
-    do global_data_modify_(key) |value: Option<~T>| {
-        match value {
-            None => {
-                let value = create();
-                clone_value = Some((*value).clone());
-                Some(value)
-            }
-            Some(value) => {
-                clone_value = Some((*value).clone());
-                Some(value)
-            }
-        }
-    }
-    return clone_value.unwrap();
-}
-
-unsafe fn global_data_modify<T:Send>(
-    key: GlobalDataKey<T>, op: &fn(Option<~T>) -> Option<~T>) {
-
-    global_data_modify_(key_ptr(key), op)
-}
-
-unsafe fn global_data_modify_<T:Send>(
-    key: uint, op: &fn(Option<~T>) -> Option<~T>) {
-
-    let mut old_dtor = None;
-    do get_global_state().with |gs| {
-        let (maybe_new_value, maybe_dtor) = match gs.map.pop(&key) {
-            Some((ptr, dtor)) => {
-                let value: ~T = transmute(ptr);
-                (op(Some(value)), Some(dtor))
-            }
-            None => {
-                (op(None), None)
-            }
-        };
-        match maybe_new_value {
-            Some(value) => {
-                let data: *c_void = transmute(value);
-                let dtor: ~fn() = match maybe_dtor {
-                    Some(dtor) => dtor,
-                    None => {
-                        let dtor: ~fn() = || {
-                            let _destroy_value: ~T = transmute(data);
-                        };
-                        dtor
-                    }
-                };
-                let value = (data, dtor);
-                gs.map.insert(key, value);
-            }
-            None => {
-                match maybe_dtor {
-                    Some(dtor) => old_dtor = Some(dtor),
-                    None => ()
-                }
-            }
-        }
-    }
-}
-
-pub unsafe fn global_data_clone<T:Send + Clone>(
-    key: GlobalDataKey<T>) -> Option<T> {
-    let mut maybe_clone: Option<T> = None;
-    do global_data_modify(key) |current| {
-        match &current {
-            &Some(~ref value) => {
-                maybe_clone = Some(value.clone());
-            }
-            &None => ()
-        }
-        current
-    }
-    return maybe_clone;
-}
-
-// GlobalState is a map from keys to unique pointers and a
-// destructor. Keys are pointers derived from the type of the
-// global value.  There is a single GlobalState instance per runtime.
-struct GlobalState {
-    map: HashMap<uint, (*c_void, ~fn())>
-}
-
-impl Drop for GlobalState {
-    fn drop(&self) {
-        for self.map.each_value |v| {
-            match v {
-                &(_, ref dtor) => (*dtor)()
-            }
-        }
-    }
-}
-
-fn get_global_state() -> Exclusive<GlobalState> {
-
-    static POISON: int = -1;
-
-    // FIXME #4728: Doing atomic_cxchg to initialize the global state
-    // lazily, which wouldn't be necessary with a runtime written
-    // in Rust
-    let global_ptr = unsafe { rust_get_global_data_ptr() };
-
-    if unsafe { *global_ptr } == 0 {
-        // Global state doesn't exist yet, probably
-
-        // The global state object
-        let state = GlobalState {
-            map: HashMap::new()
-        };
-
-        // It's under a reference-counted mutex
-        let state = ~exclusive(state);
-
-        // Convert it to an integer
-        let state_i: int = unsafe {
-            let state_ptr: &Exclusive<GlobalState> = state;
-            transmute(state_ptr)
-        };
-
-        // Swap our structure into the global pointer
-        let prev_i = unsafe { atomic_cxchg(&mut *global_ptr, 0, state_i) };
-
-        // Sanity check that we're not trying to reinitialize after shutdown
-        assert!(prev_i != POISON);
-
-        if prev_i == 0 {
-            // Successfully installed the global pointer
-
-            // Take a handle to return
-            let clone = (*state).clone();
-
-            // Install a runtime exit function to destroy the global object
-            do at_exit {
-                // Poison the global pointer
-                let prev_i = unsafe {
-                    atomic_cxchg(&mut *global_ptr, state_i, POISON)
-                };
-                assert_eq!(prev_i, state_i);
-
-                // Capture the global state object in the at_exit closure
-                // so that it is destroyed at the right time
-                let _capture_global_state = &state;
-            };
-            return clone;
-        } else {
-            // Somebody else initialized the globals first
-            let state: &Exclusive<GlobalState> = unsafe { transmute(prev_i) };
-            return state.clone();
-        }
-    } else {
-        let state: &Exclusive<GlobalState> = unsafe {
-            transmute(*global_ptr)
-        };
-        return state.clone();
-    }
-}
-
-fn key_ptr<T:Send>(key: GlobalDataKey<T>) -> uint {
-    unsafe {
-        let closure: Closure = transmute(key);
-        return transmute(closure.code);
-    }
-}
-
-extern {
-    fn rust_get_global_data_ptr() -> *mut intptr_t;
-}
-
-#[test]
-fn test_clone_rc() {
-    fn key(_v: UnsafeAtomicRcBox<int>) { }
-
-    for uint::range(0, 100) |_| {
-        do spawn {
-            unsafe {
-                let val = do global_data_clone_create(key) {
-                    ~UnsafeAtomicRcBox::new(10)
-                };
-
-                assert!(val.get() == &10);
-            }
-        }
-    }
-}
-
-#[test]
-fn test_modify() {
-    fn key(_v: UnsafeAtomicRcBox<int>) { }
-
-    unsafe {
-        do global_data_modify(key) |v| {
-            match v {
-                None => { Some(~UnsafeAtomicRcBox::new(10)) }
-                _ => fail!()
-            }
-        }
-
-        do global_data_modify(key) |v| {
-            match v {
-                Some(sms) => {
-                    let v = sms.get();
-                    assert!(*v == 10);
-                    None
-                },
-                _ => fail!()
-            }
-        }
-
-        do global_data_modify(key) |v| {
-            match v {
-                None => { Some(~UnsafeAtomicRcBox::new(10)) }
-                _ => fail!()
-            }
-        }
-    }
-}
diff --git a/src/libstd/unstable/mod.rs b/src/libstd/unstable/mod.rs
index 0a46ef619af..d6fd2cbcd1e 100644
--- a/src/libstd/unstable/mod.rs
+++ b/src/libstd/unstable/mod.rs
@@ -16,13 +16,9 @@ use libc;
 use prelude::*;
 use task;
 
-pub mod at_exit;
-
 pub mod dynamic_lib;
 
-pub mod global;
 pub mod finally;
-pub mod weak_task;
 pub mod intrinsics;
 pub mod simd;
 pub mod extfmt;
@@ -80,3 +76,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();
+    }
+}
diff --git a/src/libstd/unstable/weak_task.rs b/src/libstd/unstable/weak_task.rs
deleted file mode 100644
index f5dfa1feb9b..00000000000
--- a/src/libstd/unstable/weak_task.rs
+++ /dev/null
@@ -1,211 +0,0 @@
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-/*!
-Weak tasks
-
-Weak tasks are a runtime feature for building global services that
-do not keep the runtime alive. Normally the runtime exits when all
-tasks exits, but if a task is weak then the runtime may exit while
-it is running, sending a notification to the task that the runtime
-is trying to shut down.
-*/
-
-use cell::Cell;
-use comm::{GenericSmartChan, stream};
-use comm::{Port, Chan, SharedChan, GenericChan, GenericPort};
-use hashmap::HashMap;
-use option::{Some, None};
-use unstable::at_exit::at_exit;
-use unstable::finally::Finally;
-use unstable::global::global_data_clone_create;
-use task::rt::{task_id, get_task_id};
-use task::task;
-
-#[cfg(test)] use task::spawn;
-
-type ShutdownMsg = ();
-
-// FIXME #4729: This could be a PortOne but I've experienced bugginess
-// with oneshot pipes and try_send
-pub unsafe fn weaken_task(f: &fn(Port<ShutdownMsg>)) {
-    let service = global_data_clone_create(global_data_key,
-                                           create_global_service);
-    let (shutdown_port, shutdown_chan) = stream::<ShutdownMsg>();
-    let shutdown_port = Cell::new(shutdown_port);
-    let task = get_task_id();
-    // Expect the weak task service to be alive
-    assert!(service.try_send(RegisterWeakTask(task, shutdown_chan)));
-    rust_dec_kernel_live_count();
-    do (|| {
-        f(shutdown_port.take())
-    }).finally || {
-        rust_inc_kernel_live_count();
-        // Service my have already exited
-        service.send(UnregisterWeakTask(task));
-    }
-}
-
-type WeakTaskService = SharedChan<ServiceMsg>;
-type TaskHandle = task_id;
-
-fn global_data_key(_v: WeakTaskService) { }
-
-enum ServiceMsg {
-    RegisterWeakTask(TaskHandle, Chan<ShutdownMsg>),
-    UnregisterWeakTask(TaskHandle),
-    Shutdown
-}
-
-fn create_global_service() -> ~WeakTaskService {
-
-    debug!("creating global weak task service");
-    let (port, chan) = stream::<ServiceMsg>();
-    let port = Cell::new(port);
-    let chan = SharedChan::new(chan);
-    let chan_clone = chan.clone();
-
-    let mut task = task();
-    task.unlinked();
-    do task.spawn {
-        debug!("running global weak task service");
-        let port = Cell::new(port.take());
-        do (|| {
-            let port = port.take();
-            // The weak task service is itself a weak task
-            debug!("weakening the weak service task");
-            unsafe { rust_dec_kernel_live_count(); }
-            run_weak_task_service(port);
-        }).finally {
-            debug!("unweakening the weak service task");
-            unsafe { rust_inc_kernel_live_count(); }
-        }
-    }
-
-    do at_exit {
-        debug!("shutting down weak task service");
-        chan.send(Shutdown);
-    }
-
-    return ~chan_clone;
-}
-
-fn run_weak_task_service(port: Port<ServiceMsg>) {
-
-    let mut shutdown_map = HashMap::new();
-
-    loop {
-        match port.recv() {
-            RegisterWeakTask(task, shutdown_chan) => {
-                let previously_unregistered =
-                    shutdown_map.insert(task, shutdown_chan);
-                assert!(previously_unregistered);
-            }
-            UnregisterWeakTask(task) => {
-                match shutdown_map.pop(&task) {
-                    Some(shutdown_chan) => {
-                        // Oneshot pipes must send, even though
-                        // nobody will receive this
-                        shutdown_chan.send(());
-                    }
-                    None => fail!()
-                }
-            }
-            Shutdown => break
-        }
-    }
-
-    for shutdown_map.consume().advance |(_, shutdown_chan)| {
-        // Weak task may have already exited
-        shutdown_chan.send(());
-    }
-}
-
-extern {
-    unsafe fn rust_inc_kernel_live_count();
-    unsafe fn rust_dec_kernel_live_count();
-}
-
-#[test]
-fn test_simple() {
-    let (port, chan) = stream();
-    do spawn {
-        unsafe {
-            do weaken_task |_signal| {
-            }
-        }
-        chan.send(());
-    }
-    port.recv();
-}
-
-#[test]
-fn test_weak_weak() {
-    let (port, chan) = stream();
-    do spawn {
-        unsafe {
-            do weaken_task |_signal| {
-            }
-            do weaken_task |_signal| {
-            }
-        }
-        chan.send(());
-    }
-    port.recv();
-}
-
-#[test]
-fn test_wait_for_signal() {
-    do spawn {
-        unsafe {
-            do weaken_task |signal| {
-                signal.recv();
-            }
-        }
-    }
-}
-
-#[test]
-fn test_wait_for_signal_many() {
-    use uint;
-    for uint::range(0, 100) |_| {
-        do spawn {
-            unsafe {
-                do weaken_task |signal| {
-                    signal.recv();
-                }
-            }
-        }
-    }
-}
-
-#[test]
-fn test_select_stream_and_oneshot() {
-    use comm::select2i;
-    use either::{Left, Right};
-
-    let (port, chan) = stream();
-    let port = Cell::new(port);
-    let (waitport, waitchan) = stream();
-    do spawn {
-        unsafe {
-            do weaken_task |mut signal| {
-                let mut port = port.take();
-                match select2i(&mut port, &mut signal) {
-                    Left(*) => (),
-                    Right(*) => fail!()
-                }
-            }
-        }
-        waitchan.send(());
-    }
-    chan.send(());
-    waitport.recv();
-}