about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBrian Anderson <banderson@mozilla.com>2013-02-28 15:20:40 -0800
committerBrian Anderson <banderson@mozilla.com>2013-02-28 15:20:40 -0800
commit78d5091a4f09f0f7c613437e502db95b63a0c538 (patch)
treefdd04b3260b6e2a4472c0fafbf28378d67d9140b
parentb01d2babaf29b2798fa624676a1c9fcbcbc1e30a (diff)
downloadrust-78d5091a4f09f0f7c613437e502db95b63a0c538.tar.gz
rust-78d5091a4f09f0f7c613437e502db95b63a0c538.zip
core: Remove unwrap_shared_mutable_state. #4436
-rw-r--r--src/libcore/private.rs190
-rw-r--r--src/libstd/arc.rs66
2 files changed, 5 insertions, 251 deletions
diff --git a/src/libcore/private.rs b/src/libcore/private.rs
index e4fab18966c..5601964685e 100644
--- a/src/libcore/private.rs
+++ b/src/libcore/private.rs
@@ -107,20 +107,9 @@ fn compare_and_swap(address: &mut int, oldval: int, newval: int) -> bool {
  * Shared state & exclusive ARC
  ****************************************************************************/
 
-struct UnwrapProtoInner {
-    contents: Option<(comm::ChanOne<()>,  comm::PortOne<bool>)>,
-}
-
-// An unwrapper uses this protocol to communicate with the "other" task that
-// drops the last refcount on an arc. Unfortunately this can't be a proper
-// pipe protocol because the unwrapper has to access both stages at once.
-type UnwrapProto = ~UnwrapProtoInner;
-
 struct ArcData<T> {
     mut count:     libc::intptr_t,
-    mut unwrapper: int, // either a UnwrapProto or 0
-    // FIXME(#3224) should be able to make this non-option to save memory, and
-    // in unwrap() use "let ~ArcData { data: result, _ } = thing" to unwrap it
+    // FIXME(#3224) should be able to make this non-option to save memory
     mut data:      Option<T>,
 }
 
@@ -131,37 +120,13 @@ struct ArcDestruct<T> {
 impl<T> Drop for ArcDestruct<T>{
     fn finalize(&self) {
         unsafe {
-            if self.data.is_null() {
-                return; // Happens when destructing an unwrapper's handle.
-            }
             do task::unkillable {
                 let data: ~ArcData<T> = cast::reinterpret_cast(&self.data);
                 let new_count =
                     intrinsics::atomic_xsub(&mut data.count, 1) - 1;
                 assert new_count >= 0;
                 if new_count == 0 {
-                    // Were we really last, or should we hand off to an
-                    // unwrapper? It's safe to not xchg because the unwrapper
-                    // will set the unwrap lock *before* dropping his/her
-                    // reference. In effect, being here means we're the only
-                    // *awake* task with the data.
-                    if data.unwrapper != 0 {
-                        let mut p: UnwrapProto =
-                            cast::reinterpret_cast(&data.unwrapper);
-                        let (message, response) =
-                            option::swap_unwrap(&mut p.contents);
-                        // Send 'ready' and wait for a response.
-                        comm::send_one(message, ());
-                        // Unkillable wait. Message guaranteed to come.
-                        if comm::recv_one(response) {
-                            // Other task got the data.
-                            cast::forget(data);
-                        } else {
-                            // Other task was killed. drop glue takes over.
-                        }
-                    } else {
-                        // drop glue takes over.
-                    }
+                    // drop glue takes over.
                 } else {
                     cast::forget(data);
                 }
@@ -176,79 +141,6 @@ fn ArcDestruct<T>(data: *libc::c_void) -> ArcDestruct<T> {
     }
 }
 
-pub unsafe fn unwrap_shared_mutable_state<T:Owned>(rc: SharedMutableState<T>)
-        -> T {
-    struct DeathThroes<T> {
-        mut ptr:      Option<~ArcData<T>>,
-        mut response: Option<comm::ChanOne<bool>>,
-    }
-
-    impl<T> Drop for DeathThroes<T>{
-        fn finalize(&self) {
-            unsafe {
-                let response = option::swap_unwrap(&mut self.response);
-                // In case we get killed early, we need to tell the person who
-                // tried to wake us whether they should hand-off the data to
-                // us.
-                if task::failing() {
-                    comm::send_one(response, false);
-                    // Either this swap_unwrap or the one below (at "Got
-                    // here") ought to run.
-                    cast::forget(option::swap_unwrap(&mut self.ptr));
-                } else {
-                    assert self.ptr.is_none();
-                    comm::send_one(response, true);
-                }
-            }
-        }
-    }
-
-    do task::unkillable {
-        let ptr: ~ArcData<T> = cast::reinterpret_cast(&rc.data);
-        let (p1,c1) = comm::oneshot(); // ()
-        let (p2,c2) = comm::oneshot(); // bool
-        let mut server: UnwrapProto = ~UnwrapProtoInner {
-            contents: Some((c1,p2))
-        };
-        let serverp: int = cast::transmute(server);
-        // Try to put our server end in the unwrapper slot.
-        if compare_and_swap(&mut ptr.unwrapper, 0, serverp) {
-            // Got in. Step 0: Tell destructor not to run. We are now it.
-            rc.data = ptr::null();
-            // Step 1 - drop our own reference.
-            let new_count = intrinsics::atomic_xsub(&mut ptr.count, 1) - 1;
-            //assert new_count >= 0;
-            if new_count == 0 {
-                // We were the last owner. Can unwrap immediately.
-                // Also we have to free the server endpoints.
-                let _server: UnwrapProto = cast::transmute(serverp);
-                option::swap_unwrap(&mut ptr.data)
-                // drop glue takes over.
-            } else {
-                // The *next* person who sees the refcount hit 0 will wake us.
-                let end_result =
-                    DeathThroes { ptr: Some(ptr),
-                                  response: Some(c2) };
-                let mut p1 = Some(p1); // argh
-                do task::rekillable {
-                    comm::recv_one(option::swap_unwrap(&mut p1));
-                }
-                // Got here. Back in the 'unkillable' without getting killed.
-                // Recover ownership of ptr, then take the data out.
-                let ptr = option::swap_unwrap(&mut end_result.ptr);
-                option::swap_unwrap(&mut ptr.data)
-                // drop glue takes over.
-            }
-        } else {
-            // Somebody else was trying to unwrap. Avoid guaranteed deadlock.
-            cast::forget(ptr);
-            // Also we have to free the (rejected) server endpoints.
-            let _server: UnwrapProto = cast::transmute(serverp);
-            fail!(~"Another task is already unwrapping this ARC!");
-        }
-    }
-}
-
 /**
  * COMPLETELY UNSAFE. Used as a primitive for the safe versions in std::arc.
  *
@@ -259,7 +151,7 @@ pub type SharedMutableState<T> = ArcDestruct<T>;
 
 pub unsafe fn shared_mutable_state<T:Owned>(data: T) ->
         SharedMutableState<T> {
-    let data = ~ArcData { count: 1, unwrapper: 0, data: Some(data) };
+    let data = ~ArcData { count: 1, data: Some(data) };
     unsafe {
         let ptr = cast::transmute(data);
         ArcDestruct(ptr)
@@ -413,14 +305,6 @@ impl<T:Owned> Exclusive<T> {
     }
 }
 
-// FIXME(#3724) make this a by-move method on the exclusive
-pub fn unwrap_exclusive<T:Owned>(arc: Exclusive<T>) -> T {
-    let Exclusive { x: x } = arc;
-    let inner = unsafe { unwrap_shared_mutable_state(x) };
-    let ExData { data: data, _ } = inner;
-    data
-}
-
 #[cfg(test)]
 pub mod tests {
     use core::option::{None, Some};
@@ -428,7 +312,7 @@ pub mod tests {
     use cell::Cell;
     use comm;
     use option;
-    use private::{exclusive, unwrap_exclusive};
+    use private::exclusive;
     use result;
     use task;
     use uint;
@@ -479,70 +363,4 @@ pub mod tests {
             assert *one == 1;
         }
     }
-
-    #[test]
-    pub fn exclusive_unwrap_basic() {
-        let x = exclusive(~~"hello");
-        assert unwrap_exclusive(x) == ~~"hello";
-    }
-
-    #[test]
-    pub fn exclusive_unwrap_contended() {
-        let x = exclusive(~~"hello");
-        let x2 = Cell(x.clone());
-        do task::spawn {
-            let x2 = x2.take();
-            do x2.with |_hello| { }
-            task::yield();
-        }
-        assert unwrap_exclusive(x) == ~~"hello";
-
-        // Now try the same thing, but with the child task blocking.
-        let x = exclusive(~~"hello");
-        let x2 = Cell(x.clone());
-        let mut res = None;
-        do task::task().future_result(|+r| res = Some(r)).spawn {
-            let x2 = x2.take();
-            assert unwrap_exclusive(x2) == ~~"hello";
-        }
-        // Have to get rid of our reference before blocking.
-        { let _x = x; } // FIXME(#3161) util::ignore doesn't work here
-        let res = option::swap_unwrap(&mut res);
-        res.recv();
-    }
-
-    #[test] #[should_fail] #[ignore(cfg(windows))]
-    pub fn exclusive_unwrap_conflict() {
-        let x = exclusive(~~"hello");
-        let x2 = Cell(x.clone());
-        let mut res = None;
-        do task::task().future_result(|+r| res = Some(r)).spawn {
-            let x2 = x2.take();
-            assert unwrap_exclusive(x2) == ~~"hello";
-        }
-        assert unwrap_exclusive(x) == ~~"hello";
-        let res = option::swap_unwrap(&mut res);
-        // See #4689 for why this can't be just "res.recv()".
-        assert res.recv() == task::Success;
-    }
-
-    #[test] #[ignore(cfg(windows))]
-    pub fn exclusive_unwrap_deadlock() {
-        // This is not guaranteed to get to the deadlock before being killed,
-        // but it will show up sometimes, and if the deadlock were not there,
-        // the test would nondeterministically fail.
-        let result = do task::try {
-            // a task that has two references to the same exclusive will
-            // deadlock when it unwraps. nothing to be done about that.
-            let x = exclusive(~~"hello");
-            let x2 = x.clone();
-            do task::spawn {
-                for 10.times { task::yield(); } // try to let the unwrapper go
-                fail!(); // punt it awake from its deadlock
-            }
-            let _z = unwrap_exclusive(x);
-            do x2.with |_hello| { }
-        };
-        assert result.is_err();
-    }
 }
diff --git a/src/libstd/arc.rs b/src/libstd/arc.rs
index f258e649122..264ea9d0278 100644
--- a/src/libstd/arc.rs
+++ b/src/libstd/arc.rs
@@ -21,7 +21,7 @@ use core::cell::Cell;
 use core::pipes;
 use core::prelude::*;
 use core::private::{SharedMutableState, shared_mutable_state};
-use core::private::{clone_shared_mutable_state, unwrap_shared_mutable_state};
+use core::private::{clone_shared_mutable_state};
 use core::private::{get_shared_mutable_state, get_shared_immutable_state};
 use core::ptr;
 use core::task;
@@ -104,20 +104,6 @@ pub fn clone<T:Const + Owned>(rc: &ARC<T>) -> ARC<T> {
     ARC { x: unsafe { clone_shared_mutable_state(&rc.x) } }
 }
 
-/**
- * Retrieve the data back out of the ARC. This function blocks until the
- * reference given to it is the last existing one, and then unwrap the data
- * instead of destroying it.
- *
- * If multiple tasks call unwrap, all but the first will fail. Do not call
- * unwrap from a task that holds another reference to the same ARC; it is
- * guaranteed to deadlock.
- */
-pub fn unwrap<T:Const + Owned>(rc: ARC<T>) -> T {
-    let ARC { x: x } = rc;
-    unsafe { unwrap_shared_mutable_state(x) }
-}
-
 impl<T:Const + Owned> Clone for ARC<T> {
     fn clone(&self) -> ARC<T> {
         clone(self)
@@ -213,23 +199,6 @@ impl<T:Owned> &MutexARC<T> {
     }
 }
 
-/**
- * Retrieves the data, blocking until all other references are dropped,
- * exactly as arc::unwrap.
- *
- * Will additionally fail if another task has failed while accessing the arc.
- */
-// FIXME(#3724) make this a by-move method on the arc
-pub fn unwrap_mutex_arc<T:Owned>(arc: MutexARC<T>) -> T {
-    let MutexARC { x: x } = arc;
-    let inner = unsafe { unwrap_shared_mutable_state(x) };
-    let MutexARCInner { failed: failed, data: data, _ } = inner;
-    if failed {
-        fail!(~"Can't unwrap poisoned MutexARC - another task failed inside!")
-    }
-    data
-}
-
 // Common code for {mutex.access,rwlock.write}{,_cond}.
 #[inline(always)]
 #[doc(hidden)]
@@ -411,24 +380,6 @@ impl<T:Const + Owned> &RWARC<T> {
     }
 }
 
-/**
- * Retrieves the data, blocking until all other references are dropped,
- * exactly as arc::unwrap.
- *
- * Will additionally fail if another task has failed while accessing the arc
- * in write mode.
- */
-// FIXME(#3724) make this a by-move method on the arc
-pub fn unwrap_rw_arc<T:Const + Owned>(arc: RWARC<T>) -> T {
-    let RWARC { x: x, _ } = arc;
-    let inner = unsafe { unwrap_shared_mutable_state(x) };
-    let RWARCInner { failed: failed, data: data, _ } = inner;
-    if failed {
-        fail!(~"Can't unwrap poisoned RWARC - another task failed inside!")
-    }
-    data
-}
-
 // Borrowck rightly complains about immutably aliasing the rwlock in order to
 // lock it. This wraps the unsafety, with the justification that the 'lock'
 // field is never overwritten; only 'failed' and 'data'.
@@ -585,21 +536,6 @@ mod tests {
         }
     }
     #[test] #[should_fail] #[ignore(cfg(windows))]
-    pub fn test_mutex_arc_unwrap_poison() {
-        let arc = MutexARC(1);
-        let arc2 = ~(&arc).clone();
-        let (p, c) = comm::stream();
-        do task::spawn || {
-            do arc2.access |one| {
-                c.send(());
-                assert *one == 2;
-            }
-        }
-        let _ = p.recv();
-        let one = unwrap_mutex_arc(arc);
-        assert one == 1;
-    }
-    #[test] #[should_fail] #[ignore(cfg(windows))]
     pub fn test_rw_arc_poison_wr() {
         let arc = ~RWARC(1);
         let arc2 = ~arc.clone();