]> git.lizzy.rs Git - rust.git/commitdiff
move concurrent stuff from libextra to libsync
authorJeremyLetang <letang.jeremy@gmail.com>
Thu, 30 Jan 2014 20:04:47 +0000 (15:04 -0500)
committerJeremyLetang <letang.jeremy@gmail.com>
Wed, 5 Feb 2014 16:56:04 +0000 (11:56 -0500)
56 files changed:
mk/crates.mk
src/doc/guide-tasks.md
src/doc/index.md
src/etc/licenseck.py
src/libextra/arc.rs [deleted file]
src/libextra/comm.rs [deleted file]
src/libextra/future.rs [deleted file]
src/libextra/lib.rs
src/libextra/sync/mod.rs [deleted file]
src/libextra/sync/mpsc_intrusive.rs [deleted file]
src/libextra/sync/mutex.rs [deleted file]
src/libextra/sync/one.rs [deleted file]
src/libextra/task_pool.rs [deleted file]
src/libextra/workcache.rs
src/librustc/back/link.rs
src/librustc/lib.rs
src/librustc/middle/trans/base.rs
src/librustdoc/html/render.rs
src/librustdoc/lib.rs
src/libsync/arc.rs [new file with mode: 0644]
src/libsync/comm.rs [new file with mode: 0644]
src/libsync/future.rs [new file with mode: 0644]
src/libsync/lib.rs [new file with mode: 0644]
src/libsync/sync/mod.rs [new file with mode: 0644]
src/libsync/sync/mpsc_intrusive.rs [new file with mode: 0644]
src/libsync/sync/mutex.rs [new file with mode: 0644]
src/libsync/sync/one.rs [new file with mode: 0644]
src/libsync/task_pool.rs [new file with mode: 0644]
src/test/bench/msgsend-ring-mutex-arcs.rs
src/test/bench/msgsend-ring-rw-arcs.rs
src/test/bench/shootout-binarytrees.rs
src/test/bench/shootout-spectralnorm.rs
src/test/compile-fail/arc-cant-nest-rw-arc-3177.rs
src/test/compile-fail/arc-rw-cond-shouldnt-escape.rs
src/test/compile-fail/arc-rw-read-mode-shouldnt-escape.rs
src/test/compile-fail/arc-rw-state-shouldnt-escape.rs
src/test/compile-fail/arc-rw-write-mode-cond-shouldnt-escape.rs
src/test/compile-fail/arc-rw-write-mode-shouldnt-escape.rs
src/test/compile-fail/functional-struct-update-noncopyable.rs
src/test/compile-fail/future_not_copyable.rs
src/test/compile-fail/mutex-arc-nested.rs
src/test/compile-fail/no-capture-arc.rs
src/test/compile-fail/no-reuse-move-arc.rs
src/test/compile-fail/once-cant-call-twice-on-heap.rs
src/test/compile-fail/once-cant-call-twice-on-stack.rs
src/test/compile-fail/once-cant-move-out-of-non-once-on-stack.rs
src/test/compile-fail/sync-cond-shouldnt-escape.rs
src/test/compile-fail/sync-rwlock-cond-shouldnt-escape.rs
src/test/compile-fail/sync-rwlock-read-mode-shouldnt-escape.rs
src/test/compile-fail/sync-rwlock-write-mode-cond-shouldnt-escape.rs
src/test/compile-fail/sync-rwlock-write-mode-shouldnt-escape.rs
src/test/run-fail/issue-2444.rs
src/test/run-pass/bind-by-move.rs
src/test/run-pass/once-move-out-on-heap.rs
src/test/run-pass/once-move-out-on-stack.rs
src/test/run-pass/trait-bounds-in-arc.rs

index e02e4fb8706e822d4b7ee0981223a7f7c29bccc6..dd94d268becb5604c531887a7d2f98a221881ed2 100644 (file)
 # automatically generated for all stage/host/target combinations.
 ################################################################################
 
-TARGET_CRATES := std extra green rustuv native flate arena glob term semver uuid
+TARGET_CRATES := std extra green rustuv native flate arena glob term semver uuid sync
 HOST_CRATES := syntax rustc rustdoc
 CRATES := $(TARGET_CRATES) $(HOST_CRATES)
 TOOLS := compiletest rustdoc rustc
 
 DEPS_std := native:rustrt
-DEPS_extra := std term
+DEPS_extra := std term sync
 DEPS_green := std
 DEPS_rustuv := std native:uv native:uv_support
 DEPS_native := std
 DEPS_syntax := std extra term
-DEPS_rustc := syntax native:rustllvm flate arena
-DEPS_rustdoc := rustc native:sundown
+DEPS_rustc := syntax native:rustllvm flate arena sync
+DEPS_rustdoc := rustc native:sundown sync
 DEPS_flate := std native:miniz
 DEPS_arena := std extra
 DEPS_glob := std
 DEPS_term := std
 DEPS_semver := std
 DEPS_uuid := std extra
+DEPS_sync := std
 
 TOOL_DEPS_compiletest := extra green rustuv
 TOOL_DEPS_rustdoc := rustdoc green rustuv
index c3bdbe3a3ee8992126abee557864b10b84052caa..387f481025df71e76f6ae490e3aed9ca6ed9b10a 100644 (file)
@@ -39,7 +39,7 @@ data through the global _exchange heap_.
 
 While Rust's type system provides the building blocks needed for safe
 and efficient tasks, all of the task functionality itself is implemented
-in the standard and extra libraries, which are still under development
+in the standard and sync libraries, which are still under development
 and do not always present a consistent or complete interface.
 
 For your reference, these are the standard modules involved in Rust
@@ -47,18 +47,43 @@ concurrency at this writing:
 
 * [`std::task`] - All code relating to tasks and task scheduling,
 * [`std::comm`] - The message passing interface,
-* [`extra::comm`] - Additional messaging types based on `std::comm`,
-* [`extra::sync`] - More exotic synchronization tools, including locks,
-* [`extra::arc`] - The Arc (atomically reference counted) type,
-  for safely sharing immutable data,
-* [`extra::future`] - A type representing values that may be computed concurrently and retrieved at a later time.
+* [`sync::DuplexStream`] - An extension of `pipes::stream` that allows both sending and receiving,
+* [`sync::SyncChan`] - An extension of `pipes::stream` that provides synchronous message sending,
+* [`sync::SyncPort`] - An extension of `pipes::stream` that acknowledges each message received,
+* [`sync::rendezvous`] - Creates a stream whose channel, upon sending a message, blocks until the 
+    message is received.
+* [`sync::Arc`] - The Arc (atomically reference counted) type, for safely sharing immutable data,
+* [`sync::RWArc`] - A dual-mode Arc protected by a reader-writer lock,
+* [`sync::MutexArc`] - An Arc with mutable data protected by a blocking mutex,
+* [`sync::Semaphore`] - A counting, blocking, bounded-waiting semaphore,
+* [`sync::Mutex`] - A blocking, bounded-waiting, mutual exclusion lock with an associated 
+    FIFO condition variable,
+* [`sync::RWLock`] - A blocking, no-starvation, reader-writer lock with an associated condvar,
+* [`sync::Barrier`] - A barrier enables multiple tasks to synchronize the beginning
+    of some computation,
+* [`sync::TaskPool`] - A task pool abstraction,
+* [`sync::Future`] - A type encapsulating the result of a computation which may not be complete,
+* [`sync::one`] - A "once initialization" primitive
+* [`sync::mutex`] - A proper mutex implementation regardless of the "flavor of task" which is
+    acquiring the lock.
 
 [`std::task`]: std/task/index.html
 [`std::comm`]: std/comm/index.html
-[`extra::comm`]: extra/comm/index.html
-[`extra::sync`]: extra/sync/index.html
-[`extra::arc`]: extra/arc/index.html
-[`extra::future`]: extra/future/index.html
+[`sync::DuplexStream`]: sync/struct.DuplexStream.html
+[`sync::SyncChan`]: sync/struct.SyncChan.html
+[`sync::SyncPort`]: sync/struct.SyncPort.html
+[`sync::rendezvous`]: sync/fn.rendezvous.html
+[`sync::Arc`]: sync/struct.Arc.html
+[`sync::RWArc`]: sync/struct.RWArc.html
+[`sync::MutexArc`]: sync/struct.MutexArc.html
+[`sync::Semaphore`]: sync/struct.Semaphore.html
+[`sync::Mutex`]: sync/struct.Mutex.html
+[`sync::RWLock`]: sync/struct.RWLock.html
+[`sync::Barrier`]: sync/struct.Barrier.html
+[`sync::TaskPool`]: sync/struct.TaskPool.html
+[`sync::Future`]: sync/struct.Future.html
+[`sync::one`]: sync/one/index.html
+[`sync::mutex`]: sync/mutex/index.html
 
 # Basics
 
@@ -254,21 +279,25 @@ let result = ports.iter().fold(0, |accum, port| accum + port.recv() );
 ~~~
 
 ## Backgrounding computations: Futures
-With `extra::future`, rust has a mechanism for requesting a computation and getting the result
+With `sync::Future`, rust has a mechanism for requesting a computation and getting the result
 later.
 
 The basic example below illustrates this.
 
 ~~~
+# extern mod sync;
+
+# fn main() {
 # fn make_a_sandwich() {};
 fn fib(n: u64) -> u64 {
     // lengthy computation returning an uint
     12586269025
 }
 
-let mut delayed_fib = extra::future::Future::spawn(proc() fib(50));
+let mut delayed_fib = sync::Future::spawn(proc() fib(50));
 make_a_sandwich();
 println!("fib(50) = {:?}", delayed_fib.get())
+# }
 ~~~
 
 The call to `future::spawn` returns immediately a `future` object regardless of how long it
@@ -281,6 +310,7 @@ Here is another example showing how futures allow you to background computations
 be distributed on the available cores.
 
 ~~~
+# extern mod sync;
 # use std::vec;
 fn partial_sum(start: uint) -> f64 {
     let mut local_sum = 0f64;
@@ -291,7 +321,7 @@ fn partial_sum(start: uint) -> f64 {
 }
 
 fn main() {
-    let mut futures = vec::from_fn(1000, |ind| extra::future::Future::spawn( proc() { partial_sum(ind) }));
+    let mut futures = vec::from_fn(1000, |ind| sync::Future::spawn( proc() { partial_sum(ind) }));
 
     let mut final_res = 0f64;
     for ft in futures.mut_iter()  {
@@ -309,16 +339,17 @@ add up to a significant amount of wasted memory and would require copying the sa
 necessary.
 
 To tackle this issue, one can use an Atomically Reference Counted wrapper (`Arc`) as implemented in
-the `extra` library of Rust. With an Arc, the data will no longer be copied for each task. The Arc
+the `sync` library of Rust. With an Arc, the data will no longer be copied for each task. The Arc
 acts as a reference to the shared data and only this reference is shared and cloned.
 
 Here is a small example showing how to use Arcs. We wish to run concurrently several computations on
 a single large vector of floats. Each task needs the full vector to perform its duty.
 
 ~~~
+# extern mod sync;
 # use std::vec;
 # use std::rand;
-use extra::arc::Arc;
+use sync::Arc;
 
 fn pnorm(nums: &~[f64], p: uint) -> f64 {
     nums.iter().fold(0.0, |a,b| a+(*b).powf(&(p as f64)) ).powf(&(1.0 / (p as f64)))
@@ -348,23 +379,29 @@ at the power given as argument and takes the inverse power of this value). The A
 created by the line
 
 ~~~
-# use extra::arc::Arc;
+# extern mod sync;
+# use sync::Arc;
 # use std::vec;
 # use std::rand;
+# fn main() {
 # let numbers = vec::from_fn(1000000, |_| rand::random::<f64>());
 let numbers_arc=Arc::new(numbers);
+# }
 ~~~
 
 and a clone of it is sent to each task
 
 ~~~
-# use extra::arc::Arc;
+# extern mod sync;
+# use sync::Arc;
 # use std::vec;
 # use std::rand;
+# fn main() {
 # let numbers=vec::from_fn(1000000, |_| rand::random::<f64>());
 # let numbers_arc = Arc::new(numbers);
 # let (port, chan)  = Chan::new();
 chan.send(numbers_arc.clone());
+# }
 ~~~
 
 copying only the wrapper and not its contents.
@@ -372,15 +409,18 @@ copying only the wrapper and not its contents.
 Each task recovers the underlying data by
 
 ~~~
-# use extra::arc::Arc;
+# extern mod sync;
+# use sync::Arc;
 # use std::vec;
 # use std::rand;
+# fn main() {
 # let numbers=vec::from_fn(1000000, |_| rand::random::<f64>());
 # let numbers_arc=Arc::new(numbers);
 # let (port, chan)  = Chan::new();
 # chan.send(numbers_arc.clone());
 # let local_arc : Arc<~[f64]> = port.recv();
 let task_numbers = local_arc.get();
+# }
 ~~~
 
 and can use it as if it were local.
@@ -450,7 +490,7 @@ proceed).
 
 A very common thing to do is to spawn a child task where the parent
 and child both need to exchange messages with each other. The
-function `extra::comm::DuplexStream()` supports this pattern.  We'll
+function `sync::comm::DuplexStream()` supports this pattern.  We'll
 look briefly at how to use it.
 
 To see how `DuplexStream()` works, we will create a child task
@@ -458,17 +498,19 @@ that repeatedly receives a `uint` message, converts it to a string, and sends
 the string in response.  The child terminates when it receives `0`.
 Here is the function that implements the child task:
 
-~~~{.ignore .linked-failure}
-# use extra::comm::DuplexStream;
-# use std::uint;
-fn stringifier(channel: &DuplexStream<~str, uint>) {
-    let mut value: uint;
-    loop {
-        value = channel.recv();
-        channel.send(uint::to_str(value));
-        if value == 0 { break; }
+~~~
+# extern mod sync;
+# fn main() {
+# use sync::DuplexStream;
+    fn stringifier(channel: &DuplexStream<~str, uint>) {
+        let mut value: uint;
+        loop {
+            value = channel.recv();
+            channel.send(value.to_str());
+            if value == 0 { break; }
+        }
     }
-}
+}
 ~~~~
 
 The implementation of `DuplexStream` supports both sending and
@@ -481,15 +523,15 @@ response itself is simply the stringified version of the received value,
 
 Here is the code for the parent task:
 
-~~~{.ignore .linked-failure}
+~~~
+# extern mod sync;
 # use std::task::spawn;
-# use std::uint;
-# use extra::comm::DuplexStream;
+# use sync::DuplexStream;
 # fn stringifier(channel: &DuplexStream<~str, uint>) {
 #     let mut value: uint;
 #     loop {
 #         value = channel.recv();
-#         channel.send(uint::to_str(value));
+#         channel.send(value.to_str());
 #         if value == 0u { break; }
 #     }
 # }
index 9915d67bfcad330ded7eec4a6fbc38a7f7106b15..5aa92c9fec4dbb5a4671cf09a1abddac5cd7abf4 100644 (file)
@@ -43,6 +43,7 @@ li {list-style-type: none; }
 * [The `semver` version collation library](semver/index.html)
 * [The `term` terminal-handling library](term/index.html)
 * [The UUID library](uuid/index.html)
+* [The `sync` library for concurrency-enabled mechanisms and primitives](sync/index.html)
 
 # Tooling
 
index afbf34d07535d06bafcd9d6f5f11c4ae2db7e05c..e214a40e3d134640fc0b4255b6dd4bfd47d64d41 100644 (file)
@@ -41,7 +41,7 @@ exceptions = [
     "libstd/sync/mpsc_queue.rs", # BSD
     "libstd/sync/spsc_queue.rs", # BSD
     "libstd/sync/mpmc_bounded_queue.rs", # BSD
-    "libextra/sync/mpsc_intrusive.rs", # BSD
+    "libsync/sync/mpsc_intrusive.rs", # BSD
 ]
 
 def check_license(name, contents):
diff --git a/src/libextra/arc.rs b/src/libextra/arc.rs
deleted file mode 100644 (file)
index 7f8d640..0000000
+++ /dev/null
@@ -1,1074 +0,0 @@
-// Copyright 2012-2014 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.
-
-/*!
- * Concurrency-enabled mechanisms for sharing mutable and/or immutable state
- * between tasks.
- *
- * # Example
- *
- * In this example, a large vector of floats is shared between several tasks.
- * With simple pipes, without Arc, a copy would have to be made for each task.
- *
- * ```rust
- * use extra::arc::Arc;
- * use std::{rand, vec};
- *
- * let numbers = vec::from_fn(100, |i| (i as f32) * rand::random());
- * let shared_numbers = Arc::new(numbers);
- *
- *   for _ in range(0, 10) {
- *       let (port, chan) = Chan::new();
- *       chan.send(shared_numbers.clone());
- *
- *       spawn(proc() {
- *           let shared_numbers = port.recv();
- *           let local_numbers = shared_numbers.get();
- *
- *           // Work with the local numbers
- *       });
- *   }
- * ```
- */
-
-#[allow(missing_doc)];
-
-
-use sync;
-use sync::{Mutex, RWLock};
-
-use std::cast;
-use std::kinds::marker;
-use std::sync::arc::UnsafeArc;
-use std::task;
-
-/// As sync::condvar, a mechanism for unlock-and-descheduling and signaling.
-pub struct Condvar<'a> {
-    priv is_mutex: bool,
-    priv failed: &'a bool,
-    priv cond: &'a sync::Condvar<'a>
-}
-
-impl<'a> Condvar<'a> {
-    /// Atomically exit the associated Arc and block until a signal is sent.
-    #[inline]
-    pub fn wait(&self) { self.wait_on(0) }
-
-    /**
-     * Atomically exit the associated Arc and block on a specified condvar
-     * until a signal is sent on that same condvar (as sync::cond.wait_on).
-     *
-     * wait() is equivalent to wait_on(0).
-     */
-    #[inline]
-    pub fn wait_on(&self, condvar_id: uint) {
-        assert!(!*self.failed);
-        self.cond.wait_on(condvar_id);
-        // This is why we need to wrap sync::condvar.
-        check_poison(self.is_mutex, *self.failed);
-    }
-
-    /// Wake up a blocked task. Returns false if there was no blocked task.
-    #[inline]
-    pub fn signal(&self) -> bool { self.signal_on(0) }
-
-    /**
-     * Wake up a blocked task on a specified condvar (as
-     * sync::cond.signal_on). Returns false if there was no blocked task.
-     */
-    #[inline]
-    pub fn signal_on(&self, condvar_id: uint) -> bool {
-        assert!(!*self.failed);
-        self.cond.signal_on(condvar_id)
-    }
-
-    /// Wake up all blocked tasks. Returns the number of tasks woken.
-    #[inline]
-    pub fn broadcast(&self) -> uint { self.broadcast_on(0) }
-
-    /**
-     * Wake up all blocked tasks on a specified condvar (as
-     * sync::cond.broadcast_on). Returns the number of tasks woken.
-     */
-    #[inline]
-    pub fn broadcast_on(&self, condvar_id: uint) -> uint {
-        assert!(!*self.failed);
-        self.cond.broadcast_on(condvar_id)
-    }
-}
-
-/****************************************************************************
- * Immutable Arc
- ****************************************************************************/
-
-/// An atomically reference counted wrapper for shared immutable state.
-pub struct Arc<T> { priv x: UnsafeArc<T> }
-
-
-/**
- * Access the underlying data in an atomically reference counted
- * wrapper.
- */
-impl<T:Freeze+Send> Arc<T> {
-    /// Create an atomically reference counted wrapper.
-    #[inline]
-    pub fn new(data: T) -> Arc<T> {
-        Arc { x: UnsafeArc::new(data) }
-    }
-
-    #[inline]
-    pub fn get<'a>(&'a self) -> &'a T {
-        unsafe { &*self.x.get_immut() }
-    }
-}
-
-impl<T:Freeze + Send> Clone for Arc<T> {
-    /**
-    * Duplicate an atomically reference counted wrapper.
-    *
-    * The resulting two `arc` objects will point to the same underlying data
-    * object. However, one of the `arc` objects can be sent to another task,
-    * allowing them to share the underlying data.
-    */
-    #[inline]
-    fn clone(&self) -> Arc<T> {
-        Arc { x: self.x.clone() }
-    }
-}
-
-/****************************************************************************
- * Mutex protected Arc (unsafe)
- ****************************************************************************/
-
-#[doc(hidden)]
-struct MutexArcInner<T> { lock: Mutex, failed: bool, data: T }
-
-/// An Arc with mutable data protected by a blocking mutex.
-pub struct MutexArc<T> {
-    priv x: UnsafeArc<MutexArcInner<T>>,
-    priv marker: marker::NoFreeze,
-}
-
-impl<T:Send> Clone for MutexArc<T> {
-    /// Duplicate a mutex-protected Arc. See arc::clone for more details.
-    #[inline]
-    fn clone(&self) -> MutexArc<T> {
-        // NB: Cloning the underlying mutex is not necessary. Its reference
-        // count would be exactly the same as the shared state's.
-        MutexArc { x: self.x.clone(),
-                   marker: marker::NoFreeze, }
-    }
-}
-
-impl<T:Send> MutexArc<T> {
-    /// Create a mutex-protected Arc with the supplied data.
-    pub fn new(user_data: T) -> MutexArc<T> {
-        MutexArc::new_with_condvars(user_data, 1)
-    }
-
-    /**
-     * Create a mutex-protected Arc with the supplied data and a specified number
-     * of condvars (as sync::Mutex::new_with_condvars).
-     */
-    pub fn new_with_condvars(user_data: T, num_condvars: uint) -> MutexArc<T> {
-        let data = MutexArcInner {
-            lock: Mutex::new_with_condvars(num_condvars),
-            failed: false, data: user_data
-        };
-        MutexArc { x: UnsafeArc::new(data),
-                   marker: marker::NoFreeze, }
-    }
-
-    /**
-     * Access the underlying mutable data with mutual exclusion from other
-     * tasks. The argument closure will be run with the mutex locked; all
-     * other tasks wishing to access the data will block until the closure
-     * finishes running.
-     *
-     * The reason this function is 'unsafe' is because it is possible to
-     * construct a circular reference among multiple Arcs by mutating the
-     * underlying data. This creates potential for deadlock, but worse, this
-     * will guarantee a memory leak of all involved Arcs. Using MutexArcs
-     * inside of other Arcs is safe in absence of circular references.
-     *
-     * If you wish to nest MutexArcs, one strategy for ensuring safety at
-     * runtime is to add a "nesting level counter" inside the stored data, and
-     * when traversing the arcs, assert that they monotonically decrease.
-     *
-     * # Failure
-     *
-     * Failing while inside the Arc will unlock the Arc while unwinding, so
-     * that other tasks won't block forever. It will also poison the Arc:
-     * any tasks that subsequently try to access it (including those already
-     * blocked on the mutex) will also fail immediately.
-     */
-    #[inline]
-    pub unsafe fn unsafe_access<U>(&self, blk: |x: &mut T| -> U) -> U {
-        let state = self.x.get();
-        // Borrowck would complain about this if the function were
-        // not already unsafe. See borrow_rwlock, far below.
-        (&(*state).lock).lock(|| {
-            check_poison(true, (*state).failed);
-            let _z = PoisonOnFail::new(&mut (*state).failed);
-            blk(&mut (*state).data)
-        })
-    }
-
-    /// As unsafe_access(), but with a condvar, as sync::mutex.lock_cond().
-    #[inline]
-    pub unsafe fn unsafe_access_cond<U>(&self,
-                                        blk: |x: &mut T, c: &Condvar| -> U)
-                                        -> U {
-        let state = self.x.get();
-        (&(*state).lock).lock_cond(|cond| {
-            check_poison(true, (*state).failed);
-            let _z = PoisonOnFail::new(&mut (*state).failed);
-            blk(&mut (*state).data,
-                &Condvar {is_mutex: true,
-                          failed: &(*state).failed,
-                          cond: cond })
-        })
-    }
-}
-
-impl<T:Freeze + Send> MutexArc<T> {
-
-    /**
-     * As unsafe_access.
-     *
-     * The difference between access and unsafe_access is that the former
-     * forbids mutexes to be nested. While unsafe_access can be used on
-     * MutexArcs without freezable interiors, this safe version of access
-     * requires the Freeze bound, which prohibits access on MutexArcs which
-     * might contain nested MutexArcs inside.
-     *
-     * The purpose of this is to offer a safe implementation of MutexArc to be
-     * used instead of RWArc in cases where no readers are needed and slightly
-     * better performance is required.
-     *
-     * Both methods have the same failure behaviour as unsafe_access and
-     * unsafe_access_cond.
-     */
-    #[inline]
-    pub fn access<U>(&self, blk: |x: &mut T| -> U) -> U {
-        unsafe { self.unsafe_access(blk) }
-    }
-
-    /// As unsafe_access_cond but safe and Freeze.
-    #[inline]
-    pub fn access_cond<U>(&self,
-                          blk: |x: &mut T, c: &Condvar| -> U)
-                          -> U {
-        unsafe { self.unsafe_access_cond(blk) }
-    }
-}
-
-// Common code for {mutex.access,rwlock.write}{,_cond}.
-#[inline]
-#[doc(hidden)]
-fn check_poison(is_mutex: bool, failed: bool) {
-    if failed {
-        if is_mutex {
-            fail!("Poisoned MutexArc - another task failed inside!");
-        } else {
-            fail!("Poisoned rw_arc - another task failed inside!");
-        }
-    }
-}
-
-#[doc(hidden)]
-struct PoisonOnFail {
-    flag: *mut bool,
-    failed: bool,
-}
-
-impl Drop for PoisonOnFail {
-    fn drop(&mut self) {
-        unsafe {
-            /* assert!(!*self.failed);
-               -- might be false in case of cond.wait() */
-            if !self.failed && task::failing() {
-                *self.flag = true;
-            }
-        }
-    }
-}
-
-impl PoisonOnFail {
-    fn new<'a>(flag: &'a mut bool) -> PoisonOnFail {
-        PoisonOnFail {
-            flag: flag,
-            failed: task::failing()
-        }
-    }
-}
-
-/****************************************************************************
- * R/W lock protected Arc
- ****************************************************************************/
-
-#[doc(hidden)]
-struct RWArcInner<T> { lock: RWLock, failed: bool, data: T }
-/**
- * A dual-mode Arc protected by a reader-writer lock. The data can be accessed
- * mutably or immutably, and immutably-accessing tasks may run concurrently.
- *
- * Unlike mutex_arcs, rw_arcs are safe, because they cannot be nested.
- */
-pub struct RWArc<T> {
-    priv x: UnsafeArc<RWArcInner<T>>,
-    priv marker: marker::NoFreeze,
-}
-
-impl<T:Freeze + Send> Clone for RWArc<T> {
-    /// Duplicate a rwlock-protected Arc. See arc::clone for more details.
-    #[inline]
-    fn clone(&self) -> RWArc<T> {
-        RWArc { x: self.x.clone(),
-                marker: marker::NoFreeze, }
-    }
-
-}
-
-impl<T:Freeze + Send> RWArc<T> {
-    /// Create a reader/writer Arc with the supplied data.
-    pub fn new(user_data: T) -> RWArc<T> {
-        RWArc::new_with_condvars(user_data, 1)
-    }
-
-    /**
-     * Create a reader/writer Arc with the supplied data and a specified number
-     * of condvars (as sync::RWLock::new_with_condvars).
-     */
-    pub fn new_with_condvars(user_data: T, num_condvars: uint) -> RWArc<T> {
-        let data = RWArcInner {
-            lock: RWLock::new_with_condvars(num_condvars),
-            failed: false, data: user_data
-        };
-        RWArc { x: UnsafeArc::new(data),
-                marker: marker::NoFreeze, }
-    }
-
-    /**
-     * Access the underlying data mutably. Locks the rwlock in write mode;
-     * other readers and writers will block.
-     *
-     * # Failure
-     *
-     * Failing while inside the Arc will unlock the Arc while unwinding, so
-     * that other tasks won't block forever. As MutexArc.access, it will also
-     * poison the Arc, so subsequent readers and writers will both also fail.
-     */
-    #[inline]
-    pub fn write<U>(&self, blk: |x: &mut T| -> U) -> U {
-        unsafe {
-            let state = self.x.get();
-            (*borrow_rwlock(state)).write(|| {
-                check_poison(false, (*state).failed);
-                let _z = PoisonOnFail::new(&mut (*state).failed);
-                blk(&mut (*state).data)
-            })
-        }
-    }
-
-    /// As write(), but with a condvar, as sync::rwlock.write_cond().
-    #[inline]
-    pub fn write_cond<U>(&self,
-                         blk: |x: &mut T, c: &Condvar| -> U)
-                         -> U {
-        unsafe {
-            let state = self.x.get();
-            (*borrow_rwlock(state)).write_cond(|cond| {
-                check_poison(false, (*state).failed);
-                let _z = PoisonOnFail::new(&mut (*state).failed);
-                blk(&mut (*state).data,
-                    &Condvar {is_mutex: false,
-                              failed: &(*state).failed,
-                              cond: cond})
-            })
-        }
-    }
-
-    /**
-     * Access the underlying data immutably. May run concurrently with other
-     * reading tasks.
-     *
-     * # Failure
-     *
-     * Failing will unlock the Arc while unwinding. However, unlike all other
-     * access modes, this will not poison the Arc.
-     */
-    pub fn read<U>(&self, blk: |x: &T| -> U) -> U {
-        unsafe {
-            let state = self.x.get();
-            (*state).lock.read(|| {
-                check_poison(false, (*state).failed);
-                blk(&(*state).data)
-            })
-        }
-    }
-
-    /**
-     * As write(), but with the ability to atomically 'downgrade' the lock.
-     * See sync::rwlock.write_downgrade(). The RWWriteMode token must be used
-     * to obtain the &mut T, and can be transformed into a RWReadMode token by
-     * calling downgrade(), after which a &T can be obtained instead.
-     *
-     * # Example
-     *
-     * ```rust
-     * use extra::arc::RWArc;
-     *
-     * let arc = RWArc::new(1);
-     * arc.write_downgrade(|mut write_token| {
-     *     write_token.write_cond(|state, condvar| {
-     *         // ... exclusive access with mutable state ...
-     *     });
-     *     let read_token = arc.downgrade(write_token);
-     *     read_token.read(|state| {
-     *         // ... shared access with immutable state ...
-     *     });
-     * })
-     * ```
-     */
-    pub fn write_downgrade<U>(&self, blk: |v: RWWriteMode<T>| -> U) -> U {
-        unsafe {
-            let state = self.x.get();
-            (*borrow_rwlock(state)).write_downgrade(|write_mode| {
-                check_poison(false, (*state).failed);
-                blk(RWWriteMode {
-                    data: &mut (*state).data,
-                    token: write_mode,
-                    poison: PoisonOnFail::new(&mut (*state).failed)
-                })
-            })
-        }
-    }
-
-    /// To be called inside of the write_downgrade block.
-    pub fn downgrade<'a>(&self, token: RWWriteMode<'a, T>)
-                         -> RWReadMode<'a, T> {
-        unsafe {
-            // The rwlock should assert that the token belongs to us for us.
-            let state = self.x.get();
-            let RWWriteMode {
-                data: data,
-                token: t,
-                poison: _poison
-            } = token;
-            // Let readers in
-            let new_token = (*state).lock.downgrade(t);
-            // Whatever region the input reference had, it will be safe to use
-            // the same region for the output reference. (The only 'unsafe' part
-            // of this cast is removing the mutability.)
-            let new_data = data;
-            // Downgrade ensured the token belonged to us. Just a sanity check.
-            assert!((&(*state).data as *T as uint) == (new_data as *mut T as uint));
-            // Produce new token
-            RWReadMode {
-                data: new_data,
-                token: new_token,
-            }
-        }
-    }
-}
-
-// 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'.
-#[doc(hidden)]
-fn borrow_rwlock<T:Freeze + Send>(state: *mut RWArcInner<T>) -> *RWLock {
-    unsafe { cast::transmute(&(*state).lock) }
-}
-
-/// The "write permission" token used for RWArc.write_downgrade().
-pub struct RWWriteMode<'a, T> {
-    priv data: &'a mut T,
-    priv token: sync::RWLockWriteMode<'a>,
-    priv poison: PoisonOnFail,
-}
-
-/// The "read permission" token used for RWArc.write_downgrade().
-pub struct RWReadMode<'a, T> {
-    priv data: &'a T,
-    priv token: sync::RWLockReadMode<'a>,
-}
-
-impl<'a, T:Freeze + Send> RWWriteMode<'a, T> {
-    /// Access the pre-downgrade RWArc in write mode.
-    pub fn write<U>(&mut self, blk: |x: &mut T| -> U) -> U {
-        match *self {
-            RWWriteMode {
-                data: &ref mut data,
-                token: ref token,
-                poison: _
-            } => {
-                token.write(|| blk(data))
-            }
-        }
-    }
-
-    /// Access the pre-downgrade RWArc in write mode with a condvar.
-    pub fn write_cond<U>(&mut self,
-                         blk: |x: &mut T, c: &Condvar| -> U)
-                         -> U {
-        match *self {
-            RWWriteMode {
-                data: &ref mut data,
-                token: ref token,
-                poison: ref poison
-            } => {
-                token.write_cond(|cond| {
-                    unsafe {
-                        let cvar = Condvar {
-                            is_mutex: false,
-                            failed: &*poison.flag,
-                            cond: cond
-                        };
-                        blk(data, &cvar)
-                    }
-                })
-            }
-        }
-    }
-}
-
-impl<'a, T:Freeze + Send> RWReadMode<'a, T> {
-    /// Access the post-downgrade rwlock in read mode.
-    pub fn read<U>(&self, blk: |x: &T| -> U) -> U {
-        match *self {
-            RWReadMode {
-                data: data,
-                token: ref token
-            } => {
-                token.read(|| blk(data))
-            }
-        }
-    }
-}
-
-/****************************************************************************
- * Copy-on-write Arc
- ****************************************************************************/
-
-pub struct CowArc<T> { priv x: UnsafeArc<T> }
-
-/// A Copy-on-write Arc functions the same way as an `arc` except it allows
-/// mutation of the contents if there is only a single reference to
-/// the data. If there are multiple references the data is automatically
-/// cloned and the task modifies the cloned data in place of the shared data.
-impl<T:Clone+Send+Freeze> CowArc<T> {
-    /// Create a copy-on-write atomically reference counted wrapper
-    #[inline]
-    pub fn new(data: T) -> CowArc<T> {
-        CowArc { x: UnsafeArc::new(data) }
-    }
-
-    #[inline]
-    pub fn get<'a>(&'a self) -> &'a T {
-        unsafe { &*self.x.get_immut() }
-    }
-
-    /// get a mutable reference to the contents. If there are more then one
-    /// reference to the contents of the `CowArc` will be cloned
-    /// and this reference updated to point to the cloned data.
-    #[inline]
-    pub fn get_mut<'a>(&'a mut self) -> &'a mut T {
-        if !self.x.is_owned() {
-            *self = CowArc::new(self.get().clone())
-        }
-        unsafe { &mut *self.x.get() }
-    }
-}
-
-impl<T:Clone+Send+Freeze> Clone for CowArc<T> {
-    /// Duplicate a Copy-on-write Arc. See arc::clone for more details.
-    #[inline]
-    fn clone(&self) -> CowArc<T> {
-        CowArc { x: self.x.clone() }
-    }
-}
-
-
-
-/****************************************************************************
- * Tests
- ****************************************************************************/
-
-#[cfg(test)]
-mod tests {
-
-    use arc::*;
-
-    use std::task;
-
-    #[test]
-    fn manually_share_arc() {
-        let v = ~[1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
-        let arc_v = Arc::new(v);
-
-        let (p, c) = Chan::new();
-
-        task::spawn(proc() {
-            let arc_v: Arc<~[int]> = p.recv();
-
-            let v = arc_v.get().clone();
-            assert_eq!(v[3], 4);
-        });
-
-        c.send(arc_v.clone());
-
-        assert_eq!(arc_v.get()[2], 3);
-        assert_eq!(arc_v.get()[4], 5);
-
-        info!("{:?}", arc_v);
-    }
-
-    #[test]
-    fn test_mutex_arc_condvar() {
-        let arc = ~MutexArc::new(false);
-        let arc2 = ~arc.clone();
-        let (p,c) = Chan::new();
-        task::spawn(proc() {
-            // wait until parent gets in
-            p.recv();
-            arc2.access_cond(|state, cond| {
-                *state = true;
-                cond.signal();
-            })
-        });
-
-        arc.access_cond(|state, cond| {
-            c.send(());
-            assert!(!*state);
-            while !*state {
-                cond.wait();
-            }
-        })
-    }
-
-    #[test] #[should_fail]
-    fn test_arc_condvar_poison() {
-        let arc = ~MutexArc::new(1);
-        let arc2 = ~arc.clone();
-        let (p, c) = Chan::new();
-
-        spawn(proc() {
-            let _ = p.recv();
-            arc2.access_cond(|one, cond| {
-                cond.signal();
-                // Parent should fail when it wakes up.
-                assert_eq!(*one, 0);
-            })
-        });
-
-        arc.access_cond(|one, cond| {
-            c.send(());
-            while *one == 1 {
-                cond.wait();
-            }
-        })
-    }
-
-    #[test] #[should_fail]
-    fn test_mutex_arc_poison() {
-        let arc = ~MutexArc::new(1);
-        let arc2 = ~arc.clone();
-        let _ = task::try(proc() {
-            arc2.access(|one| {
-                assert_eq!(*one, 2);
-            })
-        });
-        arc.access(|one| {
-            assert_eq!(*one, 1);
-        })
-    }
-
-    #[test]
-    fn test_unsafe_mutex_arc_nested() {
-        unsafe {
-            // Tests nested mutexes and access
-            // to underlaying data.
-            let arc = ~MutexArc::new(1);
-            let arc2 = ~MutexArc::new(*arc);
-            task::spawn(proc() {
-                (*arc2).unsafe_access(|mutex| {
-                    (*mutex).access(|one| {
-                        assert!(*one == 1);
-                    })
-                })
-            });
-        }
-    }
-
-    #[test]
-    fn test_mutex_arc_access_in_unwind() {
-        let arc = MutexArc::new(1i);
-        let arc2 = arc.clone();
-        let _ = task::try::<()>(proc() {
-            struct Unwinder {
-                i: MutexArc<int>
-            }
-            impl Drop for Unwinder {
-                fn drop(&mut self) {
-                    self.i.access(|num| *num += 1);
-                }
-            }
-            let _u = Unwinder { i: arc2 };
-            fail!();
-        });
-        assert_eq!(2, arc.access(|n| *n));
-    }
-
-    #[test] #[should_fail]
-    fn test_rw_arc_poison_wr() {
-        let arc = RWArc::new(1);
-        let arc2 = arc.clone();
-        let _ = task::try(proc() {
-            arc2.write(|one| {
-                assert_eq!(*one, 2);
-            })
-        });
-        arc.read(|one| {
-            assert_eq!(*one, 1);
-        })
-    }
-
-    #[test] #[should_fail]
-    fn test_rw_arc_poison_ww() {
-        let arc = RWArc::new(1);
-        let arc2 = arc.clone();
-        let _ = task::try(proc() {
-            arc2.write(|one| {
-                assert_eq!(*one, 2);
-            })
-        });
-        arc.write(|one| {
-            assert_eq!(*one, 1);
-        })
-    }
-    #[test] #[should_fail]
-    fn test_rw_arc_poison_dw() {
-        let arc = RWArc::new(1);
-        let arc2 = arc.clone();
-        let _ = task::try(proc() {
-            arc2.write_downgrade(|mut write_mode| {
-                write_mode.write(|one| {
-                    assert_eq!(*one, 2);
-                })
-            })
-        });
-        arc.write(|one| {
-            assert_eq!(*one, 1);
-        })
-    }
-    #[test]
-    fn test_rw_arc_no_poison_rr() {
-        let arc = RWArc::new(1);
-        let arc2 = arc.clone();
-        let _ = task::try(proc() {
-            arc2.read(|one| {
-                assert_eq!(*one, 2);
-            })
-        });
-        arc.read(|one| {
-            assert_eq!(*one, 1);
-        })
-    }
-    #[test]
-    fn test_rw_arc_no_poison_rw() {
-        let arc = RWArc::new(1);
-        let arc2 = arc.clone();
-        let _ = task::try(proc() {
-            arc2.read(|one| {
-                assert_eq!(*one, 2);
-            })
-        });
-        arc.write(|one| {
-            assert_eq!(*one, 1);
-        })
-    }
-    #[test]
-    fn test_rw_arc_no_poison_dr() {
-        let arc = RWArc::new(1);
-        let arc2 = arc.clone();
-        let _ = task::try(proc() {
-            arc2.write_downgrade(|write_mode| {
-                let read_mode = arc2.downgrade(write_mode);
-                read_mode.read(|one| {
-                    assert_eq!(*one, 2);
-                })
-            })
-        });
-        arc.write(|one| {
-            assert_eq!(*one, 1);
-        })
-    }
-    #[test]
-    fn test_rw_arc() {
-        let arc = RWArc::new(0);
-        let arc2 = arc.clone();
-        let (p, c) = Chan::new();
-
-        task::spawn(proc() {
-            arc2.write(|num| {
-                for _ in range(0, 10) {
-                    let tmp = *num;
-                    *num = -1;
-                    task::deschedule();
-                    *num = tmp + 1;
-                }
-                c.send(());
-            })
-        });
-
-        // Readers try to catch the writer in the act
-        let mut children = ~[];
-        for _ in range(0, 5) {
-            let arc3 = arc.clone();
-            let mut builder = task::task();
-            children.push(builder.future_result());
-            builder.spawn(proc() {
-                arc3.read(|num| {
-                    assert!(*num >= 0);
-                })
-            });
-        }
-
-        // Wait for children to pass their asserts
-        for r in children.mut_iter() {
-            let _ = r.recv();
-        }
-
-        // Wait for writer to finish
-        p.recv();
-        arc.read(|num| {
-            assert_eq!(*num, 10);
-        })
-    }
-
-    #[test]
-    fn test_rw_arc_access_in_unwind() {
-        let arc = RWArc::new(1i);
-        let arc2 = arc.clone();
-        let _ = task::try::<()>(proc() {
-            struct Unwinder {
-                i: RWArc<int>
-            }
-            impl Drop for Unwinder {
-                fn drop(&mut self) {
-                    self.i.write(|num| *num += 1);
-                }
-            }
-            let _u = Unwinder { i: arc2 };
-            fail!();
-        });
-        assert_eq!(2, arc.read(|n| *n));
-    }
-
-    #[test]
-    fn test_rw_downgrade() {
-        // (1) A downgrader gets in write mode and does cond.wait.
-        // (2) A writer gets in write mode, sets state to 42, and does signal.
-        // (3) Downgrader wakes, sets state to 31337.
-        // (4) tells writer and all other readers to contend as it downgrades.
-        // (5) Writer attempts to set state back to 42, while downgraded task
-        //     and all reader tasks assert that it's 31337.
-        let arc = RWArc::new(0);
-
-        // Reader tasks
-        let mut reader_convos = ~[];
-        for _ in range(0, 10) {
-            let ((rp1, rc1), (rp2, rc2)) = (Chan::new(), Chan::new());
-            reader_convos.push((rc1, rp2));
-            let arcn = arc.clone();
-            task::spawn(proc() {
-                rp1.recv(); // wait for downgrader to give go-ahead
-                arcn.read(|state| {
-                    assert_eq!(*state, 31337);
-                    rc2.send(());
-                })
-            });
-        }
-
-        // Writer task
-        let arc2 = arc.clone();
-        let ((wp1, wc1), (wp2, wc2)) = (Chan::new(), Chan::new());
-        task::spawn(proc() {
-            wp1.recv();
-            arc2.write_cond(|state, cond| {
-                assert_eq!(*state, 0);
-                *state = 42;
-                cond.signal();
-            });
-            wp1.recv();
-            arc2.write(|state| {
-                // This shouldn't happen until after the downgrade read
-                // section, and all other readers, finish.
-                assert_eq!(*state, 31337);
-                *state = 42;
-            });
-            wc2.send(());
-        });
-
-        // Downgrader (us)
-        arc.write_downgrade(|mut write_mode| {
-            write_mode.write_cond(|state, cond| {
-                wc1.send(()); // send to another writer who will wake us up
-                while *state == 0 {
-                    cond.wait();
-                }
-                assert_eq!(*state, 42);
-                *state = 31337;
-                // send to other readers
-                for &(ref mut rc, _) in reader_convos.mut_iter() {
-                    rc.send(())
-                }
-            });
-            let read_mode = arc.downgrade(write_mode);
-            read_mode.read(|state| {
-                // complete handshake with other readers
-                for &(_, ref mut rp) in reader_convos.mut_iter() {
-                    rp.recv()
-                }
-                wc1.send(()); // tell writer to try again
-                assert_eq!(*state, 31337);
-            });
-        });
-
-        wp2.recv(); // complete handshake with writer
-    }
-    #[cfg(test)]
-    fn test_rw_write_cond_downgrade_read_race_helper() {
-        // Tests that when a downgrader hands off the "reader cloud" lock
-        // because of a contending reader, a writer can't race to get it
-        // instead, which would result in readers_and_writers. This tests
-        // the sync module rather than this one, but it's here because an
-        // rwarc gives us extra shared state to help check for the race.
-        // If you want to see this test fail, go to sync.rs and replace the
-        // line in RWLock::write_cond() that looks like:
-        //     "blk(&Condvar { order: opt_lock, ..*cond })"
-        // with just "blk(cond)".
-        let x = RWArc::new(true);
-        let (wp, wc) = Chan::new();
-
-        // writer task
-        let xw = x.clone();
-        task::spawn(proc() {
-            xw.write_cond(|state, c| {
-                wc.send(()); // tell downgrader it's ok to go
-                c.wait();
-                // The core of the test is here: the condvar reacquire path
-                // must involve order_lock, so that it cannot race with a reader
-                // trying to receive the "reader cloud lock hand-off".
-                *state = false;
-            })
-        });
-
-        wp.recv(); // wait for writer to get in
-
-        x.write_downgrade(|mut write_mode| {
-            write_mode.write_cond(|state, c| {
-                assert!(*state);
-                // make writer contend in the cond-reacquire path
-                c.signal();
-            });
-            // make a reader task to trigger the "reader cloud lock" handoff
-            let xr = x.clone();
-            let (rp, rc) = Chan::new();
-            task::spawn(proc() {
-                rc.send(());
-                xr.read(|_state| { })
-            });
-            rp.recv(); // wait for reader task to exist
-
-            let read_mode = x.downgrade(write_mode);
-            read_mode.read(|state| {
-                // if writer mistakenly got in, make sure it mutates state
-                // before we assert on it
-                for _ in range(0, 5) { task::deschedule(); }
-                // make sure writer didn't get in.
-                assert!(*state);
-            })
-        });
-    }
-    #[test]
-    fn test_rw_write_cond_downgrade_read_race() {
-        // Ideally the above test case would have deschedule statements in it that
-        // helped to expose the race nearly 100% of the time... but adding
-        // deschedules in the intuitively-right locations made it even less likely,
-        // and I wasn't sure why :( . This is a mediocre "next best" option.
-        for _ in range(0, 8) { test_rw_write_cond_downgrade_read_race_helper(); }
-    }
-
-    #[test]
-    fn test_cowarc_clone()
-    {
-        let cow0 = CowArc::new(75u);
-        let cow1 = cow0.clone();
-        let cow2 = cow1.clone();
-
-        assert!(75 == *cow0.get());
-        assert!(75 == *cow1.get());
-        assert!(75 == *cow2.get());
-
-        assert!(cow0.get() == cow1.get());
-        assert!(cow0.get() == cow2.get());
-    }
-
-    #[test]
-    fn test_cowarc_clone_get_mut()
-    {
-        let mut cow0 = CowArc::new(75u);
-        let mut cow1 = cow0.clone();
-        let mut cow2 = cow1.clone();
-
-        assert!(75 == *cow0.get_mut());
-        assert!(75 == *cow1.get_mut());
-        assert!(75 == *cow2.get_mut());
-
-        *cow0.get_mut() += 1;
-        *cow1.get_mut() += 2;
-        *cow2.get_mut() += 3;
-
-        assert!(76 == *cow0.get());
-        assert!(77 == *cow1.get());
-        assert!(78 == *cow2.get());
-
-        // none should point to the same backing memory
-        assert!(cow0.get() != cow1.get());
-        assert!(cow0.get() != cow2.get());
-        assert!(cow1.get() != cow2.get());
-    }
-
-    #[test]
-    fn test_cowarc_clone_get_mut2()
-    {
-        let mut cow0 = CowArc::new(75u);
-        let cow1 = cow0.clone();
-        let cow2 = cow1.clone();
-
-        assert!(75 == *cow0.get());
-        assert!(75 == *cow1.get());
-        assert!(75 == *cow2.get());
-
-        *cow0.get_mut() += 1;
-
-        assert!(76 == *cow0.get());
-        assert!(75 == *cow1.get());
-        assert!(75 == *cow2.get());
-
-        // cow1 and cow2 should share the same contents
-        // cow0 should have a unique reference
-        assert!(cow0.get() != cow1.get());
-        assert!(cow0.get() != cow2.get());
-        assert!(cow1.get() == cow2.get());
-    }
-}
diff --git a/src/libextra/comm.rs b/src/libextra/comm.rs
deleted file mode 100644 (file)
index c7d5507..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-// Copyright 2012-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.
-
-/*!
-
-Higher level communication abstractions.
-
-*/
-
-#[allow(missing_doc)];
-
-use std::comm;
-
-/// An extension of `pipes::stream` that allows both sending and receiving.
-pub struct DuplexStream<T, U> {
-    priv chan: Chan<T>,
-    priv port: Port<U>,
-}
-
-// Allow these methods to be used without import:
-impl<T:Send,U:Send> DuplexStream<T, U> {
-    /// Creates a bidirectional stream.
-    pub fn new() -> (DuplexStream<T, U>, DuplexStream<U, T>) {
-        let (p1, c2) = Chan::new();
-        let (p2, c1) = Chan::new();
-        (DuplexStream { chan: c1, port: p1 },
-         DuplexStream { chan: c2, port: p2 })
-    }
-    pub fn send(&self, x: T) {
-        self.chan.send(x)
-    }
-    pub fn try_send(&self, x: T) -> bool {
-        self.chan.try_send(x)
-    }
-    pub fn recv(&self) -> U {
-        self.port.recv()
-    }
-    pub fn try_recv(&self) -> comm::TryRecvResult<U> {
-        self.port.try_recv()
-    }
-    pub fn recv_opt(&self) -> Option<U> {
-        self.port.recv_opt()
-    }
-}
-
-/// An extension of `pipes::stream` that provides synchronous message sending.
-pub struct SyncChan<T> { priv duplex_stream: DuplexStream<T, ()> }
-/// An extension of `pipes::stream` that acknowledges each message received.
-pub struct SyncPort<T> { priv duplex_stream: DuplexStream<(), T> }
-
-impl<T: Send> SyncChan<T> {
-    pub fn send(&self, val: T) {
-        assert!(self.try_send(val), "SyncChan.send: receiving port closed");
-    }
-
-    /// Sends a message, or report if the receiver has closed the connection
-    /// before receiving.
-    pub fn try_send(&self, val: T) -> bool {
-        self.duplex_stream.try_send(val) && self.duplex_stream.recv_opt().is_some()
-    }
-}
-
-impl<T: Send> SyncPort<T> {
-    pub fn recv(&self) -> T {
-        self.recv_opt().expect("SyncPort.recv: sending channel closed")
-    }
-
-    pub fn recv_opt(&self) -> Option<T> {
-        self.duplex_stream.recv_opt().map(|val| {
-            self.duplex_stream.try_send(());
-            val
-        })
-    }
-
-    pub fn try_recv(&self) -> comm::TryRecvResult<T> {
-        match self.duplex_stream.try_recv() {
-            comm::Data(t) => { self.duplex_stream.try_send(()); comm::Data(t) }
-            state => state,
-        }
-    }
-}
-
-/// Creates a stream whose channel, upon sending a message, blocks until the
-/// message is received.
-pub fn rendezvous<T: Send>() -> (SyncPort<T>, SyncChan<T>) {
-    let (chan_stream, port_stream) = DuplexStream::new();
-    (SyncPort { duplex_stream: port_stream },
-     SyncChan { duplex_stream: chan_stream })
-}
-
-#[cfg(test)]
-mod test {
-    use comm::{DuplexStream, rendezvous};
-
-
-    #[test]
-    pub fn DuplexStream1() {
-        let (left, right) = DuplexStream::new();
-
-        left.send(~"abc");
-        right.send(123);
-
-        assert!(left.recv() == 123);
-        assert!(right.recv() == ~"abc");
-    }
-
-    #[test]
-    pub fn basic_rendezvous_test() {
-        let (port, chan) = rendezvous();
-
-        spawn(proc() {
-            chan.send("abc");
-        });
-
-        assert!(port.recv() == "abc");
-    }
-
-    #[test]
-    fn recv_a_lot() {
-        // Rendezvous streams should be able to handle any number of messages being sent
-        let (port, chan) = rendezvous();
-        spawn(proc() {
-            for _ in range(0, 10000) { chan.send(()); }
-        });
-        for _ in range(0, 10000) { port.recv(); }
-    }
-
-    #[test]
-    fn send_and_fail_and_try_recv() {
-        let (port, chan) = rendezvous();
-        spawn(proc() {
-            chan.duplex_stream.send(()); // Can't access this field outside this module
-            fail!()
-        });
-        port.recv()
-    }
-
-    #[test]
-    fn try_send_and_recv_then_fail_before_ack() {
-        let (port, chan) = rendezvous();
-        spawn(proc() {
-            port.duplex_stream.recv();
-            fail!()
-        });
-        chan.try_send(());
-    }
-
-    #[test]
-    #[should_fail]
-    fn send_and_recv_then_fail_before_ack() {
-        let (port, chan) = rendezvous();
-        spawn(proc() {
-            port.duplex_stream.recv();
-            fail!()
-        });
-        chan.send(());
-    }
-}
diff --git a/src/libextra/future.rs b/src/libextra/future.rs
deleted file mode 100644 (file)
index b912129..0000000
+++ /dev/null
@@ -1,205 +0,0 @@
-// Copyright 2012-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.
-
-/*!
- * A type representing values that may be computed concurrently and
- * operations for working with them.
- *
- * # Example
- *
- * ```rust
- * use extra::future::Future;
- * # fn fib(n: uint) -> uint {42};
- * # fn make_a_sandwich() {};
- * let mut delayed_fib = Future::spawn(proc() { fib(5000) });
- * make_a_sandwich();
- * println!("fib(5000) = {}", delayed_fib.get())
- * ```
- */
-
-#[allow(missing_doc)];
-
-use std::util::replace;
-
-/// A type encapsulating the result of a computation which may not be complete
-pub struct Future<A> {
-    priv state: FutureState<A>,
-}
-
-enum FutureState<A> {
-    Pending(proc() -> A),
-    Evaluating,
-    Forced(A)
-}
-
-/// Methods on the `future` type
-impl<A:Clone> Future<A> {
-    pub fn get(&mut self) -> A {
-        //! Get the value of the future.
-        (*(self.get_ref())).clone()
-    }
-}
-
-impl<A> Future<A> {
-    /// Gets the value from this future, forcing evaluation.
-    pub fn unwrap(mut self) -> A {
-        self.get_ref();
-        let state = replace(&mut self.state, Evaluating);
-        match state {
-            Forced(v) => v,
-            _ => fail!( "Logic error." ),
-        }
-    }
-
-    pub fn get_ref<'a>(&'a mut self) -> &'a A {
-        /*!
-        * Executes the future's closure and then returns a reference
-        * to the result.  The reference lasts as long as
-        * the future.
-        */
-        match self.state {
-            Forced(ref v) => return v,
-            Evaluating => fail!("Recursive forcing of future!"),
-            Pending(_) => {
-                match replace(&mut self.state, Evaluating) {
-                    Forced(_) | Evaluating => fail!("Logic error."),
-                    Pending(f) => {
-                        self.state = Forced(f());
-                        self.get_ref()
-                    }
-                }
-            }
-        }
-    }
-
-    pub fn from_value(val: A) -> Future<A> {
-        /*!
-         * Create a future from a value.
-         *
-         * The value is immediately available and calling `get` later will
-         * not block.
-         */
-
-        Future {state: Forced(val)}
-    }
-
-    pub fn from_fn(f: proc() -> A) -> Future<A> {
-        /*!
-         * Create a future from a function.
-         *
-         * The first time that the value is requested it will be retrieved by
-         * calling the function.  Note that this function is a local
-         * function. It is not spawned into another task.
-         */
-
-        Future {state: Pending(f)}
-    }
-}
-
-impl<A:Send> Future<A> {
-    pub fn from_port(port: Port<A>) -> Future<A> {
-        /*!
-         * Create a future from a port
-         *
-         * The first time that the value is requested the task will block
-         * waiting for the result to be received on the port.
-         */
-
-        Future::from_fn(proc() {
-            port.recv()
-        })
-    }
-
-    pub fn spawn(blk: proc() -> A) -> Future<A> {
-        /*!
-         * Create a future from a unique closure.
-         *
-         * The closure will be run in a new task and its result used as the
-         * value of the future.
-         */
-
-        let (port, chan) = Chan::new();
-
-        spawn(proc() {
-            chan.send(blk());
-        });
-
-        Future::from_port(port)
-    }
-}
-
-#[cfg(test)]
-mod test {
-    use future::Future;
-
-    use std::task;
-
-    #[test]
-    fn test_from_value() {
-        let mut f = Future::from_value(~"snail");
-        assert_eq!(f.get(), ~"snail");
-    }
-
-    #[test]
-    fn test_from_port() {
-        let (po, ch) = Chan::new();
-        ch.send(~"whale");
-        let mut f = Future::from_port(po);
-        assert_eq!(f.get(), ~"whale");
-    }
-
-    #[test]
-    fn test_from_fn() {
-        let mut f = Future::from_fn(proc() ~"brail");
-        assert_eq!(f.get(), ~"brail");
-    }
-
-    #[test]
-    fn test_interface_get() {
-        let mut f = Future::from_value(~"fail");
-        assert_eq!(f.get(), ~"fail");
-    }
-
-    #[test]
-    fn test_interface_unwrap() {
-        let f = Future::from_value(~"fail");
-        assert_eq!(f.unwrap(), ~"fail");
-    }
-
-    #[test]
-    fn test_get_ref_method() {
-        let mut f = Future::from_value(22);
-        assert_eq!(*f.get_ref(), 22);
-    }
-
-    #[test]
-    fn test_spawn() {
-        let mut f = Future::spawn(proc() ~"bale");
-        assert_eq!(f.get(), ~"bale");
-    }
-
-    #[test]
-    #[should_fail]
-    fn test_futurefail() {
-        let mut f = Future::spawn(proc() fail!());
-        let _x: ~str = f.get();
-    }
-
-    #[test]
-    fn test_sendable_future() {
-        let expected = "schlorf";
-        let f = Future::spawn(proc() { expected });
-        task::spawn(proc() {
-            let mut f = f;
-            let actual = f.get();
-            assert_eq!(actual, expected);
-        });
-    }
-}
index d198fd44450c4ee5bad7a7e3fde504160a3243ed..401ece64a5dc24178837c2141caead7981cb6ded 100644 (file)
 #[deny(non_camel_case_types)];
 #[deny(missing_doc)];
 
-// Utility modules
+extern mod sync;
 
-pub mod c_vec;
+#[cfg(stage0)]
+macro_rules! if_ok (
+    ($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(e) })
+)
 
-// Concurrency
+// Utility modules
 
-pub mod sync;
-pub mod arc;
-pub mod comm;
-pub mod future;
-pub mod task_pool;
+pub mod c_vec;
 
 // Collections
 
diff --git a/src/libextra/sync/mod.rs b/src/libextra/sync/mod.rs
deleted file mode 100644 (file)
index 03bf110..0000000
+++ /dev/null
@@ -1,1420 +0,0 @@
-// Copyright 2012-2014 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.
-
-#[allow(missing_doc)];
-
-/**
- * The concurrency primitives you know and love.
- *
- * Maybe once we have a "core exports x only to std" mechanism, these can be
- * in std.
- */
-
-use std::cast;
-use std::comm;
-use std::kinds::marker;
-use std::sync::arc::UnsafeArc;
-use std::sync::atomics;
-use std::unstable::finally::Finally;
-use std::util;
-
-use arc::MutexArc;
-
-/****************************************************************************
- * Internals
- ****************************************************************************/
-
-pub mod mutex;
-pub mod one;
-mod mpsc_intrusive;
-
-// Each waiting task receives on one of these.
-#[doc(hidden)]
-type WaitEnd = Port<()>;
-#[doc(hidden)]
-type SignalEnd = Chan<()>;
-// A doubly-ended queue of waiting tasks.
-#[doc(hidden)]
-struct WaitQueue { head: Port<SignalEnd>,
-                   tail: Chan<SignalEnd> }
-
-impl WaitQueue {
-    fn new() -> WaitQueue {
-        let (block_head, block_tail) = Chan::new();
-        WaitQueue { head: block_head, tail: block_tail }
-    }
-
-    // Signals one live task from the queue.
-    fn signal(&self) -> bool {
-        match self.head.try_recv() {
-            comm::Data(ch) => {
-                // Send a wakeup signal. If the waiter was killed, its port will
-                // have closed. Keep trying until we get a live task.
-                if ch.try_send(()) {
-                    true
-                } else {
-                    self.signal()
-                }
-            }
-            _ => false
-        }
-    }
-
-    fn broadcast(&self) -> uint {
-        let mut count = 0;
-        loop {
-            match self.head.try_recv() {
-                comm::Data(ch) => {
-                    if ch.try_send(()) {
-                        count += 1;
-                    }
-                }
-                _ => break
-            }
-        }
-        count
-    }
-
-    fn wait_end(&self) -> WaitEnd {
-        let (wait_end, signal_end) = Chan::new();
-        assert!(self.tail.try_send(signal_end));
-        wait_end
-    }
-}
-
-// The building-block used to make semaphores, mutexes, and rwlocks.
-struct SemInner<Q> {
-    lock: mutex::Mutex,
-    count: int,
-    waiters:   WaitQueue,
-    // Can be either unit or another waitqueue. Some sems shouldn't come with
-    // a condition variable attached, others should.
-    blocked:   Q
-}
-
-struct Sem<Q>(UnsafeArc<SemInner<Q>>);
-
-#[doc(hidden)]
-impl<Q:Send> Sem<Q> {
-    fn new(count: int, q: Q) -> Sem<Q> {
-        Sem(UnsafeArc::new(SemInner {
-            count: count,
-            waiters: WaitQueue::new(),
-            blocked: q,
-            lock: mutex::Mutex::new(),
-        }))
-    }
-
-    unsafe fn with(&self, f: |&mut SemInner<Q>|) {
-        let Sem(ref arc) = *self;
-        let state = arc.get();
-        let _g = (*state).lock.lock();
-        f(cast::transmute(state));
-    }
-
-    pub fn acquire(&self) {
-        unsafe {
-            let mut waiter_nobe = None;
-            self.with(|state| {
-                state.count -= 1;
-                if state.count < 0 {
-                    // Create waiter nobe, enqueue ourself, and tell
-                    // outer scope we need to block.
-                    waiter_nobe = Some(state.waiters.wait_end());
-                }
-            });
-            // Uncomment if you wish to test for sem races. Not valgrind-friendly.
-            /* for _ in range(0, 1000) { task::deschedule(); } */
-            // Need to wait outside the exclusive.
-            if waiter_nobe.is_some() {
-                let _ = waiter_nobe.unwrap().recv();
-            }
-        }
-    }
-
-    pub fn release(&self) {
-        unsafe {
-            self.with(|state| {
-                state.count += 1;
-                if state.count <= 0 {
-                    state.waiters.signal();
-                }
-            })
-        }
-    }
-
-    pub fn access<U>(&self, blk: || -> U) -> U {
-        (|| {
-            self.acquire();
-            blk()
-        }).finally(|| {
-            self.release();
-        })
-    }
-}
-
-#[doc(hidden)]
-impl Sem<~[WaitQueue]> {
-    fn new_and_signal(count: int, num_condvars: uint)
-        -> Sem<~[WaitQueue]> {
-        let mut queues = ~[];
-        for _ in range(0, num_condvars) { queues.push(WaitQueue::new()); }
-        Sem::new(count, queues)
-    }
-}
-
-// FIXME(#3598): Want to use an Option down below, but we need a custom enum
-// that's not polymorphic to get around the fact that lifetimes are invariant
-// inside of type parameters.
-enum ReacquireOrderLock<'a> {
-    Nothing, // c.c
-    Just(&'a Semaphore),
-}
-
-/// A mechanism for atomic-unlock-and-deschedule blocking and signalling.
-pub struct Condvar<'a> {
-    // The 'Sem' object associated with this condvar. This is the one that's
-    // atomically-unlocked-and-descheduled upon and reacquired during wakeup.
-    priv sem: &'a Sem<~[WaitQueue]>,
-    // This is (can be) an extra semaphore which is held around the reacquire
-    // operation on the first one. This is only used in cvars associated with
-    // rwlocks, and is needed to ensure that, when a downgrader is trying to
-    // hand off the access lock (which would be the first field, here), a 2nd
-    // writer waking up from a cvar wait can't race with a reader to steal it,
-    // See the comment in write_cond for more detail.
-    priv order: ReacquireOrderLock<'a>,
-    // Make sure condvars are non-copyable.
-    priv nopod: marker::NoPod,
-}
-
-impl<'a> Condvar<'a> {
-    /**
-     * Atomically drop the associated lock, and block until a signal is sent.
-     *
-     * # Failure
-     * A task which is killed (i.e., by linked failure with another task)
-     * while waiting on a condition variable will wake up, fail, and unlock
-     * the associated lock as it unwinds.
-     */
-    pub fn wait(&self) { self.wait_on(0) }
-
-    /**
-     * As wait(), but can specify which of multiple condition variables to
-     * wait on. Only a signal_on() or broadcast_on() with the same condvar_id
-     * will wake this thread.
-     *
-     * The associated lock must have been initialised with an appropriate
-     * number of condvars. The condvar_id must be between 0 and num_condvars-1
-     * or else this call will fail.
-     *
-     * wait() is equivalent to wait_on(0).
-     */
-    pub fn wait_on(&self, condvar_id: uint) {
-        let mut WaitEnd = None;
-        let mut out_of_bounds = None;
-        // Release lock, 'atomically' enqueuing ourselves in so doing.
-        unsafe {
-            self.sem.with(|state| {
-                if condvar_id < state.blocked.len() {
-                    // Drop the lock.
-                    state.count += 1;
-                    if state.count <= 0 {
-                        state.waiters.signal();
-                    }
-                    // Create waiter nobe, and enqueue ourself to
-                    // be woken up by a signaller.
-                    WaitEnd = Some(state.blocked[condvar_id].wait_end());
-                } else {
-                    out_of_bounds = Some(state.blocked.len());
-                }
-            })
-        }
-
-        // If deschedule checks start getting inserted anywhere, we can be
-        // killed before or after enqueueing.
-        check_cvar_bounds(out_of_bounds, condvar_id, "cond.wait_on()", || {
-            // Unconditionally "block". (Might not actually block if a
-            // signaller already sent -- I mean 'unconditionally' in contrast
-            // with acquire().)
-            (|| {
-                let _ = WaitEnd.take_unwrap().recv();
-            }).finally(|| {
-                // Reacquire the condvar.
-                match self.order {
-                    Just(lock) => lock.access(|| self.sem.acquire()),
-                    Nothing => self.sem.acquire(),
-                }
-            })
-        })
-    }
-
-    /// Wake up a blocked task. Returns false if there was no blocked task.
-    pub fn signal(&self) -> bool { self.signal_on(0) }
-
-    /// As signal, but with a specified condvar_id. See wait_on.
-    pub fn signal_on(&self, condvar_id: uint) -> bool {
-        unsafe {
-            let mut out_of_bounds = None;
-            let mut result = false;
-            self.sem.with(|state| {
-                if condvar_id < state.blocked.len() {
-                    result = state.blocked[condvar_id].signal();
-                } else {
-                    out_of_bounds = Some(state.blocked.len());
-                }
-            });
-            check_cvar_bounds(out_of_bounds,
-                              condvar_id,
-                              "cond.signal_on()",
-                              || result)
-        }
-    }
-
-    /// Wake up all blocked tasks. Returns the number of tasks woken.
-    pub fn broadcast(&self) -> uint { self.broadcast_on(0) }
-
-    /// As broadcast, but with a specified condvar_id. See wait_on.
-    pub fn broadcast_on(&self, condvar_id: uint) -> uint {
-        let mut out_of_bounds = None;
-        let mut queue = None;
-        unsafe {
-            self.sem.with(|state| {
-                if condvar_id < state.blocked.len() {
-                    // To avoid :broadcast_heavy, we make a new waitqueue,
-                    // swap it out with the old one, and broadcast on the
-                    // old one outside of the little-lock.
-                    queue = Some(util::replace(&mut state.blocked[condvar_id],
-                                               WaitQueue::new()));
-                } else {
-                    out_of_bounds = Some(state.blocked.len());
-                }
-            });
-            check_cvar_bounds(out_of_bounds,
-                              condvar_id,
-                              "cond.signal_on()",
-                              || {
-                queue.take_unwrap().broadcast()
-            })
-        }
-    }
-}
-
-// Checks whether a condvar ID was out of bounds, and fails if so, or does
-// something else next on success.
-#[inline]
-#[doc(hidden)]
-fn check_cvar_bounds<U>(
-                     out_of_bounds: Option<uint>,
-                     id: uint,
-                     act: &str,
-                     blk: || -> U)
-                     -> U {
-    match out_of_bounds {
-        Some(0) =>
-            fail!("{} with illegal ID {} - this lock has no condvars!", act, id),
-        Some(length) =>
-            fail!("{} with illegal ID {} - ID must be less than {}", act, id, length),
-        None => blk()
-    }
-}
-
-#[doc(hidden)]
-impl Sem<~[WaitQueue]> {
-    // The only other places that condvars get built are rwlock.write_cond()
-    // and rwlock_write_mode.
-    pub fn access_cond<U>(&self, blk: |c: &Condvar| -> U) -> U {
-        self.access(|| {
-            blk(&Condvar {
-                sem: self,
-                order: Nothing,
-                nopod: marker::NoPod
-            })
-        })
-    }
-}
-
-/****************************************************************************
- * Semaphores
- ****************************************************************************/
-
-/// A counting, blocking, bounded-waiting semaphore.
-pub struct Semaphore { priv sem: Sem<()> }
-
-
-impl Clone for Semaphore {
-    /// Create a new handle to the semaphore.
-    fn clone(&self) -> Semaphore {
-        let Sem(ref lock) = self.sem;
-        Semaphore { sem: Sem(lock.clone()) }
-    }
-}
-
-impl Semaphore {
-    /// Create a new semaphore with the specified count.
-    pub fn new(count: int) -> Semaphore {
-        Semaphore { sem: Sem::new(count, ()) }
-    }
-
-    /**
-     * Acquire a resource represented by the semaphore. Blocks if necessary
-     * until resource(s) become available.
-     */
-    pub fn acquire(&self) { (&self.sem).acquire() }
-
-    /**
-     * Release a held resource represented by the semaphore. Wakes a blocked
-     * contending task, if any exist. Won't block the caller.
-     */
-    pub fn release(&self) { (&self.sem).release() }
-
-    /// Run a function with ownership of one of the semaphore's resources.
-    pub fn access<U>(&self, blk: || -> U) -> U { (&self.sem).access(blk) }
-}
-
-/****************************************************************************
- * Mutexes
- ****************************************************************************/
-
-/**
- * A blocking, bounded-waiting, mutual exclusion lock with an associated
- * FIFO condition variable.
- *
- * # Failure
- * A task which fails while holding a mutex will unlock the mutex as it
- * unwinds.
- */
-
-pub struct Mutex { priv sem: Sem<~[WaitQueue]> }
-impl Clone for Mutex {
-    /// Create a new handle to the mutex.
-    fn clone(&self) -> Mutex {
-        let Sem(ref queue) = self.sem;
-        Mutex { sem: Sem(queue.clone()) } }
-}
-
-impl Mutex {
-    /// Create a new mutex, with one associated condvar.
-    pub fn new() -> Mutex { Mutex::new_with_condvars(1) }
-
-    /**
-    * Create a new mutex, with a specified number of associated condvars. This
-    * will allow calling wait_on/signal_on/broadcast_on with condvar IDs between
-    * 0 and num_condvars-1. (If num_condvars is 0, lock_cond will be allowed but
-    * any operations on the condvar will fail.)
-    */
-    pub fn new_with_condvars(num_condvars: uint) -> Mutex {
-        Mutex { sem: Sem::new_and_signal(1, num_condvars) }
-    }
-
-
-    /// Run a function with ownership of the mutex.
-    pub fn lock<U>(&self, blk: || -> U) -> U {
-        (&self.sem).access(blk)
-    }
-
-    /// Run a function with ownership of the mutex and a handle to a condvar.
-    pub fn lock_cond<U>(&self, blk: |c: &Condvar| -> U) -> U {
-        (&self.sem).access_cond(blk)
-    }
-}
-
-/****************************************************************************
- * Reader-writer locks
- ****************************************************************************/
-
-// NB: Wikipedia - Readers-writers_problem#The_third_readers-writers_problem
-
-#[doc(hidden)]
-struct RWLockInner {
-    // You might ask, "Why don't you need to use an atomic for the mode flag?"
-    // This flag affects the behaviour of readers (for plain readers, they
-    // assert on it; for downgraders, they use it to decide which mode to
-    // unlock for). Consider that the flag is only unset when the very last
-    // reader exits; therefore, it can never be unset during a reader/reader
-    // (or reader/downgrader) race.
-    // By the way, if we didn't care about the assert in the read unlock path,
-    // we could instead store the mode flag in write_downgrade's stack frame,
-    // and have the downgrade tokens store a reference to it.
-    read_mode:  bool,
-    // The only way the count flag is ever accessed is with xadd. Since it is
-    // a read-modify-write operation, multiple xadds on different cores will
-    // always be consistent with respect to each other, so a monotonic/relaxed
-    // consistency ordering suffices (i.e., no extra barriers are needed).
-    // FIXME(#6598): The atomics module has no relaxed ordering flag, so I use
-    // acquire/release orderings superfluously. Change these someday.
-    read_count: atomics::AtomicUint,
-}
-
-/**
- * A blocking, no-starvation, reader-writer lock with an associated condvar.
- *
- * # Failure
- * A task which fails while holding an rwlock will unlock the rwlock as it
- * unwinds.
- */
-pub struct RWLock {
-    priv order_lock:  Semaphore,
-    priv access_lock: Sem<~[WaitQueue]>,
-    priv state:       UnsafeArc<RWLockInner>,
-}
-
-impl RWLock {
-    /// Create a new rwlock, with one associated condvar.
-    pub fn new() -> RWLock { RWLock::new_with_condvars(1) }
-
-    /**
-    * Create a new rwlock, with a specified number of associated condvars.
-    * Similar to mutex_with_condvars.
-    */
-    pub fn new_with_condvars(num_condvars: uint) -> RWLock {
-        let state = UnsafeArc::new(RWLockInner {
-            read_mode:  false,
-            read_count: atomics::AtomicUint::new(0),
-        });
-        RWLock { order_lock:  Semaphore::new(1),
-                access_lock: Sem::new_and_signal(1, num_condvars),
-                state:       state, }
-    }
-
-    /// Create a new handle to the rwlock.
-    pub fn clone(&self) -> RWLock {
-        let Sem(ref access_lock_queue) = self.access_lock;
-        RWLock { order_lock:  (&(self.order_lock)).clone(),
-                 access_lock: Sem(access_lock_queue.clone()),
-                 state:       self.state.clone() }
-    }
-
-    /**
-     * Run a function with the rwlock in read mode. Calls to 'read' from other
-     * tasks may run concurrently with this one.
-     */
-    pub fn read<U>(&self, blk: || -> U) -> U {
-        unsafe {
-            (&self.order_lock).access(|| {
-                let state = &mut *self.state.get();
-                let old_count = state.read_count.fetch_add(1, atomics::Acquire);
-                if old_count == 0 {
-                    (&self.access_lock).acquire();
-                    state.read_mode = true;
-                }
-            });
-            (|| {
-                blk()
-            }).finally(|| {
-                let state = &mut *self.state.get();
-                assert!(state.read_mode);
-                let old_count = state.read_count.fetch_sub(1, atomics::Release);
-                assert!(old_count > 0);
-                if old_count == 1 {
-                    state.read_mode = false;
-                    // Note: this release used to be outside of a locked access
-                    // to exclusive-protected state. If this code is ever
-                    // converted back to such (instead of using atomic ops),
-                    // this access MUST NOT go inside the exclusive access.
-                    (&self.access_lock).release();
-                }
-            })
-        }
-    }
-
-    /**
-     * Run a function with the rwlock in write mode. No calls to 'read' or
-     * 'write' from other tasks will run concurrently with this one.
-     */
-    pub fn write<U>(&self, blk: || -> U) -> U {
-        (&self.order_lock).acquire();
-        (&self.access_lock).access(|| {
-            (&self.order_lock).release();
-            blk()
-        })
-    }
-
-    /**
-     * As write(), but also with a handle to a condvar. Waiting on this
-     * condvar will allow readers and writers alike to take the rwlock before
-     * the waiting task is signalled. (Note: a writer that waited and then
-     * was signalled might reacquire the lock before other waiting writers.)
-     */
-    pub fn write_cond<U>(&self, blk: |c: &Condvar| -> U) -> U {
-        // It's important to thread our order lock into the condvar, so that
-        // when a cond.wait() wakes up, it uses it while reacquiring the
-        // access lock. If we permitted a waking-up writer to "cut in line",
-        // there could arise a subtle race when a downgrader attempts to hand
-        // off the reader cloud lock to a waiting reader. This race is tested
-        // in arc.rs (test_rw_write_cond_downgrade_read_race) and looks like:
-        // T1 (writer)              T2 (downgrader)             T3 (reader)
-        // [in cond.wait()]
-        //                          [locks for writing]
-        //                          [holds access_lock]
-        // [is signalled, perhaps by
-        //  downgrader or a 4th thread]
-        // tries to lock access(!)
-        //                                                      lock order_lock
-        //                                                      xadd read_count[0->1]
-        //                                                      tries to lock access
-        //                          [downgrade]
-        //                          xadd read_count[1->2]
-        //                          unlock access
-        // Since T1 contended on the access lock before T3 did, it will steal
-        // the lock handoff. Adding order_lock in the condvar reacquire path
-        // solves this because T1 will hold order_lock while waiting on access,
-        // which will cause T3 to have to wait until T1 finishes its write,
-        // which can't happen until T2 finishes the downgrade-read entirely.
-        // The astute reader will also note that making waking writers use the
-        // order_lock is better for not starving readers.
-        (&self.order_lock).acquire();
-        (&self.access_lock).access_cond(|cond| {
-            (&self.order_lock).release();
-            let opt_lock = Just(&self.order_lock);
-            blk(&Condvar { sem: cond.sem, order: opt_lock,
-                           nopod: marker::NoPod })
-        })
-    }
-
-    /**
-     * As write(), but with the ability to atomically 'downgrade' the lock;
-     * i.e., to become a reader without letting other writers get the lock in
-     * the meantime (such as unlocking and then re-locking as a reader would
-     * do). The block takes a "write mode token" argument, which can be
-     * transformed into a "read mode token" by calling downgrade(). Example:
-     *
-     * # Example
-     *
-     * ```rust
-     * use extra::sync::RWLock;
-     *
-     * let lock = RWLock::new();
-     * lock.write_downgrade(|mut write_token| {
-     *     write_token.write_cond(|condvar| {
-     *         // ... exclusive access ...
-     *     });
-     *     let read_token = lock.downgrade(write_token);
-     *     read_token.read(|| {
-     *         // ... shared access ...
-     *     })
-     * })
-     * ```
-     */
-    pub fn write_downgrade<U>(&self, blk: |v: RWLockWriteMode| -> U) -> U {
-        // Implementation slightly different from the slicker 'write's above.
-        // The exit path is conditional on whether the caller downgrades.
-        (&self.order_lock).acquire();
-        (&self.access_lock).acquire();
-        (&self.order_lock).release();
-        (|| {
-            blk(RWLockWriteMode { lock: self, nopod: marker::NoPod })
-        }).finally(|| {
-            let writer_or_last_reader;
-            // Check if we're releasing from read mode or from write mode.
-            let state = unsafe { &mut *self.state.get() };
-            if state.read_mode {
-                // Releasing from read mode.
-                let old_count = state.read_count.fetch_sub(1, atomics::Release);
-                assert!(old_count > 0);
-                // Check if other readers remain.
-                if old_count == 1 {
-                    // Case 1: Writer downgraded & was the last reader
-                    writer_or_last_reader = true;
-                    state.read_mode = false;
-                } else {
-                    // Case 2: Writer downgraded & was not the last reader
-                    writer_or_last_reader = false;
-                }
-            } else {
-                // Case 3: Writer did not downgrade
-                writer_or_last_reader = true;
-            }
-            if writer_or_last_reader {
-                // Nobody left inside; release the "reader cloud" lock.
-                (&self.access_lock).release();
-            }
-        })
-    }
-
-    /// To be called inside of the write_downgrade block.
-    pub fn downgrade<'a>(&self, token: RWLockWriteMode<'a>)
-                         -> RWLockReadMode<'a> {
-        if !((self as *RWLock) == (token.lock as *RWLock)) {
-            fail!("Can't downgrade() with a different rwlock's write_mode!");
-        }
-        unsafe {
-            let state = &mut *self.state.get();
-            assert!(!state.read_mode);
-            state.read_mode = true;
-            // If a reader attempts to enter at this point, both the
-            // downgrader and reader will set the mode flag. This is fine.
-            let old_count = state.read_count.fetch_add(1, atomics::Release);
-            // If another reader was already blocking, we need to hand-off
-            // the "reader cloud" access lock to them.
-            if old_count != 0 {
-                // Guaranteed not to let another writer in, because
-                // another reader was holding the order_lock. Hence they
-                // must be the one to get the access_lock (because all
-                // access_locks are acquired with order_lock held). See
-                // the comment in write_cond for more justification.
-                (&self.access_lock).release();
-            }
-        }
-        RWLockReadMode { lock: token.lock, nopod: marker::NoPod }
-    }
-}
-
-/// The "write permission" token used for rwlock.write_downgrade().
-
-pub struct RWLockWriteMode<'a> { priv lock: &'a RWLock, priv nopod: marker::NoPod }
-/// The "read permission" token used for rwlock.write_downgrade().
-pub struct RWLockReadMode<'a> { priv lock: &'a RWLock,
-                                   priv nopod: marker::NoPod }
-
-impl<'a> RWLockWriteMode<'a> {
-    /// Access the pre-downgrade rwlock in write mode.
-    pub fn write<U>(&self, blk: || -> U) -> U { blk() }
-    /// Access the pre-downgrade rwlock in write mode with a condvar.
-    pub fn write_cond<U>(&self, blk: |c: &Condvar| -> U) -> U {
-        // Need to make the condvar use the order lock when reacquiring the
-        // access lock. See comment in RWLock::write_cond for why.
-        blk(&Condvar { sem:        &self.lock.access_lock,
-                       order: Just(&self.lock.order_lock),
-                       nopod: marker::NoPod })
-    }
-}
-
-impl<'a> RWLockReadMode<'a> {
-    /// Access the post-downgrade rwlock in read mode.
-    pub fn read<U>(&self, blk: || -> U) -> U { blk() }
-}
-
-/// A barrier enables multiple tasks to synchronize the beginning
-/// of some computation.
-///
-/// ```rust
-/// use extra::sync::Barrier;
-///
-/// let barrier = Barrier::new(10);
-/// for _ in range(0, 10) {
-///     let c = barrier.clone();
-///     // The same messages will be printed together.
-///     // You will NOT see any interleaving.
-///     spawn(proc() {
-///         println!("before wait");
-///         c.wait();
-///         println!("after wait");
-///     });
-/// }
-/// ```
-#[deriving(Clone)]
-pub struct Barrier {
-    priv arc: MutexArc<BarrierState>,
-    priv num_tasks: uint,
-}
-
-// The inner state of a double barrier
-struct BarrierState {
-    count: uint,
-    generation_id: uint,
-}
-
-impl Barrier {
-    /// Create a new barrier that can block a given number of tasks.
-    pub fn new(num_tasks: uint) -> Barrier {
-        Barrier {
-            arc: MutexArc::new(BarrierState {
-                count: 0,
-                generation_id: 0,
-            }),
-            num_tasks: num_tasks,
-        }
-    }
-
-    /// Block the current task until a certain number of tasks is waiting.
-    pub fn wait(&self) {
-        self.arc.access_cond(|state, cond| {
-            let local_gen = state.generation_id;
-            state.count += 1;
-            if state.count < self.num_tasks {
-                // We need a while loop to guard against spurious wakeups.
-                // http://en.wikipedia.org/wiki/Spurious_wakeup
-                while local_gen == state.generation_id && state.count < self.num_tasks {
-                    cond.wait();
-                }
-            } else {
-                state.count = 0;
-                state.generation_id += 1;
-                cond.broadcast();
-            }
-        });
-    }
-}
-
-/****************************************************************************
- * Tests
- ****************************************************************************/
-
-#[cfg(test)]
-mod tests {
-    use sync::*;
-
-    use std::cast;
-    use std::result;
-    use std::task;
-    use std::comm::{SharedChan, Empty};
-
-    /************************************************************************
-     * Semaphore tests
-     ************************************************************************/
-    #[test]
-    fn test_sem_acquire_release() {
-        let s = Semaphore::new(1);
-        s.acquire();
-        s.release();
-        s.acquire();
-    }
-    #[test]
-    fn test_sem_basic() {
-        let s = Semaphore::new(1);
-        s.access(|| { })
-    }
-    #[test]
-    fn test_sem_as_mutex() {
-        let s = Semaphore::new(1);
-        let s2 = s.clone();
-        task::spawn(proc() {
-            s2.access(|| {
-                for _ in range(0, 5) { task::deschedule(); }
-            })
-        });
-        s.access(|| {
-            for _ in range(0, 5) { task::deschedule(); }
-        })
-    }
-    #[test]
-    fn test_sem_as_cvar() {
-        /* Child waits and parent signals */
-        let (p, c) = Chan::new();
-        let s = Semaphore::new(0);
-        let s2 = s.clone();
-        task::spawn(proc() {
-            s2.acquire();
-            c.send(());
-        });
-        for _ in range(0, 5) { task::deschedule(); }
-        s.release();
-        let _ = p.recv();
-
-        /* Parent waits and child signals */
-        let (p, c) = Chan::new();
-        let s = Semaphore::new(0);
-        let s2 = s.clone();
-        task::spawn(proc() {
-            for _ in range(0, 5) { task::deschedule(); }
-            s2.release();
-            let _ = p.recv();
-        });
-        s.acquire();
-        c.send(());
-    }
-    #[test]
-    fn test_sem_multi_resource() {
-        // Parent and child both get in the critical section at the same
-        // time, and shake hands.
-        let s = Semaphore::new(2);
-        let s2 = s.clone();
-        let (p1,c1) = Chan::new();
-        let (p2,c2) = Chan::new();
-        task::spawn(proc() {
-            s2.access(|| {
-                let _ = p2.recv();
-                c1.send(());
-            })
-        });
-        s.access(|| {
-            c2.send(());
-            let _ = p1.recv();
-        })
-    }
-    #[test]
-    fn test_sem_runtime_friendly_blocking() {
-        // Force the runtime to schedule two threads on the same sched_loop.
-        // When one blocks, it should schedule the other one.
-        let s = Semaphore::new(1);
-        let s2 = s.clone();
-        let (p, c) = Chan::new();
-        let mut child_data = Some((s2, c));
-        s.access(|| {
-            let (s2, c) = child_data.take_unwrap();
-            task::spawn(proc() {
-                c.send(());
-                s2.access(|| { });
-                c.send(());
-            });
-            let _ = p.recv(); // wait for child to come alive
-            for _ in range(0, 5) { task::deschedule(); } // let the child contend
-        });
-        let _ = p.recv(); // wait for child to be done
-    }
-    /************************************************************************
-     * Mutex tests
-     ************************************************************************/
-    #[test]
-    fn test_mutex_lock() {
-        // Unsafely achieve shared state, and do the textbook
-        // "load tmp = move ptr; inc tmp; store ptr <- tmp" dance.
-        let (p, c) = Chan::new();
-        let m = Mutex::new();
-        let m2 = m.clone();
-        let mut sharedstate = ~0;
-        {
-            let ptr: *int = &*sharedstate;
-            task::spawn(proc() {
-                let sharedstate: &mut int =
-                    unsafe { cast::transmute(ptr) };
-                access_shared(sharedstate, &m2, 10);
-                c.send(());
-            });
-        }
-        {
-            access_shared(sharedstate, &m, 10);
-            let _ = p.recv();
-
-            assert_eq!(*sharedstate, 20);
-        }
-
-        fn access_shared(sharedstate: &mut int, m: &Mutex, n: uint) {
-            for _ in range(0, n) {
-                m.lock(|| {
-                    let oldval = *sharedstate;
-                    task::deschedule();
-                    *sharedstate = oldval + 1;
-                })
-            }
-        }
-    }
-    #[test]
-    fn test_mutex_cond_wait() {
-        let m = Mutex::new();
-
-        // Child wakes up parent
-        m.lock_cond(|cond| {
-            let m2 = m.clone();
-            task::spawn(proc() {
-                m2.lock_cond(|cond| {
-                    let woken = cond.signal();
-                    assert!(woken);
-                })
-            });
-            cond.wait();
-        });
-        // Parent wakes up child
-        let (port,chan) = Chan::new();
-        let m3 = m.clone();
-        task::spawn(proc() {
-            m3.lock_cond(|cond| {
-                chan.send(());
-                cond.wait();
-                chan.send(());
-            })
-        });
-        let _ = port.recv(); // Wait until child gets in the mutex
-        m.lock_cond(|cond| {
-            let woken = cond.signal();
-            assert!(woken);
-        });
-        let _ = port.recv(); // Wait until child wakes up
-    }
-    #[cfg(test)]
-    fn test_mutex_cond_broadcast_helper(num_waiters: uint) {
-        let m = Mutex::new();
-        let mut ports = ~[];
-
-        for _ in range(0, num_waiters) {
-            let mi = m.clone();
-            let (port, chan) = Chan::new();
-            ports.push(port);
-            task::spawn(proc() {
-                mi.lock_cond(|cond| {
-                    chan.send(());
-                    cond.wait();
-                    chan.send(());
-                })
-            });
-        }
-
-        // wait until all children get in the mutex
-        for port in ports.mut_iter() { let _ = port.recv(); }
-        m.lock_cond(|cond| {
-            let num_woken = cond.broadcast();
-            assert_eq!(num_woken, num_waiters);
-        });
-        // wait until all children wake up
-        for port in ports.mut_iter() { let _ = port.recv(); }
-    }
-    #[test]
-    fn test_mutex_cond_broadcast() {
-        test_mutex_cond_broadcast_helper(12);
-    }
-    #[test]
-    fn test_mutex_cond_broadcast_none() {
-        test_mutex_cond_broadcast_helper(0);
-    }
-    #[test]
-    fn test_mutex_cond_no_waiter() {
-        let m = Mutex::new();
-        let m2 = m.clone();
-        let _ = task::try(proc() {
-            m.lock_cond(|_x| { })
-        });
-        m2.lock_cond(|cond| {
-            assert!(!cond.signal());
-        })
-    }
-    #[test]
-    fn test_mutex_killed_simple() {
-        // Mutex must get automatically unlocked if failed/killed within.
-        let m = Mutex::new();
-        let m2 = m.clone();
-
-        let result: result::Result<(), ~Any> = task::try(proc() {
-            m2.lock(|| {
-                fail!();
-            })
-        });
-        assert!(result.is_err());
-        // child task must have finished by the time try returns
-        m.lock(|| { })
-    }
-    #[ignore(reason = "linked failure")]
-    #[test]
-    fn test_mutex_killed_cond() {
-        // Getting killed during cond wait must not corrupt the mutex while
-        // unwinding (e.g. double unlock).
-        let m = Mutex::new();
-        let m2 = m.clone();
-
-        let result: result::Result<(), ~Any> = task::try(proc() {
-            let (p, c) = Chan::new();
-            task::spawn(proc() { // linked
-                let _ = p.recv(); // wait for sibling to get in the mutex
-                task::deschedule();
-                fail!();
-            });
-            m2.lock_cond(|cond| {
-                c.send(()); // tell sibling go ahead
-                cond.wait(); // block forever
-            })
-        });
-        assert!(result.is_err());
-        // child task must have finished by the time try returns
-        m.lock_cond(|cond| {
-            let woken = cond.signal();
-            assert!(!woken);
-        })
-    }
-    #[ignore(reason = "linked failure")]
-    #[test]
-    fn test_mutex_killed_broadcast() {
-        use std::unstable::finally::Finally;
-
-        let m = Mutex::new();
-        let m2 = m.clone();
-        let (p, c) = Chan::new();
-
-        let result: result::Result<(), ~Any> = task::try(proc() {
-            let mut sibling_convos = ~[];
-            for _ in range(0, 2) {
-                let (p, c) = Chan::new();
-                sibling_convos.push(p);
-                let mi = m2.clone();
-                // spawn sibling task
-                task::spawn(proc() { // linked
-                    mi.lock_cond(|cond| {
-                        c.send(()); // tell sibling to go ahead
-                        (|| {
-                            cond.wait(); // block forever
-                        }).finally(|| {
-                            error!("task unwinding and sending");
-                            c.send(());
-                            error!("task unwinding and done sending");
-                        })
-                    })
-                });
-            }
-            for p in sibling_convos.mut_iter() {
-                let _ = p.recv(); // wait for sibling to get in the mutex
-            }
-            m2.lock(|| { });
-            c.send(sibling_convos); // let parent wait on all children
-            fail!();
-        });
-        assert!(result.is_err());
-        // child task must have finished by the time try returns
-        let mut r = p.recv();
-        for p in r.mut_iter() { p.recv(); } // wait on all its siblings
-        m.lock_cond(|cond| {
-            let woken = cond.broadcast();
-            assert_eq!(woken, 0);
-        })
-    }
-    #[test]
-    fn test_mutex_cond_signal_on_0() {
-        // Tests that signal_on(0) is equivalent to signal().
-        let m = Mutex::new();
-        m.lock_cond(|cond| {
-            let m2 = m.clone();
-            task::spawn(proc() {
-                m2.lock_cond(|cond| {
-                    cond.signal_on(0);
-                })
-            });
-            cond.wait();
-        })
-    }
-    #[test]
-    #[ignore(reason = "linked failure?")]
-    fn test_mutex_different_conds() {
-        let result = task::try(proc() {
-            let m = Mutex::new_with_condvars(2);
-            let m2 = m.clone();
-            let (p, c) = Chan::new();
-            task::spawn(proc() {
-                m2.lock_cond(|cond| {
-                    c.send(());
-                    cond.wait_on(1);
-                })
-            });
-            let _ = p.recv();
-            m.lock_cond(|cond| {
-                if !cond.signal_on(0) {
-                    fail!(); // success; punt sibling awake.
-                }
-            })
-        });
-        assert!(result.is_err());
-    }
-    #[test]
-    fn test_mutex_no_condvars() {
-        let result = task::try(proc() {
-            let m = Mutex::new_with_condvars(0);
-            m.lock_cond(|cond| { cond.wait(); })
-        });
-        assert!(result.is_err());
-        let result = task::try(proc() {
-            let m = Mutex::new_with_condvars(0);
-            m.lock_cond(|cond| { cond.signal(); })
-        });
-        assert!(result.is_err());
-        let result = task::try(proc() {
-            let m = Mutex::new_with_condvars(0);
-            m.lock_cond(|cond| { cond.broadcast(); })
-        });
-        assert!(result.is_err());
-    }
-    /************************************************************************
-     * Reader/writer lock tests
-     ************************************************************************/
-    #[cfg(test)]
-    pub enum RWLockMode { Read, Write, Downgrade, DowngradeRead }
-    #[cfg(test)]
-    fn lock_rwlock_in_mode(x: &RWLock, mode: RWLockMode, blk: ||) {
-        match mode {
-            Read => x.read(blk),
-            Write => x.write(blk),
-            Downgrade =>
-                x.write_downgrade(|mode| {
-                    mode.write(|| { blk() });
-                }),
-            DowngradeRead =>
-                x.write_downgrade(|mode| {
-                    let mode = x.downgrade(mode);
-                    mode.read(|| { blk() });
-                }),
-        }
-    }
-    #[cfg(test)]
-    fn test_rwlock_exclusion(x: &RWLock,
-                                 mode1: RWLockMode,
-                                 mode2: RWLockMode) {
-        // Test mutual exclusion between readers and writers. Just like the
-        // mutex mutual exclusion test, a ways above.
-        let (p, c) = Chan::new();
-        let x2 = x.clone();
-        let mut sharedstate = ~0;
-        {
-            let ptr: *int = &*sharedstate;
-            task::spawn(proc() {
-                let sharedstate: &mut int =
-                    unsafe { cast::transmute(ptr) };
-                access_shared(sharedstate, &x2, mode1, 10);
-                c.send(());
-            });
-        }
-        {
-            access_shared(sharedstate, x, mode2, 10);
-            let _ = p.recv();
-
-            assert_eq!(*sharedstate, 20);
-        }
-
-        fn access_shared(sharedstate: &mut int, x: &RWLock, mode: RWLockMode,
-                         n: uint) {
-            for _ in range(0, n) {
-                lock_rwlock_in_mode(x, mode, || {
-                    let oldval = *sharedstate;
-                    task::deschedule();
-                    *sharedstate = oldval + 1;
-                })
-            }
-        }
-    }
-    #[test]
-    fn test_rwlock_readers_wont_modify_the_data() {
-        test_rwlock_exclusion(&RWLock::new(), Read, Write);
-        test_rwlock_exclusion(&RWLock::new(), Write, Read);
-        test_rwlock_exclusion(&RWLock::new(), Read, Downgrade);
-        test_rwlock_exclusion(&RWLock::new(), Downgrade, Read);
-    }
-    #[test]
-    fn test_rwlock_writers_and_writers() {
-        test_rwlock_exclusion(&RWLock::new(), Write, Write);
-        test_rwlock_exclusion(&RWLock::new(), Write, Downgrade);
-        test_rwlock_exclusion(&RWLock::new(), Downgrade, Write);
-        test_rwlock_exclusion(&RWLock::new(), Downgrade, Downgrade);
-    }
-    #[cfg(test)]
-    fn test_rwlock_handshake(x: &RWLock,
-                                 mode1: RWLockMode,
-                                 mode2: RWLockMode,
-                                 make_mode2_go_first: bool) {
-        // Much like sem_multi_resource.
-        let x2 = x.clone();
-        let (p1, c1) = Chan::new();
-        let (p2, c2) = Chan::new();
-        task::spawn(proc() {
-            if !make_mode2_go_first {
-                let _ = p2.recv(); // parent sends to us once it locks, or ...
-            }
-            lock_rwlock_in_mode(&x2, mode2, || {
-                if make_mode2_go_first {
-                    c1.send(()); // ... we send to it once we lock
-                }
-                let _ = p2.recv();
-                c1.send(());
-            })
-        });
-        if make_mode2_go_first {
-            let _ = p1.recv(); // child sends to us once it locks, or ...
-        }
-        lock_rwlock_in_mode(x, mode1, || {
-            if !make_mode2_go_first {
-                c2.send(()); // ... we send to it once we lock
-            }
-            c2.send(());
-            let _ = p1.recv();
-        })
-    }
-    #[test]
-    fn test_rwlock_readers_and_readers() {
-        test_rwlock_handshake(&RWLock::new(), Read, Read, false);
-        // The downgrader needs to get in before the reader gets in, otherwise
-        // they cannot end up reading at the same time.
-        test_rwlock_handshake(&RWLock::new(), DowngradeRead, Read, false);
-        test_rwlock_handshake(&RWLock::new(), Read, DowngradeRead, true);
-        // Two downgrade_reads can never both end up reading at the same time.
-    }
-    #[test]
-    fn test_rwlock_downgrade_unlock() {
-        // Tests that downgrade can unlock the lock in both modes
-        let x = RWLock::new();
-        lock_rwlock_in_mode(&x, Downgrade, || { });
-        test_rwlock_handshake(&x, Read, Read, false);
-        let y = RWLock::new();
-        lock_rwlock_in_mode(&y, DowngradeRead, || { });
-        test_rwlock_exclusion(&y, Write, Write);
-    }
-    #[test]
-    fn test_rwlock_read_recursive() {
-        let x = RWLock::new();
-        x.read(|| { x.read(|| { }) })
-    }
-    #[test]
-    fn test_rwlock_cond_wait() {
-        // As test_mutex_cond_wait above.
-        let x = RWLock::new();
-
-        // Child wakes up parent
-        x.write_cond(|cond| {
-            let x2 = x.clone();
-            task::spawn(proc() {
-                x2.write_cond(|cond| {
-                    let woken = cond.signal();
-                    assert!(woken);
-                })
-            });
-            cond.wait();
-        });
-        // Parent wakes up child
-        let (port, chan) = Chan::new();
-        let x3 = x.clone();
-        task::spawn(proc() {
-            x3.write_cond(|cond| {
-                chan.send(());
-                cond.wait();
-                chan.send(());
-            })
-        });
-        let _ = port.recv(); // Wait until child gets in the rwlock
-        x.read(|| { }); // Must be able to get in as a reader in the meantime
-        x.write_cond(|cond| { // Or as another writer
-            let woken = cond.signal();
-            assert!(woken);
-        });
-        let _ = port.recv(); // Wait until child wakes up
-        x.read(|| { }); // Just for good measure
-    }
-    #[cfg(test)]
-    fn test_rwlock_cond_broadcast_helper(num_waiters: uint,
-                                             dg1: bool,
-                                             dg2: bool) {
-        // Much like the mutex broadcast test. Downgrade-enabled.
-        fn lock_cond(x: &RWLock, downgrade: bool, blk: |c: &Condvar|) {
-            if downgrade {
-                x.write_downgrade(|mode| {
-                    mode.write_cond(|c| { blk(c) });
-                });
-            } else {
-                x.write_cond(|c| { blk(c) });
-            }
-        }
-        let x = RWLock::new();
-        let mut ports = ~[];
-
-        for _ in range(0, num_waiters) {
-            let xi = x.clone();
-            let (port, chan) = Chan::new();
-            ports.push(port);
-            task::spawn(proc() {
-                lock_cond(&xi, dg1, |cond| {
-                    chan.send(());
-                    cond.wait();
-                    chan.send(());
-                })
-            });
-        }
-
-        // wait until all children get in the mutex
-        for port in ports.mut_iter() { let _ = port.recv(); }
-        lock_cond(&x, dg2, |cond| {
-            let num_woken = cond.broadcast();
-            assert_eq!(num_woken, num_waiters);
-        });
-        // wait until all children wake up
-        for port in ports.mut_iter() { let _ = port.recv(); }
-    }
-    #[test]
-    fn test_rwlock_cond_broadcast() {
-        test_rwlock_cond_broadcast_helper(0, true, true);
-        test_rwlock_cond_broadcast_helper(0, true, false);
-        test_rwlock_cond_broadcast_helper(0, false, true);
-        test_rwlock_cond_broadcast_helper(0, false, false);
-        test_rwlock_cond_broadcast_helper(12, true, true);
-        test_rwlock_cond_broadcast_helper(12, true, false);
-        test_rwlock_cond_broadcast_helper(12, false, true);
-        test_rwlock_cond_broadcast_helper(12, false, false);
-    }
-    #[cfg(test)]
-    fn rwlock_kill_helper(mode1: RWLockMode, mode2: RWLockMode) {
-        // Mutex must get automatically unlocked if failed/killed within.
-        let x = RWLock::new();
-        let x2 = x.clone();
-
-        let result: result::Result<(), ~Any> = task::try(proc() {
-            lock_rwlock_in_mode(&x2, mode1, || {
-                fail!();
-            })
-        });
-        assert!(result.is_err());
-        // child task must have finished by the time try returns
-        lock_rwlock_in_mode(&x, mode2, || { })
-    }
-    #[test]
-    fn test_rwlock_reader_killed_writer() {
-        rwlock_kill_helper(Read, Write);
-    }
-    #[test]
-    fn test_rwlock_writer_killed_reader() {
-        rwlock_kill_helper(Write, Read);
-    }
-    #[test]
-    fn test_rwlock_reader_killed_reader() {
-        rwlock_kill_helper(Read, Read);
-    }
-    #[test]
-    fn test_rwlock_writer_killed_writer() {
-        rwlock_kill_helper(Write, Write);
-    }
-    #[test]
-    fn test_rwlock_kill_downgrader() {
-        rwlock_kill_helper(Downgrade, Read);
-        rwlock_kill_helper(Read, Downgrade);
-        rwlock_kill_helper(Downgrade, Write);
-        rwlock_kill_helper(Write, Downgrade);
-        rwlock_kill_helper(DowngradeRead, Read);
-        rwlock_kill_helper(Read, DowngradeRead);
-        rwlock_kill_helper(DowngradeRead, Write);
-        rwlock_kill_helper(Write, DowngradeRead);
-        rwlock_kill_helper(DowngradeRead, Downgrade);
-        rwlock_kill_helper(DowngradeRead, Downgrade);
-        rwlock_kill_helper(Downgrade, DowngradeRead);
-        rwlock_kill_helper(Downgrade, DowngradeRead);
-    }
-    #[test] #[should_fail]
-    fn test_rwlock_downgrade_cant_swap() {
-        // Tests that you can't downgrade with a different rwlock's token.
-        let x = RWLock::new();
-        let y = RWLock::new();
-        x.write_downgrade(|xwrite| {
-            let mut xopt = Some(xwrite);
-            y.write_downgrade(|_ywrite| {
-                y.downgrade(xopt.take_unwrap());
-                error!("oops, y.downgrade(x) should have failed!");
-            })
-        })
-    }
-
-    /************************************************************************
-     * Barrier tests
-     ************************************************************************/
-    #[test]
-    fn test_barrier() {
-        let barrier = Barrier::new(10);
-        let (port, chan) = SharedChan::new();
-
-        for _ in range(0, 9) {
-            let c = barrier.clone();
-            let chan = chan.clone();
-            spawn(proc() {
-                c.wait();
-                chan.send(true);
-            });
-        }
-
-        // At this point, all spawned tasks should be blocked,
-        // so we shouldn't get anything from the port
-        assert!(match port.try_recv() {
-            Empty => true,
-            _ => false,
-        });
-
-        barrier.wait();
-        // Now, the barrier is cleared and we should get data.
-        for _ in range(0, 9) {
-            port.recv();
-        }
-    }
-}
diff --git a/src/libextra/sync/mpsc_intrusive.rs b/src/libextra/sync/mpsc_intrusive.rs
deleted file mode 100644 (file)
index 0f13a49..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-/* Copyright (c) 2010-2011 Dmitry Vyukov. All rights reserved.
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- *    1. Redistributions of source code must retain the above copyright notice,
- *       this list of conditions and the following disclaimer.
- *
- *    2. Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY DMITRY VYUKOV "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL DMITRY VYUKOV OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
- * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and documentation are
- * those of the authors and should not be interpreted as representing official
- * policies, either expressed or implied, of Dmitry Vyukov.
- */
-
-//! A mostly lock-free multi-producer, single consumer queue.
-//!
-//! This module implements an intrusive MPSC queue. This queue is incredibly
-//! unsafe (due to use of unsafe pointers for nodes), and hence is not public.
-
-// http://www.1024cores.net/home/lock-free-algorithms
-//                         /queues/intrusive-mpsc-node-based-queue
-
-use std::cast;
-use std::sync::atomics;
-
-// NB: all links are done as AtomicUint instead of AtomicPtr to allow for static
-// initialization.
-
-pub struct Node<T> {
-    next: atomics::AtomicUint,
-    data: T,
-}
-
-pub struct DummyNode {
-    next: atomics::AtomicUint,
-}
-
-pub struct Queue<T> {
-    head: atomics::AtomicUint,
-    tail: *mut Node<T>,
-    stub: DummyNode,
-}
-
-impl<T: Send> Queue<T> {
-    pub fn new() -> Queue<T> {
-        Queue {
-            head: atomics::AtomicUint::new(0),
-            tail: 0 as *mut Node<T>,
-            stub: DummyNode {
-                next: atomics::AtomicUint::new(0),
-            },
-        }
-    }
-
-    pub unsafe fn push(&mut self, node: *mut Node<T>) {
-        (*node).next.store(0, atomics::Release);
-        let prev = self.head.swap(node as uint, atomics::AcqRel);
-
-        // Note that this code is slightly modified to allow static
-        // initialization of these queues with rust's flavor of static
-        // initialization.
-        if prev == 0 {
-            self.stub.next.store(node as uint, atomics::Release);
-        } else {
-            let prev = prev as *mut Node<T>;
-            (*prev).next.store(node as uint, atomics::Release);
-        }
-    }
-
-    /// You'll note that the other MPSC queue in std::sync is non-intrusive and
-    /// returns a `PopResult` here to indicate when the queue is inconsistent.
-    /// An "inconsistent state" in the other queue means that a pusher has
-    /// pushed, but it hasn't finished linking the rest of the chain.
-    ///
-    /// This queue also suffers from this problem, but I currently haven't been
-    /// able to detangle when this actually happens. This code is translated
-    /// verbatim from the website above, and is more complicated than the
-    /// non-intrusive version.
-    ///
-    /// Right now consumers of this queue must be ready for this fact. Just
-    /// because `pop` returns `None` does not mean that there is not data
-    /// on the queue.
-    pub unsafe fn pop(&mut self) -> Option<*mut Node<T>> {
-        let tail = self.tail;
-        let mut tail = if !tail.is_null() {tail} else {
-            cast::transmute(&self.stub)
-        };
-        let mut next = (*tail).next(atomics::Relaxed);
-        if tail as uint == &self.stub as *DummyNode as uint {
-            if next.is_null() {
-                return None;
-            }
-            self.tail = next;
-            tail = next;
-            next = (*next).next(atomics::Relaxed);
-        }
-        if !next.is_null() {
-            self.tail = next;
-            return Some(tail);
-        }
-        let head = self.head.load(atomics::Acquire) as *mut Node<T>;
-        if tail != head {
-            return None;
-        }
-        let stub = cast::transmute(&self.stub);
-        self.push(stub);
-        next = (*tail).next(atomics::Relaxed);
-        if !next.is_null() {
-            self.tail = next;
-            return Some(tail);
-        }
-        return None
-    }
-}
-
-impl<T: Send> Node<T> {
-    pub fn new(t: T) -> Node<T> {
-        Node {
-            data: t,
-            next: atomics::AtomicUint::new(0),
-        }
-    }
-    pub unsafe fn next(&mut self, ord: atomics::Ordering) -> *mut Node<T> {
-        cast::transmute::<uint, *mut Node<T>>(self.next.load(ord))
-    }
-}
diff --git a/src/libextra/sync/mutex.rs b/src/libextra/sync/mutex.rs
deleted file mode 100644 (file)
index 7ea98c0..0000000
+++ /dev/null
@@ -1,557 +0,0 @@
-// Copyright 2014 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.
-
-//! A proper mutex implementation regardless of the "flavor of task" which is
-//! acquiring the lock.
-
-// # Implementation of Rust mutexes
-//
-// Most answers to the question of "how do I use a mutex" are "use pthreads",
-// but for Rust this isn't quite sufficient. Green threads cannot acquire an OS
-// mutex because they can context switch among many OS threads, leading to
-// deadlocks with other green threads.
-//
-// Another problem for green threads grabbing an OS mutex is that POSIX dictates
-// that unlocking a mutex on a different thread from where it was locked is
-// undefined behavior. Remember that green threads can migrate among OS threads,
-// so this would mean that we would have to pin green threads to OS threads,
-// which is less than ideal.
-//
-// ## Using deschedule/reawaken
-//
-// We already have primitives for descheduling/reawakening tasks, so they're the
-// first obvious choice when implementing a mutex. The idea would be to have a
-// concurrent queue that everyone is pushed on to, and then the owner of the
-// mutex is the one popping from the queue.
-//
-// Unfortunately, this is not very performant for native tasks. The suspected
-// reason for this is that each native thread is suspended on its own condition
-// variable, unique from all the other threads. In this situation, the kernel
-// has no idea what the scheduling semantics are of the user program, so all of
-// the threads are distributed among all cores on the system. This ends up
-// having very expensive wakeups of remote cores high up in the profile when
-// handing off the mutex among native tasks. On the other hand, when using an OS
-// mutex, the kernel knows that all native threads are contended on the same
-// mutex, so they're in theory all migrated to a single core (fast context
-// switching).
-//
-// ## Mixing implementations
-//
-// From that above information, we have two constraints. The first is that
-// green threads can't touch os mutexes, and the second is that native tasks
-// pretty much *must* touch an os mutex.
-//
-// As a compromise, the queueing implementation is used for green threads and
-// the os mutex is used for native threads (why not have both?). This ends up
-// leading to fairly decent performance for both native threads and green
-// threads on various workloads (uncontended and contended).
-//
-// The crux of this implementation is an atomic work which is CAS'd on many many
-// times in order to manage a few flags about who's blocking where and whether
-// it's locked or not.
-
-use std::rt::local::Local;
-use std::rt::task::{BlockedTask, Task};
-use std::rt::thread::Thread;
-use std::sync::atomics;
-use std::unstable::mutex;
-
-use q = sync::mpsc_intrusive;
-
-pub static LOCKED: uint = 1 << 0;
-pub static GREEN_BLOCKED: uint = 1 << 1;
-pub static NATIVE_BLOCKED: uint = 1 << 2;
-
-/// A mutual exclusion primitive useful for protecting shared data
-///
-/// This mutex is an implementation of a lock for all flavors of tasks which may
-/// be grabbing. A common problem with green threads is that they cannot grab
-/// locks (if they reschedule during the lock a contender could deadlock the
-/// system), but this mutex does *not* suffer this problem.
-///
-/// This mutex will properly block tasks waiting for the lock to become
-/// available. The mutex can also be statically initialized or created via a
-/// `new` constructor.
-///
-/// # Example
-///
-/// ```rust
-/// use extra::sync::mutex::Mutex;
-///
-/// let mut m = Mutex::new();
-/// let guard = m.lock();
-/// // do some work
-/// drop(guard); // unlock the lock
-/// ```
-pub struct Mutex {
-    priv lock: StaticMutex,
-}
-
-#[deriving(Eq)]
-enum Flavor {
-    Unlocked,
-    TryLockAcquisition,
-    GreenAcquisition,
-    NativeAcquisition,
-}
-
-/// The static mutex type is provided to allow for static allocation of mutexes.
-///
-/// Note that this is a separate type because using a Mutex correctly means that
-/// it needs to have a destructor run. In Rust, statics are not allowed to have
-/// destructors. As a result, a `StaticMutex` has one extra method when compared
-/// to a `Mutex`, a `destroy` method. This method is unsafe to call, and
-/// documentation can be found directly on the method.
-///
-/// # Example
-///
-/// ```rust
-/// use extra::sync::mutex::{StaticMutex, MUTEX_INIT};
-///
-/// static mut LOCK: StaticMutex = MUTEX_INIT;
-///
-/// unsafe {
-///     let _g = LOCK.lock();
-///     // do some productive work
-/// }
-/// // lock is unlocked here.
-/// ```
-pub struct StaticMutex {
-    /// Current set of flags on this mutex
-    priv state: atomics::AtomicUint,
-    /// Type of locking operation currently on this mutex
-    priv flavor: Flavor,
-    /// uint-cast of the green thread waiting for this mutex
-    priv green_blocker: uint,
-    /// uint-cast of the native thread waiting for this mutex
-    priv native_blocker: uint,
-    /// an OS mutex used by native threads
-    priv lock: mutex::Mutex,
-
-    /// A concurrent mpsc queue used by green threads, along with a count used
-    /// to figure out when to dequeue and enqueue.
-    priv q: q::Queue<uint>,
-    priv green_cnt: atomics::AtomicUint,
-}
-
-/// An RAII implementation of a "scoped lock" of a mutex. When this structure is
-/// dropped (falls out of scope), the lock will be unlocked.
-pub struct Guard<'a> {
-    priv lock: &'a mut StaticMutex,
-}
-
-/// Static initialization of a mutex. This constant can be used to initialize
-/// other mutex constants.
-pub static MUTEX_INIT: StaticMutex = StaticMutex {
-    lock: mutex::MUTEX_INIT,
-    state: atomics::INIT_ATOMIC_UINT,
-    flavor: Unlocked,
-    green_blocker: 0,
-    native_blocker: 0,
-    green_cnt: atomics::INIT_ATOMIC_UINT,
-    q: q::Queue {
-        head: atomics::INIT_ATOMIC_UINT,
-        tail: 0 as *mut q::Node<uint>,
-        stub: q::DummyNode {
-            next: atomics::INIT_ATOMIC_UINT,
-        }
-    }
-};
-
-impl StaticMutex {
-    /// Attempts to grab this lock, see `Mutex::try_lock`
-    pub fn try_lock<'a>(&'a mut self) -> Option<Guard<'a>> {
-        // Attempt to steal the mutex from an unlocked state.
-        //
-        // FIXME: this can mess up the fairness of the mutex, seems bad
-        match self.state.compare_and_swap(0, LOCKED, atomics::SeqCst) {
-            0 => {
-                assert!(self.flavor == Unlocked);
-                self.flavor = TryLockAcquisition;
-                Some(Guard::new(self))
-            }
-            _ => None
-        }
-    }
-
-    /// Acquires this lock, see `Mutex::lock`
-    pub fn lock<'a>(&'a mut self) -> Guard<'a> {
-        // First, attempt to steal the mutex from an unlocked state. The "fast
-        // path" needs to have as few atomic instructions as possible, and this
-        // one cmpxchg is already pretty expensive.
-        //
-        // FIXME: this can mess up the fairness of the mutex, seems bad
-        match self.state.compare_and_swap(0, LOCKED, atomics::SeqCst) {
-            0 => {
-                assert!(self.flavor == Unlocked);
-                self.flavor = TryLockAcquisition;
-                return Guard::new(self)
-            }
-            _ => {}
-        }
-
-        // After we've failed the fast path, then we delegate to the differnet
-        // locking protocols for green/native tasks. This will select two tasks
-        // to continue further (one native, one green).
-        let t: ~Task = Local::take();
-        let can_block = t.can_block();
-        let native_bit;
-        if can_block {
-            self.native_lock(t);
-            native_bit = NATIVE_BLOCKED;
-        } else {
-            self.green_lock(t);
-            native_bit = GREEN_BLOCKED;
-        }
-
-        // After we've arbitrated among task types, attempt to re-acquire the
-        // lock (avoids a deschedule). This is very important to do in order to
-        // allow threads coming out of the native_lock function to try their
-        // best to not hit a cvar in deschedule.
-        let mut old = match self.state.compare_and_swap(0, LOCKED,
-                                                        atomics::SeqCst) {
-            0 => {
-                self.flavor = if can_block {
-                    NativeAcquisition
-                } else {
-                    GreenAcquisition
-                };
-                return Guard::new(self)
-            }
-            old => old,
-        };
-
-        // Alright, everything else failed. We need to deschedule ourselves and
-        // flag ourselves as waiting. Note that this case should only happen
-        // regularly in native/green contention. Due to try_lock and the header
-        // of lock stealing the lock, it's also possible for native/native
-        // contention to hit this location, but as less common.
-        let t: ~Task = Local::take();
-        t.deschedule(1, |task| {
-            let task = unsafe { task.cast_to_uint() };
-            if can_block {
-                assert_eq!(self.native_blocker, 0);
-                self.native_blocker = task;
-            } else {
-                assert_eq!(self.green_blocker, 0);
-                self.green_blocker = task;
-            }
-
-            loop {
-                assert_eq!(old & native_bit, 0);
-                // If the old state was locked, then we need to flag ourselves
-                // as blocking in the state. If the old state was unlocked, then
-                // we attempt to acquire the mutex. Everything here is a CAS
-                // loop that'll eventually make progress.
-                if old & LOCKED != 0 {
-                    old = match self.state.compare_and_swap(old,
-                                                            old | native_bit,
-                                                            atomics::SeqCst) {
-                        n if n == old => return Ok(()),
-                        n => n
-                    };
-                } else {
-                    assert_eq!(old, 0);
-                    old = match self.state.compare_and_swap(old,
-                                                            old | LOCKED,
-                                                            atomics::SeqCst) {
-                        n if n == old => {
-                            assert_eq!(self.flavor, Unlocked);
-                            if can_block {
-                                self.native_blocker = 0;
-                                self.flavor = NativeAcquisition;
-                            } else {
-                                self.green_blocker = 0;
-                                self.flavor = GreenAcquisition;
-                            }
-                            return Err(unsafe {
-                                BlockedTask::cast_from_uint(task)
-                            })
-                        }
-                        n => n,
-                    };
-                }
-            }
-        });
-
-        Guard::new(self)
-    }
-
-    // Tasks which can block are super easy. These tasks just call the blocking
-    // `lock()` function on an OS mutex
-    fn native_lock(&mut self, t: ~Task) {
-        Local::put(t);
-        unsafe { self.lock.lock(); }
-    }
-
-    fn native_unlock(&mut self) {
-        unsafe { self.lock.unlock(); }
-    }
-
-    fn green_lock(&mut self, t: ~Task) {
-        // Green threads flag their presence with an atomic counter, and if they
-        // fail to be the first to the mutex, they enqueue themselves on a
-        // concurrent internal queue with a stack-allocated node.
-        //
-        // FIXME: There isn't a cancellation currently of an enqueue, forcing
-        //        the unlocker to spin for a bit.
-        if self.green_cnt.fetch_add(1, atomics::SeqCst) == 0 {
-            Local::put(t);
-            return
-        }
-
-        let mut node = q::Node::new(0);
-        t.deschedule(1, |task| {
-            unsafe {
-                node.data = task.cast_to_uint();
-                self.q.push(&mut node);
-            }
-            Ok(())
-        });
-    }
-
-    fn green_unlock(&mut self) {
-        // If we're the only green thread, then no need to check the queue,
-        // otherwise the fixme above forces us to spin for a bit.
-        if self.green_cnt.fetch_sub(1, atomics::SeqCst) == 1 { return }
-        let node;
-        loop {
-            match unsafe { self.q.pop() } {
-                Some(t) => { node = t; break; }
-                None => Thread::yield_now(),
-            }
-        }
-        let task = unsafe { BlockedTask::cast_from_uint((*node).data) };
-        task.wake().map(|t| t.reawaken());
-    }
-
-    fn unlock(&mut self) {
-        // Unlocking this mutex is a little tricky. We favor any task that is
-        // manually blocked (not in each of the separate locks) in order to help
-        // provide a little fairness (green threads will wake up the pending
-        // native thread and native threads will wake up the pending green
-        // thread).
-        //
-        // There's also the question of when we unlock the actual green/native
-        // locking halves as well. If we're waking up someone, then we can wait
-        // to unlock until we've acquired the task to wake up (we're guaranteed
-        // the mutex memory is still valid when there's contenders), but as soon
-        // as we don't find any contenders we must unlock the mutex, and *then*
-        // flag the mutex as unlocked.
-        //
-        // This flagging can fail, leading to another round of figuring out if a
-        // task needs to be woken, and in this case it's ok that the "mutex
-        // halves" are unlocked, we're just mainly dealing with the atomic state
-        // of the outer mutex.
-        let flavor = self.flavor;
-        self.flavor = Unlocked;
-
-        let mut state = self.state.load(atomics::SeqCst);
-        let mut unlocked = false;
-        let task;
-        loop {
-            assert!(state & LOCKED != 0);
-            if state & GREEN_BLOCKED != 0 {
-                self.unset(state, GREEN_BLOCKED);
-                task = unsafe {
-                    BlockedTask::cast_from_uint(self.green_blocker)
-                };
-                self.green_blocker = 0;
-                self.flavor = GreenAcquisition;
-                break;
-            } else if state & NATIVE_BLOCKED != 0 {
-                self.unset(state, NATIVE_BLOCKED);
-                task = unsafe {
-                    BlockedTask::cast_from_uint(self.native_blocker)
-                };
-                self.native_blocker = 0;
-                self.flavor = NativeAcquisition;
-                break;
-            } else {
-                assert_eq!(state, LOCKED);
-                if !unlocked {
-                    match flavor {
-                        GreenAcquisition => { self.green_unlock(); }
-                        NativeAcquisition => { self.native_unlock(); }
-                        TryLockAcquisition => {}
-                        Unlocked => unreachable!()
-                    }
-                    unlocked = true;
-                }
-                match self.state.compare_and_swap(LOCKED, 0, atomics::SeqCst) {
-                    LOCKED => return,
-                    n => { state = n; }
-                }
-            }
-        }
-        if !unlocked {
-            match flavor {
-                GreenAcquisition => { self.green_unlock(); }
-                NativeAcquisition => { self.native_unlock(); }
-                TryLockAcquisition => {}
-                Unlocked => unreachable!()
-            }
-        }
-
-        task.wake().map(|t| t.reawaken());
-    }
-
-    /// Loops around a CAS to unset the `bit` in `state`
-    fn unset(&mut self, mut state: uint, bit: uint) {
-        loop {
-            assert!(state & bit != 0);
-            let new = state ^ bit;
-            match self.state.compare_and_swap(state, new, atomics::SeqCst) {
-                n if n == state => break,
-                n => { state = n; }
-            }
-        }
-    }
-
-    /// Deallocates resources associated with this static mutex.
-    ///
-    /// This method is unsafe because it provides no guarantees that there are
-    /// no active users of this mutex, and safety is not guaranteed if there are
-    /// active users of this mutex.
-    ///
-    /// This method is required to ensure that there are no memory leaks on
-    /// *all* platforms. It may be the case that some platforms do not leak
-    /// memory if this method is not called, but this is not guaranteed to be
-    /// true on all platforms.
-    pub unsafe fn destroy(&mut self) {
-        self.lock.destroy()
-    }
-}
-
-impl Mutex {
-    /// Creates a new mutex in an unlocked state ready for use.
-    pub fn new() -> Mutex {
-        Mutex {
-            lock: StaticMutex {
-                state: atomics::AtomicUint::new(0),
-                flavor: Unlocked,
-                green_blocker: 0,
-                native_blocker: 0,
-                green_cnt: atomics::AtomicUint::new(0),
-                q: q::Queue::new(),
-                lock: unsafe { mutex::Mutex::new() },
-            }
-        }
-    }
-
-    /// Attempts to acquire this lock.
-    ///
-    /// If the lock could not be acquired at this time, then `None` is returned.
-    /// Otherwise, an RAII guard is returned. The lock will be unlocked when the
-    /// guard is dropped.
-    ///
-    /// This function does not block.
-    pub fn try_lock<'a>(&'a mut self) -> Option<Guard<'a>> {
-        self.lock.try_lock()
-    }
-
-    /// Acquires a mutex, blocking the current task until it is able to do so.
-    ///
-    /// This function will block the local task until it is availble to acquire
-    /// the mutex. Upon returning, the task is the only task with the mutex
-    /// held. An RAII guard is returned to allow scoped unlock of the lock. When
-    /// the guard goes out of scope, the mutex will be unlocked.
-    pub fn lock<'a>(&'a mut self) -> Guard<'a> { self.lock.lock() }
-}
-
-impl<'a> Guard<'a> {
-    fn new<'b>(lock: &'b mut StaticMutex) -> Guard<'b> {
-        if cfg!(debug) {
-            assert!(lock.flavor != Unlocked);
-            assert!(lock.state.load(atomics::SeqCst) & LOCKED != 0);
-        }
-        Guard { lock: lock }
-    }
-}
-
-#[unsafe_destructor]
-impl<'a> Drop for Guard<'a> {
-    #[inline]
-    fn drop(&mut self) {
-        self.lock.unlock();
-    }
-}
-
-impl Drop for Mutex {
-    fn drop(&mut self) {
-        // This is actually safe b/c we know that there is no further usage of
-        // this mutex (it's up to the user to arrange for a mutex to get
-        // dropped, that's not our job)
-        unsafe { self.lock.destroy() }
-    }
-}
-
-#[cfg(test)]
-mod test {
-    extern mod native;
-    use super::{Mutex, StaticMutex, MUTEX_INIT};
-
-    #[test]
-    fn smoke() {
-        let mut m = Mutex::new();
-        drop(m.lock());
-        drop(m.lock());
-    }
-
-    #[test]
-    fn smoke_static() {
-        static mut m: StaticMutex = MUTEX_INIT;
-        unsafe {
-            drop(m.lock());
-            drop(m.lock());
-            m.destroy();
-        }
-    }
-
-    #[test]
-    fn lots_and_lots() {
-        static mut m: StaticMutex = MUTEX_INIT;
-        static mut CNT: uint = 0;
-        static M: uint = 1000;
-        static N: uint = 3;
-
-        fn inc() {
-            for _ in range(0, M) {
-                unsafe {
-                    let _g = m.lock();
-                    CNT += 1;
-                }
-            }
-        }
-
-        let (p, c) = SharedChan::new();
-        for _ in range(0, N) {
-            let c2 = c.clone();
-            native::task::spawn(proc() { inc(); c2.send(()); });
-            let c2 = c.clone();
-            spawn(proc() { inc(); c2.send(()); });
-        }
-
-        drop(c);
-        for _ in range(0, 2 * N) {
-            p.recv();
-        }
-        assert_eq!(unsafe {CNT}, M * N * 2);
-        unsafe {
-            m.destroy();
-        }
-    }
-
-    #[test]
-    fn trylock() {
-        let mut m = Mutex::new();
-        assert!(m.try_lock().is_some());
-    }
-}
diff --git a/src/libextra/sync/one.rs b/src/libextra/sync/one.rs
deleted file mode 100644 (file)
index 826955d..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-// Copyright 2014 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.
-
-//! A "once initialization" primitive
-//!
-//! This primitive is meant to be used to run one-time initialization. An
-//! example use case would be for initializing an FFI library.
-
-use std::int;
-use std::sync::atomics;
-use sync::mutex::{StaticMutex, MUTEX_INIT};
-
-/// A type which can be used to run a one-time global initialization. This type
-/// is *unsafe* to use because it is built on top of the `Mutex` in this module.
-/// It does not know whether the currently running task is in a green or native
-/// context, and a blocking mutex should *not* be used under normal
-/// circumstances on a green task.
-///
-/// Despite its unsafety, it is often useful to have a one-time initialization
-/// routine run for FFI bindings or related external functionality. This type
-/// can only be statically constructed with the `ONCE_INIT` value.
-///
-/// # Example
-///
-/// ```rust
-/// use extra::sync::one::{Once, ONCE_INIT};
-///
-/// static mut START: Once = ONCE_INIT;
-/// unsafe {
-///     START.doit(|| {
-///         // run initialization here
-///     });
-/// }
-/// ```
-pub struct Once {
-    priv mutex: StaticMutex,
-    priv cnt: atomics::AtomicInt,
-    priv lock_cnt: atomics::AtomicInt,
-}
-
-/// Initialization value for static `Once` values.
-pub static ONCE_INIT: Once = Once {
-    mutex: MUTEX_INIT,
-    cnt: atomics::INIT_ATOMIC_INT,
-    lock_cnt: atomics::INIT_ATOMIC_INT,
-};
-
-impl Once {
-    /// Perform an initialization routine once and only once. The given closure
-    /// will be executed if this is the first time `doit` has been called, and
-    /// otherwise the routine will *not* be invoked.
-    ///
-    /// This method will block the calling *os thread* if another initialization
-    /// routine is currently running.
-    ///
-    /// When this function returns, it is guaranteed that some initialization
-    /// has run and completed (it may not be the closure specified).
-    pub fn doit(&mut self, f: ||) {
-        // Implementation-wise, this would seem like a fairly trivial primitive.
-        // The stickler part is where our mutexes currently require an
-        // allocation, and usage of a `Once` should't leak this allocation.
-        //
-        // This means that there must be a deterministic destroyer of the mutex
-        // contained within (because it's not needed after the initialization
-        // has run).
-        //
-        // The general scheme here is to gate all future threads once
-        // initialization has completed with a "very negative" count, and to
-        // allow through threads to lock the mutex if they see a non negative
-        // count. For all threads grabbing the mutex, exactly one of them should
-        // be responsible for unlocking the mutex, and this should only be done
-        // once everyone else is done with the mutex.
-        //
-        // This atomicity is achieved by swapping a very negative value into the
-        // shared count when the initialization routine has completed. This will
-        // read the number of threads which will at some point attempt to
-        // acquire the mutex. This count is then squirreled away in a separate
-        // variable, and the last person on the way out of the mutex is then
-        // responsible for destroying the mutex.
-        //
-        // It is crucial that the negative value is swapped in *after* the
-        // initialization routine has completed because otherwise new threads
-        // calling `doit` will return immediately before the initialization has
-        // completed.
-
-        let prev = self.cnt.fetch_add(1, atomics::SeqCst);
-        if prev < 0 {
-            // Make sure we never overflow, we'll never have int::MIN
-            // simultaneous calls to `doit` to make this value go back to 0
-            self.cnt.store(int::MIN, atomics::SeqCst);
-            return
-        }
-
-        // If the count is negative, then someone else finished the job,
-        // otherwise we run the job and record how many people will try to grab
-        // this lock
-        {
-            let _guard = self.mutex.lock();
-            if self.cnt.load(atomics::SeqCst) > 0 {
-                f();
-                let prev = self.cnt.swap(int::MIN, atomics::SeqCst);
-                self.lock_cnt.store(prev, atomics::SeqCst);
-            }
-        }
-
-        // Last one out cleans up after everyone else, no leaks!
-        if self.lock_cnt.fetch_add(-1, atomics::SeqCst) == 1 {
-            unsafe { self.mutex.destroy() }
-        }
-    }
-}
-
-#[cfg(test)]
-mod test {
-    use super::{ONCE_INIT, Once};
-    use std::task;
-
-    #[test]
-    fn smoke_once() {
-        static mut o: Once = ONCE_INIT;
-        let mut a = 0;
-        unsafe { o.doit(|| a += 1); }
-        assert_eq!(a, 1);
-        unsafe { o.doit(|| a += 1); }
-        assert_eq!(a, 1);
-    }
-
-    #[test]
-    fn stampede_once() {
-        static mut o: Once = ONCE_INIT;
-        static mut run: bool = false;
-
-        let (p, c) = SharedChan::new();
-        for _ in range(0, 10) {
-            let c = c.clone();
-            spawn(proc() {
-                for _ in range(0, 4) { task::deschedule() }
-                unsafe {
-                    o.doit(|| {
-                        assert!(!run);
-                        run = true;
-                    });
-                    assert!(run);
-                }
-                c.send(());
-            });
-        }
-
-        unsafe {
-            o.doit(|| {
-                assert!(!run);
-                run = true;
-            });
-            assert!(run);
-        }
-
-        for _ in range(0, 10) {
-            p.recv();
-        }
-    }
-}
diff --git a/src/libextra/task_pool.rs b/src/libextra/task_pool.rs
deleted file mode 100644 (file)
index 0d8cccf..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2012 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.
-
-#[allow(missing_doc)];
-
-/// A task pool abstraction. Useful for achieving predictable CPU
-/// parallelism.
-
-
-use std::task;
-use std::vec;
-
-enum Msg<T> {
-    Execute(proc(&T)),
-    Quit
-}
-
-pub struct TaskPool<T> {
-    priv channels: ~[Chan<Msg<T>>],
-    priv next_index: uint,
-}
-
-#[unsafe_destructor]
-impl<T> Drop for TaskPool<T> {
-    fn drop(&mut self) {
-        for channel in self.channels.mut_iter() {
-            channel.send(Quit);
-        }
-    }
-}
-
-impl<T> TaskPool<T> {
-    /// Spawns a new task pool with `n_tasks` tasks. If the `sched_mode`
-    /// is None, the tasks run on this scheduler; otherwise, they run on a
-    /// new scheduler with the given mode. The provided `init_fn_factory`
-    /// returns a function which, given the index of the task, should return
-    /// local data to be kept around in that task.
-    pub fn new(n_tasks: uint,
-               init_fn_factory: || -> proc(uint) -> T)
-               -> TaskPool<T> {
-        assert!(n_tasks >= 1);
-
-        let channels = vec::from_fn(n_tasks, |i| {
-            let (port, chan) = Chan::<Msg<T>>::new();
-            let init_fn = init_fn_factory();
-
-            let task_body: proc() = proc() {
-                let local_data = init_fn(i);
-                loop {
-                    match port.recv() {
-                        Execute(f) => f(&local_data),
-                        Quit => break
-                    }
-                }
-            };
-
-            // Run on this scheduler.
-            task::spawn(task_body);
-
-            chan
-        });
-
-        return TaskPool { channels: channels, next_index: 0 };
-    }
-
-    /// Executes the function `f` on a task in the pool. The function
-    /// receives a reference to the local data returned by the `init_fn`.
-    pub fn execute(&mut self, f: proc(&T)) {
-        self.channels[self.next_index].send(Execute(f));
-        self.next_index += 1;
-        if self.next_index == self.channels.len() { self.next_index = 0; }
-    }
-}
-
-#[test]
-fn test_task_pool() {
-    let f: || -> proc(uint) -> uint = || {
-        let g: proc(uint) -> uint = proc(i) i;
-        g
-    };
-    let mut pool = TaskPool::new(4, f);
-    for _ in range(0, 8) {
-        pool.execute(proc(i) println!("Hello from thread {}!", *i));
-    }
-}
index 4d8e7e50dcfd50f93092585387de5a6a61dd4754..d16edb7aa1e79074be636bac59ce23007e531aad 100644 (file)
@@ -13,7 +13,7 @@
 use json;
 use json::ToJson;
 use serialize::{Encoder, Encodable, Decoder, Decodable};
-use arc::{Arc,RWArc};
+use sync::{Arc,RWArc};
 use treemap::TreeMap;
 use std::str;
 use std::io;
index e224a06818af18f444914251bd1ec021d80645c6..aea9b65087dc68b4a0cc76fb3260cee5a2602f10 100644 (file)
@@ -331,7 +331,7 @@ pub fn run_assembler(sess: Session, assembly: &Path, object: &Path) {
     }
 
     unsafe fn configure_llvm(sess: Session) {
-        use extra::sync::one::{Once, ONCE_INIT};
+        use sync::one::{Once, ONCE_INIT};
         static mut INIT: Once = ONCE_INIT;
 
         // Copy what clang does by turning on loop vectorization at O2 and
index 8e722fae13a36ed756e697cea3b011ac3fd71c89..d4a6c29752d16dc63fabe52c19f52f8a98ef3484 100644 (file)
@@ -35,6 +35,7 @@
 extern mod flate;
 extern mod arena;
 extern mod syntax;
+extern mod sync;
 
 use back::link;
 use driver::session;
index 1ebe4a03cfdd2a5cef44df6175ec81c10462365a..5b4a961761277273ecb7a055e97acf11bd1b63da 100644 (file)
@@ -2660,7 +2660,7 @@ pub fn trans_crate(sess: session::Session,
                    output: &Path) -> CrateTranslation {
     // Before we touch LLVM, make sure that multithreading is enabled.
     unsafe {
-        use extra::sync::one::{Once, ONCE_INIT};
+        use sync::one::{Once, ONCE_INIT};
         static mut INIT: Once = ONCE_INIT;
         static mut POISONED: bool = false;
         INIT.doit(|| {
index 65696528a6fa1cab4ae0603a410dcfeb165a169d..f01e420030f6d9f9f7ae4f226458f906492f1dc3 100644 (file)
@@ -41,7 +41,7 @@
 use std::str;
 use std::vec;
 
-use extra::arc::Arc;
+use sync::Arc;
 use extra::json::ToJson;
 use syntax::ast;
 use syntax::attr;
index fe989279e7147dd13286e0cd41009c59f1f9c3b3..bf096a7e49b461eba6fa9f31d50ffd5183b28630 100644 (file)
@@ -18,6 +18,7 @@
 extern mod syntax;
 extern mod rustc;
 extern mod extra;
+extern mod sync;
 
 use std::local_data;
 use std::io;
diff --git a/src/libsync/arc.rs b/src/libsync/arc.rs
new file mode 100644 (file)
index 0000000..0e53ecd
--- /dev/null
@@ -0,0 +1,1074 @@
+// Copyright 2012-2014 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.
+
+/*!
+ * Concurrency-enabled mechanisms for sharing mutable and/or immutable state
+ * between tasks.
+ *
+ * # Example
+ *
+ * In this example, a large vector of floats is shared between several tasks.
+ * With simple pipes, without Arc, a copy would have to be made for each task.
+ *
+ * ```rust
+ * use sync::Arc;
+ * use std::{rand, vec};
+ *
+ * let numbers = vec::from_fn(100, |i| (i as f32) * rand::random());
+ * let shared_numbers = Arc::new(numbers);
+ *
+ *   for _ in range(0, 10) {
+ *       let (port, chan) = Chan::new();
+ *       chan.send(shared_numbers.clone());
+ *
+ *       spawn(proc() {
+ *           let shared_numbers = port.recv();
+ *           let local_numbers = shared_numbers.get();
+ *
+ *           // Work with the local numbers
+ *       });
+ *   }
+ * ```
+ */
+
+#[allow(missing_doc, dead_code)];
+
+
+use sync;
+use sync::{Mutex, RWLock};
+
+use std::cast;
+use std::kinds::marker;
+use std::sync::arc::UnsafeArc;
+use std::task;
+
+/// As sync::condvar, a mechanism for unlock-and-descheduling and signaling.
+pub struct Condvar<'a> {
+    priv is_mutex: bool,
+    priv failed: &'a bool,
+    priv cond: &'a sync::Condvar<'a>
+}
+
+impl<'a> Condvar<'a> {
+    /// Atomically exit the associated Arc and block until a signal is sent.
+    #[inline]
+    pub fn wait(&self) { self.wait_on(0) }
+
+    /**
+     * Atomically exit the associated Arc and block on a specified condvar
+     * until a signal is sent on that same condvar (as sync::cond.wait_on).
+     *
+     * wait() is equivalent to wait_on(0).
+     */
+    #[inline]
+    pub fn wait_on(&self, condvar_id: uint) {
+        assert!(!*self.failed);
+        self.cond.wait_on(condvar_id);
+        // This is why we need to wrap sync::condvar.
+        check_poison(self.is_mutex, *self.failed);
+    }
+
+    /// Wake up a blocked task. Returns false if there was no blocked task.
+    #[inline]
+    pub fn signal(&self) -> bool { self.signal_on(0) }
+
+    /**
+     * Wake up a blocked task on a specified condvar (as
+     * sync::cond.signal_on). Returns false if there was no blocked task.
+     */
+    #[inline]
+    pub fn signal_on(&self, condvar_id: uint) -> bool {
+        assert!(!*self.failed);
+        self.cond.signal_on(condvar_id)
+    }
+
+    /// Wake up all blocked tasks. Returns the number of tasks woken.
+    #[inline]
+    pub fn broadcast(&self) -> uint { self.broadcast_on(0) }
+
+    /**
+     * Wake up all blocked tasks on a specified condvar (as
+     * sync::cond.broadcast_on). Returns the number of tasks woken.
+     */
+    #[inline]
+    pub fn broadcast_on(&self, condvar_id: uint) -> uint {
+        assert!(!*self.failed);
+        self.cond.broadcast_on(condvar_id)
+    }
+}
+
+/****************************************************************************
+ * Immutable Arc
+ ****************************************************************************/
+
+/// An atomically reference counted wrapper for shared immutable state.
+pub struct Arc<T> { priv x: UnsafeArc<T> }
+
+
+/**
+ * Access the underlying data in an atomically reference counted
+ * wrapper.
+ */
+impl<T:Freeze+Send> Arc<T> {
+    /// Create an atomically reference counted wrapper.
+    #[inline]
+    pub fn new(data: T) -> Arc<T> {
+        Arc { x: UnsafeArc::new(data) }
+    }
+
+    #[inline]
+    pub fn get<'a>(&'a self) -> &'a T {
+        unsafe { &*self.x.get_immut() }
+    }
+}
+
+impl<T:Freeze + Send> Clone for Arc<T> {
+    /**
+    * Duplicate an atomically reference counted wrapper.
+    *
+    * The resulting two `arc` objects will point to the same underlying data
+    * object. However, one of the `arc` objects can be sent to another task,
+    * allowing them to share the underlying data.
+    */
+    #[inline]
+    fn clone(&self) -> Arc<T> {
+        Arc { x: self.x.clone() }
+    }
+}
+
+/****************************************************************************
+ * Mutex protected Arc (unsafe)
+ ****************************************************************************/
+
+#[doc(hidden)]
+struct MutexArcInner<T> { lock: Mutex, failed: bool, data: T }
+
+/// An Arc with mutable data protected by a blocking mutex.
+pub struct MutexArc<T> {
+    priv x: UnsafeArc<MutexArcInner<T>>,
+    priv marker: marker::NoFreeze,
+}
+
+impl<T:Send> Clone for MutexArc<T> {
+    /// Duplicate a mutex-protected Arc. See arc::clone for more details.
+    #[inline]
+    fn clone(&self) -> MutexArc<T> {
+        // NB: Cloning the underlying mutex is not necessary. Its reference
+        // count would be exactly the same as the shared state's.
+        MutexArc { x: self.x.clone(),
+                   marker: marker::NoFreeze, }
+    }
+}
+
+impl<T:Send> MutexArc<T> {
+    /// Create a mutex-protected Arc with the supplied data.
+    pub fn new(user_data: T) -> MutexArc<T> {
+        MutexArc::new_with_condvars(user_data, 1)
+    }
+
+    /**
+     * Create a mutex-protected Arc with the supplied data and a specified number
+     * of condvars (as sync::Mutex::new_with_condvars).
+     */
+    pub fn new_with_condvars(user_data: T, num_condvars: uint) -> MutexArc<T> {
+        let data = MutexArcInner {
+            lock: Mutex::new_with_condvars(num_condvars),
+            failed: false, data: user_data
+        };
+        MutexArc { x: UnsafeArc::new(data),
+                   marker: marker::NoFreeze, }
+    }
+
+    /**
+     * Access the underlying mutable data with mutual exclusion from other
+     * tasks. The argument closure will be run with the mutex locked; all
+     * other tasks wishing to access the data will block until the closure
+     * finishes running.
+     *
+     * The reason this function is 'unsafe' is because it is possible to
+     * construct a circular reference among multiple Arcs by mutating the
+     * underlying data. This creates potential for deadlock, but worse, this
+     * will guarantee a memory leak of all involved Arcs. Using MutexArcs
+     * inside of other Arcs is safe in absence of circular references.
+     *
+     * If you wish to nest MutexArcs, one strategy for ensuring safety at
+     * runtime is to add a "nesting level counter" inside the stored data, and
+     * when traversing the arcs, assert that they monotonically decrease.
+     *
+     * # Failure
+     *
+     * Failing while inside the Arc will unlock the Arc while unwinding, so
+     * that other tasks won't block forever. It will also poison the Arc:
+     * any tasks that subsequently try to access it (including those already
+     * blocked on the mutex) will also fail immediately.
+     */
+    #[inline]
+    pub unsafe fn unsafe_access<U>(&self, blk: |x: &mut T| -> U) -> U {
+        let state = self.x.get();
+        // Borrowck would complain about this if the function were
+        // not already unsafe. See borrow_rwlock, far below.
+        (&(*state).lock).lock(|| {
+            check_poison(true, (*state).failed);
+            let _z = PoisonOnFail::new(&mut (*state).failed);
+            blk(&mut (*state).data)
+        })
+    }
+
+    /// As unsafe_access(), but with a condvar, as sync::mutex.lock_cond().
+    #[inline]
+    pub unsafe fn unsafe_access_cond<U>(&self,
+                                        blk: |x: &mut T, c: &Condvar| -> U)
+                                        -> U {
+        let state = self.x.get();
+        (&(*state).lock).lock_cond(|cond| {
+            check_poison(true, (*state).failed);
+            let _z = PoisonOnFail::new(&mut (*state).failed);
+            blk(&mut (*state).data,
+                &Condvar {is_mutex: true,
+                          failed: &(*state).failed,
+                          cond: cond })
+        })
+    }
+}
+
+impl<T:Freeze + Send> MutexArc<T> {
+
+    /**
+     * As unsafe_access.
+     *
+     * The difference between access and unsafe_access is that the former
+     * forbids mutexes to be nested. While unsafe_access can be used on
+     * MutexArcs without freezable interiors, this safe version of access
+     * requires the Freeze bound, which prohibits access on MutexArcs which
+     * might contain nested MutexArcs inside.
+     *
+     * The purpose of this is to offer a safe implementation of MutexArc to be
+     * used instead of RWArc in cases where no readers are needed and slightly
+     * better performance is required.
+     *
+     * Both methods have the same failure behaviour as unsafe_access and
+     * unsafe_access_cond.
+     */
+    #[inline]
+    pub fn access<U>(&self, blk: |x: &mut T| -> U) -> U {
+        unsafe { self.unsafe_access(blk) }
+    }
+
+    /// As unsafe_access_cond but safe and Freeze.
+    #[inline]
+    pub fn access_cond<U>(&self,
+                          blk: |x: &mut T, c: &Condvar| -> U)
+                          -> U {
+        unsafe { self.unsafe_access_cond(blk) }
+    }
+}
+
+// Common code for {mutex.access,rwlock.write}{,_cond}.
+#[inline]
+#[doc(hidden)]
+fn check_poison(is_mutex: bool, failed: bool) {
+    if failed {
+        if is_mutex {
+            fail!("Poisoned MutexArc - another task failed inside!");
+        } else {
+            fail!("Poisoned rw_arc - another task failed inside!");
+        }
+    }
+}
+
+#[doc(hidden)]
+struct PoisonOnFail {
+    flag: *mut bool,
+    failed: bool,
+}
+
+impl Drop for PoisonOnFail {
+    fn drop(&mut self) {
+        unsafe {
+            /* assert!(!*self.failed);
+               -- might be false in case of cond.wait() */
+            if !self.failed && task::failing() {
+                *self.flag = true;
+            }
+        }
+    }
+}
+
+impl PoisonOnFail {
+    fn new<'a>(flag: &'a mut bool) -> PoisonOnFail {
+        PoisonOnFail {
+            flag: flag,
+            failed: task::failing()
+        }
+    }
+}
+
+/****************************************************************************
+ * R/W lock protected Arc
+ ****************************************************************************/
+
+#[doc(hidden)]
+struct RWArcInner<T> { lock: RWLock, failed: bool, data: T }
+/**
+ * A dual-mode Arc protected by a reader-writer lock. The data can be accessed
+ * mutably or immutably, and immutably-accessing tasks may run concurrently.
+ *
+ * Unlike mutex_arcs, rw_arcs are safe, because they cannot be nested.
+ */
+pub struct RWArc<T> {
+    priv x: UnsafeArc<RWArcInner<T>>,
+    priv marker: marker::NoFreeze,
+}
+
+impl<T:Freeze + Send> Clone for RWArc<T> {
+    /// Duplicate a rwlock-protected Arc. See arc::clone for more details.
+    #[inline]
+    fn clone(&self) -> RWArc<T> {
+        RWArc { x: self.x.clone(),
+                marker: marker::NoFreeze, }
+    }
+
+}
+
+impl<T:Freeze + Send> RWArc<T> {
+    /// Create a reader/writer Arc with the supplied data.
+    pub fn new(user_data: T) -> RWArc<T> {
+        RWArc::new_with_condvars(user_data, 1)
+    }
+
+    /**
+     * Create a reader/writer Arc with the supplied data and a specified number
+     * of condvars (as sync::RWLock::new_with_condvars).
+     */
+    pub fn new_with_condvars(user_data: T, num_condvars: uint) -> RWArc<T> {
+        let data = RWArcInner {
+            lock: RWLock::new_with_condvars(num_condvars),
+            failed: false, data: user_data
+        };
+        RWArc { x: UnsafeArc::new(data),
+                marker: marker::NoFreeze, }
+    }
+
+    /**
+     * Access the underlying data mutably. Locks the rwlock in write mode;
+     * other readers and writers will block.
+     *
+     * # Failure
+     *
+     * Failing while inside the Arc will unlock the Arc while unwinding, so
+     * that other tasks won't block forever. As MutexArc.access, it will also
+     * poison the Arc, so subsequent readers and writers will both also fail.
+     */
+    #[inline]
+    pub fn write<U>(&self, blk: |x: &mut T| -> U) -> U {
+        unsafe {
+            let state = self.x.get();
+            (*borrow_rwlock(state)).write(|| {
+                check_poison(false, (*state).failed);
+                let _z = PoisonOnFail::new(&mut (*state).failed);
+                blk(&mut (*state).data)
+            })
+        }
+    }
+
+    /// As write(), but with a condvar, as sync::rwlock.write_cond().
+    #[inline]
+    pub fn write_cond<U>(&self,
+                         blk: |x: &mut T, c: &Condvar| -> U)
+                         -> U {
+        unsafe {
+            let state = self.x.get();
+            (*borrow_rwlock(state)).write_cond(|cond| {
+                check_poison(false, (*state).failed);
+                let _z = PoisonOnFail::new(&mut (*state).failed);
+                blk(&mut (*state).data,
+                    &Condvar {is_mutex: false,
+                              failed: &(*state).failed,
+                              cond: cond})
+            })
+        }
+    }
+
+    /**
+     * Access the underlying data immutably. May run concurrently with other
+     * reading tasks.
+     *
+     * # Failure
+     *
+     * Failing will unlock the Arc while unwinding. However, unlike all other
+     * access modes, this will not poison the Arc.
+     */
+    pub fn read<U>(&self, blk: |x: &T| -> U) -> U {
+        unsafe {
+            let state = self.x.get();
+            (*state).lock.read(|| {
+                check_poison(false, (*state).failed);
+                blk(&(*state).data)
+            })
+        }
+    }
+
+    /**
+     * As write(), but with the ability to atomically 'downgrade' the lock.
+     * See sync::rwlock.write_downgrade(). The RWWriteMode token must be used
+     * to obtain the &mut T, and can be transformed into a RWReadMode token by
+     * calling downgrade(), after which a &T can be obtained instead.
+     *
+     * # Example
+     *
+     * ```rust
+     * use sync::RWArc;
+     *
+     * let arc = RWArc::new(1);
+     * arc.write_downgrade(|mut write_token| {
+     *     write_token.write_cond(|state, condvar| {
+     *         // ... exclusive access with mutable state ...
+     *     });
+     *     let read_token = arc.downgrade(write_token);
+     *     read_token.read(|state| {
+     *         // ... shared access with immutable state ...
+     *     });
+     * })
+     * ```
+     */
+    pub fn write_downgrade<U>(&self, blk: |v: RWWriteMode<T>| -> U) -> U {
+        unsafe {
+            let state = self.x.get();
+            (*borrow_rwlock(state)).write_downgrade(|write_mode| {
+                check_poison(false, (*state).failed);
+                blk(RWWriteMode {
+                    data: &mut (*state).data,
+                    token: write_mode,
+                    poison: PoisonOnFail::new(&mut (*state).failed)
+                })
+            })
+        }
+    }
+
+    /// To be called inside of the write_downgrade block.
+    pub fn downgrade<'a>(&self, token: RWWriteMode<'a, T>)
+                         -> RWReadMode<'a, T> {
+        unsafe {
+            // The rwlock should assert that the token belongs to us for us.
+            let state = self.x.get();
+            let RWWriteMode {
+                data: data,
+                token: t,
+                poison: _poison
+            } = token;
+            // Let readers in
+            let new_token = (*state).lock.downgrade(t);
+            // Whatever region the input reference had, it will be safe to use
+            // the same region for the output reference. (The only 'unsafe' part
+            // of this cast is removing the mutability.)
+            let new_data = data;
+            // Downgrade ensured the token belonged to us. Just a sanity check.
+            assert!((&(*state).data as *T as uint) == (new_data as *mut T as uint));
+            // Produce new token
+            RWReadMode {
+                data: new_data,
+                token: new_token,
+            }
+        }
+    }
+}
+
+// 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'.
+#[doc(hidden)]
+fn borrow_rwlock<T:Freeze + Send>(state: *mut RWArcInner<T>) -> *RWLock {
+    unsafe { cast::transmute(&(*state).lock) }
+}
+
+/// The "write permission" token used for RWArc.write_downgrade().
+pub struct RWWriteMode<'a, T> {
+    priv data: &'a mut T,
+    priv token: sync::RWLockWriteMode<'a>,
+    priv poison: PoisonOnFail,
+}
+
+/// The "read permission" token used for RWArc.write_downgrade().
+pub struct RWReadMode<'a, T> {
+    priv data: &'a T,
+    priv token: sync::RWLockReadMode<'a>,
+}
+
+impl<'a, T:Freeze + Send> RWWriteMode<'a, T> {
+    /// Access the pre-downgrade RWArc in write mode.
+    pub fn write<U>(&mut self, blk: |x: &mut T| -> U) -> U {
+        match *self {
+            RWWriteMode {
+                data: &ref mut data,
+                token: ref token,
+                poison: _
+            } => {
+                token.write(|| blk(data))
+            }
+        }
+    }
+
+    /// Access the pre-downgrade RWArc in write mode with a condvar.
+    pub fn write_cond<U>(&mut self,
+                         blk: |x: &mut T, c: &Condvar| -> U)
+                         -> U {
+        match *self {
+            RWWriteMode {
+                data: &ref mut data,
+                token: ref token,
+                poison: ref poison
+            } => {
+                token.write_cond(|cond| {
+                    unsafe {
+                        let cvar = Condvar {
+                            is_mutex: false,
+                            failed: &*poison.flag,
+                            cond: cond
+                        };
+                        blk(data, &cvar)
+                    }
+                })
+            }
+        }
+    }
+}
+
+impl<'a, T:Freeze + Send> RWReadMode<'a, T> {
+    /// Access the post-downgrade rwlock in read mode.
+    pub fn read<U>(&self, blk: |x: &T| -> U) -> U {
+        match *self {
+            RWReadMode {
+                data: data,
+                token: ref token
+            } => {
+                token.read(|| blk(data))
+            }
+        }
+    }
+}
+
+/****************************************************************************
+ * Copy-on-write Arc
+ ****************************************************************************/
+
+pub struct CowArc<T> { priv x: UnsafeArc<T> }
+
+/// A Copy-on-write Arc functions the same way as an `arc` except it allows
+/// mutation of the contents if there is only a single reference to
+/// the data. If there are multiple references the data is automatically
+/// cloned and the task modifies the cloned data in place of the shared data.
+impl<T:Clone+Send+Freeze> CowArc<T> {
+    /// Create a copy-on-write atomically reference counted wrapper
+    #[inline]
+    pub fn new(data: T) -> CowArc<T> {
+        CowArc { x: UnsafeArc::new(data) }
+    }
+
+    #[inline]
+    pub fn get<'a>(&'a self) -> &'a T {
+        unsafe { &*self.x.get_immut() }
+    }
+
+    /// get a mutable reference to the contents. If there are more then one
+    /// reference to the contents of the `CowArc` will be cloned
+    /// and this reference updated to point to the cloned data.
+    #[inline]
+    pub fn get_mut<'a>(&'a mut self) -> &'a mut T {
+        if !self.x.is_owned() {
+            *self = CowArc::new(self.get().clone())
+        }
+        unsafe { &mut *self.x.get() }
+    }
+}
+
+impl<T:Clone+Send+Freeze> Clone for CowArc<T> {
+    /// Duplicate a Copy-on-write Arc. See arc::clone for more details.
+    #[inline]
+    fn clone(&self) -> CowArc<T> {
+        CowArc { x: self.x.clone() }
+    }
+}
+
+
+
+/****************************************************************************
+ * Tests
+ ****************************************************************************/
+
+#[cfg(test)]
+mod tests {
+
+    use super::{Arc, RWArc, MutexArc, CowArc};
+
+    use std::task;
+
+    #[test]
+    fn manually_share_arc() {
+        let v = ~[1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+        let arc_v = Arc::new(v);
+
+        let (p, c) = Chan::new();
+
+        task::spawn(proc() {
+            let arc_v: Arc<~[int]> = p.recv();
+
+            let v = arc_v.get().clone();
+            assert_eq!(v[3], 4);
+        });
+
+        c.send(arc_v.clone());
+
+        assert_eq!(arc_v.get()[2], 3);
+        assert_eq!(arc_v.get()[4], 5);
+
+        info!("{:?}", arc_v);
+    }
+
+    #[test]
+    fn test_mutex_arc_condvar() {
+        let arc = ~MutexArc::new(false);
+        let arc2 = ~arc.clone();
+        let (p,c) = Chan::new();
+        task::spawn(proc() {
+            // wait until parent gets in
+            p.recv();
+            arc2.access_cond(|state, cond| {
+                *state = true;
+                cond.signal();
+            })
+        });
+
+        arc.access_cond(|state, cond| {
+            c.send(());
+            assert!(!*state);
+            while !*state {
+                cond.wait();
+            }
+        })
+    }
+
+    #[test] #[should_fail]
+    fn test_arc_condvar_poison() {
+        let arc = ~MutexArc::new(1);
+        let arc2 = ~arc.clone();
+        let (p, c) = Chan::new();
+
+        spawn(proc() {
+            let _ = p.recv();
+            arc2.access_cond(|one, cond| {
+                cond.signal();
+                // Parent should fail when it wakes up.
+                assert_eq!(*one, 0);
+            })
+        });
+
+        arc.access_cond(|one, cond| {
+            c.send(());
+            while *one == 1 {
+                cond.wait();
+            }
+        })
+    }
+
+    #[test] #[should_fail]
+    fn test_mutex_arc_poison() {
+        let arc = ~MutexArc::new(1);
+        let arc2 = ~arc.clone();
+        let _ = task::try(proc() {
+            arc2.access(|one| {
+                assert_eq!(*one, 2);
+            })
+        });
+        arc.access(|one| {
+            assert_eq!(*one, 1);
+        })
+    }
+
+    #[test]
+    fn test_unsafe_mutex_arc_nested() {
+        unsafe {
+            // Tests nested mutexes and access
+            // to underlaying data.
+            let arc = ~MutexArc::new(1);
+            let arc2 = ~MutexArc::new(*arc);
+            task::spawn(proc() {
+                (*arc2).unsafe_access(|mutex| {
+                    (*mutex).access(|one| {
+                        assert!(*one == 1);
+                    })
+                })
+            });
+        }
+    }
+
+    #[test]
+    fn test_mutex_arc_access_in_unwind() {
+        let arc = MutexArc::new(1i);
+        let arc2 = arc.clone();
+        let _ = task::try::<()>(proc() {
+            struct Unwinder {
+                i: MutexArc<int>
+            }
+            impl Drop for Unwinder {
+                fn drop(&mut self) {
+                    self.i.access(|num| *num += 1);
+                }
+            }
+            let _u = Unwinder { i: arc2 };
+            fail!();
+        });
+        assert_eq!(2, arc.access(|n| *n));
+    }
+
+    #[test] #[should_fail]
+    fn test_rw_arc_poison_wr() {
+        let arc = RWArc::new(1);
+        let arc2 = arc.clone();
+        let _ = task::try(proc() {
+            arc2.write(|one| {
+                assert_eq!(*one, 2);
+            })
+        });
+        arc.read(|one| {
+            assert_eq!(*one, 1);
+        })
+    }
+
+    #[test] #[should_fail]
+    fn test_rw_arc_poison_ww() {
+        let arc = RWArc::new(1);
+        let arc2 = arc.clone();
+        let _ = task::try(proc() {
+            arc2.write(|one| {
+                assert_eq!(*one, 2);
+            })
+        });
+        arc.write(|one| {
+            assert_eq!(*one, 1);
+        })
+    }
+    #[test] #[should_fail]
+    fn test_rw_arc_poison_dw() {
+        let arc = RWArc::new(1);
+        let arc2 = arc.clone();
+        let _ = task::try(proc() {
+            arc2.write_downgrade(|mut write_mode| {
+                write_mode.write(|one| {
+                    assert_eq!(*one, 2);
+                })
+            })
+        });
+        arc.write(|one| {
+            assert_eq!(*one, 1);
+        })
+    }
+    #[test]
+    fn test_rw_arc_no_poison_rr() {
+        let arc = RWArc::new(1);
+        let arc2 = arc.clone();
+        let _ = task::try(proc() {
+            arc2.read(|one| {
+                assert_eq!(*one, 2);
+            })
+        });
+        arc.read(|one| {
+            assert_eq!(*one, 1);
+        })
+    }
+    #[test]
+    fn test_rw_arc_no_poison_rw() {
+        let arc = RWArc::new(1);
+        let arc2 = arc.clone();
+        let _ = task::try(proc() {
+            arc2.read(|one| {
+                assert_eq!(*one, 2);
+            })
+        });
+        arc.write(|one| {
+            assert_eq!(*one, 1);
+        })
+    }
+    #[test]
+    fn test_rw_arc_no_poison_dr() {
+        let arc = RWArc::new(1);
+        let arc2 = arc.clone();
+        let _ = task::try(proc() {
+            arc2.write_downgrade(|write_mode| {
+                let read_mode = arc2.downgrade(write_mode);
+                read_mode.read(|one| {
+                    assert_eq!(*one, 2);
+                })
+            })
+        });
+        arc.write(|one| {
+            assert_eq!(*one, 1);
+        })
+    }
+    #[test]
+    fn test_rw_arc() {
+        let arc = RWArc::new(0);
+        let arc2 = arc.clone();
+        let (p, c) = Chan::new();
+
+        task::spawn(proc() {
+            arc2.write(|num| {
+                for _ in range(0, 10) {
+                    let tmp = *num;
+                    *num = -1;
+                    task::deschedule();
+                    *num = tmp + 1;
+                }
+                c.send(());
+            })
+        });
+
+        // Readers try to catch the writer in the act
+        let mut children = ~[];
+        for _ in range(0, 5) {
+            let arc3 = arc.clone();
+            let mut builder = task::task();
+            children.push(builder.future_result());
+            builder.spawn(proc() {
+                arc3.read(|num| {
+                    assert!(*num >= 0);
+                })
+            });
+        }
+
+        // Wait for children to pass their asserts
+        for r in children.mut_iter() {
+            let _ = r.recv();
+        }
+
+        // Wait for writer to finish
+        p.recv();
+        arc.read(|num| {
+            assert_eq!(*num, 10);
+        })
+    }
+
+    #[test]
+    fn test_rw_arc_access_in_unwind() {
+        let arc = RWArc::new(1i);
+        let arc2 = arc.clone();
+        let _ = task::try::<()>(proc() {
+            struct Unwinder {
+                i: RWArc<int>
+            }
+            impl Drop for Unwinder {
+                fn drop(&mut self) {
+                    self.i.write(|num| *num += 1);
+                }
+            }
+            let _u = Unwinder { i: arc2 };
+            fail!();
+        });
+        assert_eq!(2, arc.read(|n| *n));
+    }
+
+    #[test]
+    fn test_rw_downgrade() {
+        // (1) A downgrader gets in write mode and does cond.wait.
+        // (2) A writer gets in write mode, sets state to 42, and does signal.
+        // (3) Downgrader wakes, sets state to 31337.
+        // (4) tells writer and all other readers to contend as it downgrades.
+        // (5) Writer attempts to set state back to 42, while downgraded task
+        //     and all reader tasks assert that it's 31337.
+        let arc = RWArc::new(0);
+
+        // Reader tasks
+        let mut reader_convos = ~[];
+        for _ in range(0, 10) {
+            let ((rp1, rc1), (rp2, rc2)) = (Chan::new(), Chan::new());
+            reader_convos.push((rc1, rp2));
+            let arcn = arc.clone();
+            task::spawn(proc() {
+                rp1.recv(); // wait for downgrader to give go-ahead
+                arcn.read(|state| {
+                    assert_eq!(*state, 31337);
+                    rc2.send(());
+                })
+            });
+        }
+
+        // Writer task
+        let arc2 = arc.clone();
+        let ((wp1, wc1), (wp2, wc2)) = (Chan::new(), Chan::new());
+        task::spawn(proc() {
+            wp1.recv();
+            arc2.write_cond(|state, cond| {
+                assert_eq!(*state, 0);
+                *state = 42;
+                cond.signal();
+            });
+            wp1.recv();
+            arc2.write(|state| {
+                // This shouldn't happen until after the downgrade read
+                // section, and all other readers, finish.
+                assert_eq!(*state, 31337);
+                *state = 42;
+            });
+            wc2.send(());
+        });
+
+        // Downgrader (us)
+        arc.write_downgrade(|mut write_mode| {
+            write_mode.write_cond(|state, cond| {
+                wc1.send(()); // send to another writer who will wake us up
+                while *state == 0 {
+                    cond.wait();
+                }
+                assert_eq!(*state, 42);
+                *state = 31337;
+                // send to other readers
+                for &(ref mut rc, _) in reader_convos.mut_iter() {
+                    rc.send(())
+                }
+            });
+            let read_mode = arc.downgrade(write_mode);
+            read_mode.read(|state| {
+                // complete handshake with other readers
+                for &(_, ref mut rp) in reader_convos.mut_iter() {
+                    rp.recv()
+                }
+                wc1.send(()); // tell writer to try again
+                assert_eq!(*state, 31337);
+            });
+        });
+
+        wp2.recv(); // complete handshake with writer
+    }
+    #[cfg(test)]
+    fn test_rw_write_cond_downgrade_read_race_helper() {
+        // Tests that when a downgrader hands off the "reader cloud" lock
+        // because of a contending reader, a writer can't race to get it
+        // instead, which would result in readers_and_writers. This tests
+        // the sync module rather than this one, but it's here because an
+        // rwarc gives us extra shared state to help check for the race.
+        // If you want to see this test fail, go to sync.rs and replace the
+        // line in RWLock::write_cond() that looks like:
+        //     "blk(&Condvar { order: opt_lock, ..*cond })"
+        // with just "blk(cond)".
+        let x = RWArc::new(true);
+        let (wp, wc) = Chan::new();
+
+        // writer task
+        let xw = x.clone();
+        task::spawn(proc() {
+            xw.write_cond(|state, c| {
+                wc.send(()); // tell downgrader it's ok to go
+                c.wait();
+                // The core of the test is here: the condvar reacquire path
+                // must involve order_lock, so that it cannot race with a reader
+                // trying to receive the "reader cloud lock hand-off".
+                *state = false;
+            })
+        });
+
+        wp.recv(); // wait for writer to get in
+
+        x.write_downgrade(|mut write_mode| {
+            write_mode.write_cond(|state, c| {
+                assert!(*state);
+                // make writer contend in the cond-reacquire path
+                c.signal();
+            });
+            // make a reader task to trigger the "reader cloud lock" handoff
+            let xr = x.clone();
+            let (rp, rc) = Chan::new();
+            task::spawn(proc() {
+                rc.send(());
+                xr.read(|_state| { })
+            });
+            rp.recv(); // wait for reader task to exist
+
+            let read_mode = x.downgrade(write_mode);
+            read_mode.read(|state| {
+                // if writer mistakenly got in, make sure it mutates state
+                // before we assert on it
+                for _ in range(0, 5) { task::deschedule(); }
+                // make sure writer didn't get in.
+                assert!(*state);
+            })
+        });
+    }
+    #[test]
+    fn test_rw_write_cond_downgrade_read_race() {
+        // Ideally the above test case would have deschedule statements in it that
+        // helped to expose the race nearly 100% of the time... but adding
+        // deschedules in the intuitively-right locations made it even less likely,
+        // and I wasn't sure why :( . This is a mediocre "next best" option.
+        for _ in range(0, 8) { test_rw_write_cond_downgrade_read_race_helper(); }
+    }
+
+    #[test]
+    fn test_cowarc_clone()
+    {
+        let cow0 = CowArc::new(75u);
+        let cow1 = cow0.clone();
+        let cow2 = cow1.clone();
+
+        assert!(75 == *cow0.get());
+        assert!(75 == *cow1.get());
+        assert!(75 == *cow2.get());
+
+        assert!(cow0.get() == cow1.get());
+        assert!(cow0.get() == cow2.get());
+    }
+
+    #[test]
+    fn test_cowarc_clone_get_mut()
+    {
+        let mut cow0 = CowArc::new(75u);
+        let mut cow1 = cow0.clone();
+        let mut cow2 = cow1.clone();
+
+        assert!(75 == *cow0.get_mut());
+        assert!(75 == *cow1.get_mut());
+        assert!(75 == *cow2.get_mut());
+
+        *cow0.get_mut() += 1;
+        *cow1.get_mut() += 2;
+        *cow2.get_mut() += 3;
+
+        assert!(76 == *cow0.get());
+        assert!(77 == *cow1.get());
+        assert!(78 == *cow2.get());
+
+        // none should point to the same backing memory
+        assert!(cow0.get() != cow1.get());
+        assert!(cow0.get() != cow2.get());
+        assert!(cow1.get() != cow2.get());
+    }
+
+    #[test]
+    fn test_cowarc_clone_get_mut2()
+    {
+        let mut cow0 = CowArc::new(75u);
+        let cow1 = cow0.clone();
+        let cow2 = cow1.clone();
+
+        assert!(75 == *cow0.get());
+        assert!(75 == *cow1.get());
+        assert!(75 == *cow2.get());
+
+        *cow0.get_mut() += 1;
+
+        assert!(76 == *cow0.get());
+        assert!(75 == *cow1.get());
+        assert!(75 == *cow2.get());
+
+        // cow1 and cow2 should share the same contents
+        // cow0 should have a unique reference
+        assert!(cow0.get() != cow1.get());
+        assert!(cow0.get() != cow2.get());
+        assert!(cow1.get() == cow2.get());
+    }
+}
diff --git a/src/libsync/comm.rs b/src/libsync/comm.rs
new file mode 100644 (file)
index 0000000..c7d5507
--- /dev/null
@@ -0,0 +1,165 @@
+// Copyright 2012-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.
+
+/*!
+
+Higher level communication abstractions.
+
+*/
+
+#[allow(missing_doc)];
+
+use std::comm;
+
+/// An extension of `pipes::stream` that allows both sending and receiving.
+pub struct DuplexStream<T, U> {
+    priv chan: Chan<T>,
+    priv port: Port<U>,
+}
+
+// Allow these methods to be used without import:
+impl<T:Send,U:Send> DuplexStream<T, U> {
+    /// Creates a bidirectional stream.
+    pub fn new() -> (DuplexStream<T, U>, DuplexStream<U, T>) {
+        let (p1, c2) = Chan::new();
+        let (p2, c1) = Chan::new();
+        (DuplexStream { chan: c1, port: p1 },
+         DuplexStream { chan: c2, port: p2 })
+    }
+    pub fn send(&self, x: T) {
+        self.chan.send(x)
+    }
+    pub fn try_send(&self, x: T) -> bool {
+        self.chan.try_send(x)
+    }
+    pub fn recv(&self) -> U {
+        self.port.recv()
+    }
+    pub fn try_recv(&self) -> comm::TryRecvResult<U> {
+        self.port.try_recv()
+    }
+    pub fn recv_opt(&self) -> Option<U> {
+        self.port.recv_opt()
+    }
+}
+
+/// An extension of `pipes::stream` that provides synchronous message sending.
+pub struct SyncChan<T> { priv duplex_stream: DuplexStream<T, ()> }
+/// An extension of `pipes::stream` that acknowledges each message received.
+pub struct SyncPort<T> { priv duplex_stream: DuplexStream<(), T> }
+
+impl<T: Send> SyncChan<T> {
+    pub fn send(&self, val: T) {
+        assert!(self.try_send(val), "SyncChan.send: receiving port closed");
+    }
+
+    /// Sends a message, or report if the receiver has closed the connection
+    /// before receiving.
+    pub fn try_send(&self, val: T) -> bool {
+        self.duplex_stream.try_send(val) && self.duplex_stream.recv_opt().is_some()
+    }
+}
+
+impl<T: Send> SyncPort<T> {
+    pub fn recv(&self) -> T {
+        self.recv_opt().expect("SyncPort.recv: sending channel closed")
+    }
+
+    pub fn recv_opt(&self) -> Option<T> {
+        self.duplex_stream.recv_opt().map(|val| {
+            self.duplex_stream.try_send(());
+            val
+        })
+    }
+
+    pub fn try_recv(&self) -> comm::TryRecvResult<T> {
+        match self.duplex_stream.try_recv() {
+            comm::Data(t) => { self.duplex_stream.try_send(()); comm::Data(t) }
+            state => state,
+        }
+    }
+}
+
+/// Creates a stream whose channel, upon sending a message, blocks until the
+/// message is received.
+pub fn rendezvous<T: Send>() -> (SyncPort<T>, SyncChan<T>) {
+    let (chan_stream, port_stream) = DuplexStream::new();
+    (SyncPort { duplex_stream: port_stream },
+     SyncChan { duplex_stream: chan_stream })
+}
+
+#[cfg(test)]
+mod test {
+    use comm::{DuplexStream, rendezvous};
+
+
+    #[test]
+    pub fn DuplexStream1() {
+        let (left, right) = DuplexStream::new();
+
+        left.send(~"abc");
+        right.send(123);
+
+        assert!(left.recv() == 123);
+        assert!(right.recv() == ~"abc");
+    }
+
+    #[test]
+    pub fn basic_rendezvous_test() {
+        let (port, chan) = rendezvous();
+
+        spawn(proc() {
+            chan.send("abc");
+        });
+
+        assert!(port.recv() == "abc");
+    }
+
+    #[test]
+    fn recv_a_lot() {
+        // Rendezvous streams should be able to handle any number of messages being sent
+        let (port, chan) = rendezvous();
+        spawn(proc() {
+            for _ in range(0, 10000) { chan.send(()); }
+        });
+        for _ in range(0, 10000) { port.recv(); }
+    }
+
+    #[test]
+    fn send_and_fail_and_try_recv() {
+        let (port, chan) = rendezvous();
+        spawn(proc() {
+            chan.duplex_stream.send(()); // Can't access this field outside this module
+            fail!()
+        });
+        port.recv()
+    }
+
+    #[test]
+    fn try_send_and_recv_then_fail_before_ack() {
+        let (port, chan) = rendezvous();
+        spawn(proc() {
+            port.duplex_stream.recv();
+            fail!()
+        });
+        chan.try_send(());
+    }
+
+    #[test]
+    #[should_fail]
+    fn send_and_recv_then_fail_before_ack() {
+        let (port, chan) = rendezvous();
+        spawn(proc() {
+            port.duplex_stream.recv();
+            fail!()
+        });
+        chan.send(());
+    }
+}
diff --git a/src/libsync/future.rs b/src/libsync/future.rs
new file mode 100644 (file)
index 0000000..479174d
--- /dev/null
@@ -0,0 +1,205 @@
+// Copyright 2012-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.
+
+/*!
+ * A type representing values that may be computed concurrently and
+ * operations for working with them.
+ *
+ * # Example
+ *
+ * ```rust
+ * use sync::Future;
+ * # fn fib(n: uint) -> uint {42};
+ * # fn make_a_sandwich() {};
+ * let mut delayed_fib = Future::spawn(proc() { fib(5000) });
+ * make_a_sandwich();
+ * println!("fib(5000) = {}", delayed_fib.get())
+ * ```
+ */
+
+#[allow(missing_doc)];
+
+use std::util::replace;
+
+/// A type encapsulating the result of a computation which may not be complete
+pub struct Future<A> {
+    priv state: FutureState<A>,
+}
+
+enum FutureState<A> {
+    Pending(proc() -> A),
+    Evaluating,
+    Forced(A)
+}
+
+/// Methods on the `future` type
+impl<A:Clone> Future<A> {
+    pub fn get(&mut self) -> A {
+        //! Get the value of the future.
+        (*(self.get_ref())).clone()
+    }
+}
+
+impl<A> Future<A> {
+    /// Gets the value from this future, forcing evaluation.
+    pub fn unwrap(mut self) -> A {
+        self.get_ref();
+        let state = replace(&mut self.state, Evaluating);
+        match state {
+            Forced(v) => v,
+            _ => fail!( "Logic error." ),
+        }
+    }
+
+    pub fn get_ref<'a>(&'a mut self) -> &'a A {
+        /*!
+        * Executes the future's closure and then returns a reference
+        * to the result.  The reference lasts as long as
+        * the future.
+        */
+        match self.state {
+            Forced(ref v) => return v,
+            Evaluating => fail!("Recursive forcing of future!"),
+            Pending(_) => {
+                match replace(&mut self.state, Evaluating) {
+                    Forced(_) | Evaluating => fail!("Logic error."),
+                    Pending(f) => {
+                        self.state = Forced(f());
+                        self.get_ref()
+                    }
+                }
+            }
+        }
+    }
+
+    pub fn from_value(val: A) -> Future<A> {
+        /*!
+         * Create a future from a value.
+         *
+         * The value is immediately available and calling `get` later will
+         * not block.
+         */
+
+        Future {state: Forced(val)}
+    }
+
+    pub fn from_fn(f: proc() -> A) -> Future<A> {
+        /*!
+         * Create a future from a function.
+         *
+         * The first time that the value is requested it will be retrieved by
+         * calling the function.  Note that this function is a local
+         * function. It is not spawned into another task.
+         */
+
+        Future {state: Pending(f)}
+    }
+}
+
+impl<A:Send> Future<A> {
+    pub fn from_port(port: Port<A>) -> Future<A> {
+        /*!
+         * Create a future from a port
+         *
+         * The first time that the value is requested the task will block
+         * waiting for the result to be received on the port.
+         */
+
+        Future::from_fn(proc() {
+            port.recv()
+        })
+    }
+
+    pub fn spawn(blk: proc() -> A) -> Future<A> {
+        /*!
+         * Create a future from a unique closure.
+         *
+         * The closure will be run in a new task and its result used as the
+         * value of the future.
+         */
+
+        let (port, chan) = Chan::new();
+
+        spawn(proc() {
+            chan.send(blk());
+        });
+
+        Future::from_port(port)
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use future::Future;
+
+    use std::task;
+
+    #[test]
+    fn test_from_value() {
+        let mut f = Future::from_value(~"snail");
+        assert_eq!(f.get(), ~"snail");
+    }
+
+    #[test]
+    fn test_from_port() {
+        let (po, ch) = Chan::new();
+        ch.send(~"whale");
+        let mut f = Future::from_port(po);
+        assert_eq!(f.get(), ~"whale");
+    }
+
+    #[test]
+    fn test_from_fn() {
+        let mut f = Future::from_fn(proc() ~"brail");
+        assert_eq!(f.get(), ~"brail");
+    }
+
+    #[test]
+    fn test_interface_get() {
+        let mut f = Future::from_value(~"fail");
+        assert_eq!(f.get(), ~"fail");
+    }
+
+    #[test]
+    fn test_interface_unwrap() {
+        let f = Future::from_value(~"fail");
+        assert_eq!(f.unwrap(), ~"fail");
+    }
+
+    #[test]
+    fn test_get_ref_method() {
+        let mut f = Future::from_value(22);
+        assert_eq!(*f.get_ref(), 22);
+    }
+
+    #[test]
+    fn test_spawn() {
+        let mut f = Future::spawn(proc() ~"bale");
+        assert_eq!(f.get(), ~"bale");
+    }
+
+    #[test]
+    #[should_fail]
+    fn test_futurefail() {
+        let mut f = Future::spawn(proc() fail!());
+        let _x: ~str = f.get();
+    }
+
+    #[test]
+    fn test_sendable_future() {
+        let expected = "schlorf";
+        let f = Future::spawn(proc() { expected });
+        task::spawn(proc() {
+            let mut f = f;
+            let actual = f.get();
+            assert_eq!(actual, expected);
+        });
+    }
+}
diff --git a/src/libsync/lib.rs b/src/libsync/lib.rs
new file mode 100644 (file)
index 0000000..de1b0f9
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright 2012-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.
+
+/*!
+ * Concurrency-enabled mechanisms and primitives.
+ */
+
+#[crate_id = "sync#0.10-pre"];
+#[crate_type = "rlib"];
+#[crate_type = "dylib"];
+#[license = "MIT/ASL2"];
+
+pub use arc::{Arc, MutexArc, RWArc, RWWriteMode, RWReadMode, Condvar};
+pub use sync::{Mutex, RWLock, Condvar, Semaphore, RWLockWriteMode,
+    RWLockReadMode, Barrier, one, mutex};
+pub use comm::{DuplexStream, SyncChan, SyncPort, rendezvous};
+pub use task_pool::TaskPool;
+pub use future::Future;
+
+mod arc;
+mod sync;
+mod comm;
+mod task_pool;
+mod future;
diff --git a/src/libsync/sync/mod.rs b/src/libsync/sync/mod.rs
new file mode 100644 (file)
index 0000000..cfff31e
--- /dev/null
@@ -0,0 +1,1420 @@
+// Copyright 2012-2014 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.
+
+#[allow(missing_doc)];
+
+/**
+ * The concurrency primitives you know and love.
+ *
+ * Maybe once we have a "core exports x only to std" mechanism, these can be
+ * in std.
+ */
+
+use std::cast;
+use std::comm;
+use std::kinds::marker;
+use std::sync::arc::UnsafeArc;
+use std::sync::atomics;
+use std::unstable::finally::Finally;
+use std::util;
+
+use arc::MutexArc;
+
+/****************************************************************************
+ * Internals
+ ****************************************************************************/
+
+pub mod mutex;
+pub mod one;
+mod mpsc_intrusive;
+
+// Each waiting task receives on one of these.
+#[doc(hidden)]
+type WaitEnd = Port<()>;
+#[doc(hidden)]
+type SignalEnd = Chan<()>;
+// A doubly-ended queue of waiting tasks.
+#[doc(hidden)]
+struct WaitQueue { head: Port<SignalEnd>,
+                   tail: Chan<SignalEnd> }
+
+impl WaitQueue {
+    fn new() -> WaitQueue {
+        let (block_head, block_tail) = Chan::new();
+        WaitQueue { head: block_head, tail: block_tail }
+    }
+
+    // Signals one live task from the queue.
+    fn signal(&self) -> bool {
+        match self.head.try_recv() {
+            comm::Data(ch) => {
+                // Send a wakeup signal. If the waiter was killed, its port will
+                // have closed. Keep trying until we get a live task.
+                if ch.try_send(()) {
+                    true
+                } else {
+                    self.signal()
+                }
+            }
+            _ => false
+        }
+    }
+
+    fn broadcast(&self) -> uint {
+        let mut count = 0;
+        loop {
+            match self.head.try_recv() {
+                comm::Data(ch) => {
+                    if ch.try_send(()) {
+                        count += 1;
+                    }
+                }
+                _ => break
+            }
+        }
+        count
+    }
+
+    fn wait_end(&self) -> WaitEnd {
+        let (wait_end, signal_end) = Chan::new();
+        assert!(self.tail.try_send(signal_end));
+        wait_end
+    }
+}
+
+// The building-block used to make semaphores, mutexes, and rwlocks.
+struct SemInner<Q> {
+    lock: mutex::Mutex,
+    count: int,
+    waiters:   WaitQueue,
+    // Can be either unit or another waitqueue. Some sems shouldn't come with
+    // a condition variable attached, others should.
+    blocked:   Q
+}
+
+struct Sem<Q>(UnsafeArc<SemInner<Q>>);
+
+#[doc(hidden)]
+impl<Q:Send> Sem<Q> {
+    fn new(count: int, q: Q) -> Sem<Q> {
+        Sem(UnsafeArc::new(SemInner {
+            count: count,
+            waiters: WaitQueue::new(),
+            blocked: q,
+            lock: mutex::Mutex::new(),
+        }))
+    }
+
+    unsafe fn with(&self, f: |&mut SemInner<Q>|) {
+        let Sem(ref arc) = *self;
+        let state = arc.get();
+        let _g = (*state).lock.lock();
+        f(cast::transmute(state));
+    }
+
+    pub fn acquire(&self) {
+        unsafe {
+            let mut waiter_nobe = None;
+            self.with(|state| {
+                state.count -= 1;
+                if state.count < 0 {
+                    // Create waiter nobe, enqueue ourself, and tell
+                    // outer scope we need to block.
+                    waiter_nobe = Some(state.waiters.wait_end());
+                }
+            });
+            // Uncomment if you wish to test for sem races. Not valgrind-friendly.
+            /* for _ in range(0, 1000) { task::deschedule(); } */
+            // Need to wait outside the exclusive.
+            if waiter_nobe.is_some() {
+                let _ = waiter_nobe.unwrap().recv();
+            }
+        }
+    }
+
+    pub fn release(&self) {
+        unsafe {
+            self.with(|state| {
+                state.count += 1;
+                if state.count <= 0 {
+                    state.waiters.signal();
+                }
+            })
+        }
+    }
+
+    pub fn access<U>(&self, blk: || -> U) -> U {
+        (|| {
+            self.acquire();
+            blk()
+        }).finally(|| {
+            self.release();
+        })
+    }
+}
+
+#[doc(hidden)]
+impl Sem<~[WaitQueue]> {
+    fn new_and_signal(count: int, num_condvars: uint)
+        -> Sem<~[WaitQueue]> {
+        let mut queues = ~[];
+        for _ in range(0, num_condvars) { queues.push(WaitQueue::new()); }
+        Sem::new(count, queues)
+    }
+}
+
+// FIXME(#3598): Want to use an Option down below, but we need a custom enum
+// that's not polymorphic to get around the fact that lifetimes are invariant
+// inside of type parameters.
+enum ReacquireOrderLock<'a> {
+    Nothing, // c.c
+    Just(&'a Semaphore),
+}
+
+/// A mechanism for atomic-unlock-and-deschedule blocking and signalling.
+pub struct Condvar<'a> {
+    // The 'Sem' object associated with this condvar. This is the one that's
+    // atomically-unlocked-and-descheduled upon and reacquired during wakeup.
+    priv sem: &'a Sem<~[WaitQueue]>,
+    // This is (can be) an extra semaphore which is held around the reacquire
+    // operation on the first one. This is only used in cvars associated with
+    // rwlocks, and is needed to ensure that, when a downgrader is trying to
+    // hand off the access lock (which would be the first field, here), a 2nd
+    // writer waking up from a cvar wait can't race with a reader to steal it,
+    // See the comment in write_cond for more detail.
+    priv order: ReacquireOrderLock<'a>,
+    // Make sure condvars are non-copyable.
+    priv nopod: marker::NoPod,
+}
+
+impl<'a> Condvar<'a> {
+    /**
+     * Atomically drop the associated lock, and block until a signal is sent.
+     *
+     * # Failure
+     * A task which is killed (i.e., by linked failure with another task)
+     * while waiting on a condition variable will wake up, fail, and unlock
+     * the associated lock as it unwinds.
+     */
+    pub fn wait(&self) { self.wait_on(0) }
+
+    /**
+     * As wait(), but can specify which of multiple condition variables to
+     * wait on. Only a signal_on() or broadcast_on() with the same condvar_id
+     * will wake this thread.
+     *
+     * The associated lock must have been initialised with an appropriate
+     * number of condvars. The condvar_id must be between 0 and num_condvars-1
+     * or else this call will fail.
+     *
+     * wait() is equivalent to wait_on(0).
+     */
+    pub fn wait_on(&self, condvar_id: uint) {
+        let mut WaitEnd = None;
+        let mut out_of_bounds = None;
+        // Release lock, 'atomically' enqueuing ourselves in so doing.
+        unsafe {
+            self.sem.with(|state| {
+                if condvar_id < state.blocked.len() {
+                    // Drop the lock.
+                    state.count += 1;
+                    if state.count <= 0 {
+                        state.waiters.signal();
+                    }
+                    // Create waiter nobe, and enqueue ourself to
+                    // be woken up by a signaller.
+                    WaitEnd = Some(state.blocked[condvar_id].wait_end());
+                } else {
+                    out_of_bounds = Some(state.blocked.len());
+                }
+            })
+        }
+
+        // If deschedule checks start getting inserted anywhere, we can be
+        // killed before or after enqueueing.
+        check_cvar_bounds(out_of_bounds, condvar_id, "cond.wait_on()", || {
+            // Unconditionally "block". (Might not actually block if a
+            // signaller already sent -- I mean 'unconditionally' in contrast
+            // with acquire().)
+            (|| {
+                let _ = WaitEnd.take_unwrap().recv();
+            }).finally(|| {
+                // Reacquire the condvar.
+                match self.order {
+                    Just(lock) => lock.access(|| self.sem.acquire()),
+                    Nothing => self.sem.acquire(),
+                }
+            })
+        })
+    }
+
+    /// Wake up a blocked task. Returns false if there was no blocked task.
+    pub fn signal(&self) -> bool { self.signal_on(0) }
+
+    /// As signal, but with a specified condvar_id. See wait_on.
+    pub fn signal_on(&self, condvar_id: uint) -> bool {
+        unsafe {
+            let mut out_of_bounds = None;
+            let mut result = false;
+            self.sem.with(|state| {
+                if condvar_id < state.blocked.len() {
+                    result = state.blocked[condvar_id].signal();
+                } else {
+                    out_of_bounds = Some(state.blocked.len());
+                }
+            });
+            check_cvar_bounds(out_of_bounds,
+                              condvar_id,
+                              "cond.signal_on()",
+                              || result)
+        }
+    }
+
+    /// Wake up all blocked tasks. Returns the number of tasks woken.
+    pub fn broadcast(&self) -> uint { self.broadcast_on(0) }
+
+    /// As broadcast, but with a specified condvar_id. See wait_on.
+    pub fn broadcast_on(&self, condvar_id: uint) -> uint {
+        let mut out_of_bounds = None;
+        let mut queue = None;
+        unsafe {
+            self.sem.with(|state| {
+                if condvar_id < state.blocked.len() {
+                    // To avoid :broadcast_heavy, we make a new waitqueue,
+                    // swap it out with the old one, and broadcast on the
+                    // old one outside of the little-lock.
+                    queue = Some(util::replace(&mut state.blocked[condvar_id],
+                                               WaitQueue::new()));
+                } else {
+                    out_of_bounds = Some(state.blocked.len());
+                }
+            });
+            check_cvar_bounds(out_of_bounds,
+                              condvar_id,
+                              "cond.signal_on()",
+                              || {
+                queue.take_unwrap().broadcast()
+            })
+        }
+    }
+}
+
+// Checks whether a condvar ID was out of bounds, and fails if so, or does
+// something else next on success.
+#[inline]
+#[doc(hidden)]
+fn check_cvar_bounds<U>(
+                     out_of_bounds: Option<uint>,
+                     id: uint,
+                     act: &str,
+                     blk: || -> U)
+                     -> U {
+    match out_of_bounds {
+        Some(0) =>
+            fail!("{} with illegal ID {} - this lock has no condvars!", act, id),
+        Some(length) =>
+            fail!("{} with illegal ID {} - ID must be less than {}", act, id, length),
+        None => blk()
+    }
+}
+
+#[doc(hidden)]
+impl Sem<~[WaitQueue]> {
+    // The only other places that condvars get built are rwlock.write_cond()
+    // and rwlock_write_mode.
+    pub fn access_cond<U>(&self, blk: |c: &Condvar| -> U) -> U {
+        self.access(|| {
+            blk(&Condvar {
+                sem: self,
+                order: Nothing,
+                nopod: marker::NoPod
+            })
+        })
+    }
+}
+
+/****************************************************************************
+ * Semaphores
+ ****************************************************************************/
+
+/// A counting, blocking, bounded-waiting semaphore.
+pub struct Semaphore { priv sem: Sem<()> }
+
+
+impl Clone for Semaphore {
+    /// Create a new handle to the semaphore.
+    fn clone(&self) -> Semaphore {
+        let Sem(ref lock) = self.sem;
+        Semaphore { sem: Sem(lock.clone()) }
+    }
+}
+
+impl Semaphore {
+    /// Create a new semaphore with the specified count.
+    pub fn new(count: int) -> Semaphore {
+        Semaphore { sem: Sem::new(count, ()) }
+    }
+
+    /**
+     * Acquire a resource represented by the semaphore. Blocks if necessary
+     * until resource(s) become available.
+     */
+    pub fn acquire(&self) { (&self.sem).acquire() }
+
+    /**
+     * Release a held resource represented by the semaphore. Wakes a blocked
+     * contending task, if any exist. Won't block the caller.
+     */
+    pub fn release(&self) { (&self.sem).release() }
+
+    /// Run a function with ownership of one of the semaphore's resources.
+    pub fn access<U>(&self, blk: || -> U) -> U { (&self.sem).access(blk) }
+}
+
+/****************************************************************************
+ * Mutexes
+ ****************************************************************************/
+
+/**
+ * A blocking, bounded-waiting, mutual exclusion lock with an associated
+ * FIFO condition variable.
+ *
+ * # Failure
+ * A task which fails while holding a mutex will unlock the mutex as it
+ * unwinds.
+ */
+
+pub struct Mutex { priv sem: Sem<~[WaitQueue]> }
+impl Clone for Mutex {
+    /// Create a new handle to the mutex.
+    fn clone(&self) -> Mutex {
+        let Sem(ref queue) = self.sem;
+        Mutex { sem: Sem(queue.clone()) } }
+}
+
+impl Mutex {
+    /// Create a new mutex, with one associated condvar.
+    pub fn new() -> Mutex { Mutex::new_with_condvars(1) }
+
+    /**
+    * Create a new mutex, with a specified number of associated condvars. This
+    * will allow calling wait_on/signal_on/broadcast_on with condvar IDs between
+    * 0 and num_condvars-1. (If num_condvars is 0, lock_cond will be allowed but
+    * any operations on the condvar will fail.)
+    */
+    pub fn new_with_condvars(num_condvars: uint) -> Mutex {
+        Mutex { sem: Sem::new_and_signal(1, num_condvars) }
+    }
+
+
+    /// Run a function with ownership of the mutex.
+    pub fn lock<U>(&self, blk: || -> U) -> U {
+        (&self.sem).access(blk)
+    }
+
+    /// Run a function with ownership of the mutex and a handle to a condvar.
+    pub fn lock_cond<U>(&self, blk: |c: &Condvar| -> U) -> U {
+        (&self.sem).access_cond(blk)
+    }
+}
+
+/****************************************************************************
+ * Reader-writer locks
+ ****************************************************************************/
+
+// NB: Wikipedia - Readers-writers_problem#The_third_readers-writers_problem
+
+#[doc(hidden)]
+struct RWLockInner {
+    // You might ask, "Why don't you need to use an atomic for the mode flag?"
+    // This flag affects the behaviour of readers (for plain readers, they
+    // assert on it; for downgraders, they use it to decide which mode to
+    // unlock for). Consider that the flag is only unset when the very last
+    // reader exits; therefore, it can never be unset during a reader/reader
+    // (or reader/downgrader) race.
+    // By the way, if we didn't care about the assert in the read unlock path,
+    // we could instead store the mode flag in write_downgrade's stack frame,
+    // and have the downgrade tokens store a reference to it.
+    read_mode:  bool,
+    // The only way the count flag is ever accessed is with xadd. Since it is
+    // a read-modify-write operation, multiple xadds on different cores will
+    // always be consistent with respect to each other, so a monotonic/relaxed
+    // consistency ordering suffices (i.e., no extra barriers are needed).
+    // FIXME(#6598): The atomics module has no relaxed ordering flag, so I use
+    // acquire/release orderings superfluously. Change these someday.
+    read_count: atomics::AtomicUint,
+}
+
+/**
+ * A blocking, no-starvation, reader-writer lock with an associated condvar.
+ *
+ * # Failure
+ * A task which fails while holding an rwlock will unlock the rwlock as it
+ * unwinds.
+ */
+pub struct RWLock {
+    priv order_lock:  Semaphore,
+    priv access_lock: Sem<~[WaitQueue]>,
+    priv state:       UnsafeArc<RWLockInner>,
+}
+
+impl RWLock {
+    /// Create a new rwlock, with one associated condvar.
+    pub fn new() -> RWLock { RWLock::new_with_condvars(1) }
+
+    /**
+    * Create a new rwlock, with a specified number of associated condvars.
+    * Similar to mutex_with_condvars.
+    */
+    pub fn new_with_condvars(num_condvars: uint) -> RWLock {
+        let state = UnsafeArc::new(RWLockInner {
+            read_mode:  false,
+            read_count: atomics::AtomicUint::new(0),
+        });
+        RWLock { order_lock:  Semaphore::new(1),
+                access_lock: Sem::new_and_signal(1, num_condvars),
+                state:       state, }
+    }
+
+    /// Create a new handle to the rwlock.
+    pub fn clone(&self) -> RWLock {
+        let Sem(ref access_lock_queue) = self.access_lock;
+        RWLock { order_lock:  (&(self.order_lock)).clone(),
+                 access_lock: Sem(access_lock_queue.clone()),
+                 state:       self.state.clone() }
+    }
+
+    /**
+     * Run a function with the rwlock in read mode. Calls to 'read' from other
+     * tasks may run concurrently with this one.
+     */
+    pub fn read<U>(&self, blk: || -> U) -> U {
+        unsafe {
+            (&self.order_lock).access(|| {
+                let state = &mut *self.state.get();
+                let old_count = state.read_count.fetch_add(1, atomics::Acquire);
+                if old_count == 0 {
+                    (&self.access_lock).acquire();
+                    state.read_mode = true;
+                }
+            });
+            (|| {
+                blk()
+            }).finally(|| {
+                let state = &mut *self.state.get();
+                assert!(state.read_mode);
+                let old_count = state.read_count.fetch_sub(1, atomics::Release);
+                assert!(old_count > 0);
+                if old_count == 1 {
+                    state.read_mode = false;
+                    // Note: this release used to be outside of a locked access
+                    // to exclusive-protected state. If this code is ever
+                    // converted back to such (instead of using atomic ops),
+                    // this access MUST NOT go inside the exclusive access.
+                    (&self.access_lock).release();
+                }
+            })
+        }
+    }
+
+    /**
+     * Run a function with the rwlock in write mode. No calls to 'read' or
+     * 'write' from other tasks will run concurrently with this one.
+     */
+    pub fn write<U>(&self, blk: || -> U) -> U {
+        (&self.order_lock).acquire();
+        (&self.access_lock).access(|| {
+            (&self.order_lock).release();
+            blk()
+        })
+    }
+
+    /**
+     * As write(), but also with a handle to a condvar. Waiting on this
+     * condvar will allow readers and writers alike to take the rwlock before
+     * the waiting task is signalled. (Note: a writer that waited and then
+     * was signalled might reacquire the lock before other waiting writers.)
+     */
+    pub fn write_cond<U>(&self, blk: |c: &Condvar| -> U) -> U {
+        // It's important to thread our order lock into the condvar, so that
+        // when a cond.wait() wakes up, it uses it while reacquiring the
+        // access lock. If we permitted a waking-up writer to "cut in line",
+        // there could arise a subtle race when a downgrader attempts to hand
+        // off the reader cloud lock to a waiting reader. This race is tested
+        // in arc.rs (test_rw_write_cond_downgrade_read_race) and looks like:
+        // T1 (writer)              T2 (downgrader)             T3 (reader)
+        // [in cond.wait()]
+        //                          [locks for writing]
+        //                          [holds access_lock]
+        // [is signalled, perhaps by
+        //  downgrader or a 4th thread]
+        // tries to lock access(!)
+        //                                                      lock order_lock
+        //                                                      xadd read_count[0->1]
+        //                                                      tries to lock access
+        //                          [downgrade]
+        //                          xadd read_count[1->2]
+        //                          unlock access
+        // Since T1 contended on the access lock before T3 did, it will steal
+        // the lock handoff. Adding order_lock in the condvar reacquire path
+        // solves this because T1 will hold order_lock while waiting on access,
+        // which will cause T3 to have to wait until T1 finishes its write,
+        // which can't happen until T2 finishes the downgrade-read entirely.
+        // The astute reader will also note that making waking writers use the
+        // order_lock is better for not starving readers.
+        (&self.order_lock).acquire();
+        (&self.access_lock).access_cond(|cond| {
+            (&self.order_lock).release();
+            let opt_lock = Just(&self.order_lock);
+            blk(&Condvar { sem: cond.sem, order: opt_lock,
+                           nopod: marker::NoPod })
+        })
+    }
+
+    /**
+     * As write(), but with the ability to atomically 'downgrade' the lock;
+     * i.e., to become a reader without letting other writers get the lock in
+     * the meantime (such as unlocking and then re-locking as a reader would
+     * do). The block takes a "write mode token" argument, which can be
+     * transformed into a "read mode token" by calling downgrade(). Example:
+     *
+     * # Example
+     *
+     * ```rust
+     * use sync::RWLock;
+     *
+     * let lock = RWLock::new();
+     * lock.write_downgrade(|mut write_token| {
+     *     write_token.write_cond(|condvar| {
+     *         // ... exclusive access ...
+     *     });
+     *     let read_token = lock.downgrade(write_token);
+     *     read_token.read(|| {
+     *         // ... shared access ...
+     *     })
+     * })
+     * ```
+     */
+    pub fn write_downgrade<U>(&self, blk: |v: RWLockWriteMode| -> U) -> U {
+        // Implementation slightly different from the slicker 'write's above.
+        // The exit path is conditional on whether the caller downgrades.
+        (&self.order_lock).acquire();
+        (&self.access_lock).acquire();
+        (&self.order_lock).release();
+        (|| {
+            blk(RWLockWriteMode { lock: self, nopod: marker::NoPod })
+        }).finally(|| {
+            let writer_or_last_reader;
+            // Check if we're releasing from read mode or from write mode.
+            let state = unsafe { &mut *self.state.get() };
+            if state.read_mode {
+                // Releasing from read mode.
+                let old_count = state.read_count.fetch_sub(1, atomics::Release);
+                assert!(old_count > 0);
+                // Check if other readers remain.
+                if old_count == 1 {
+                    // Case 1: Writer downgraded & was the last reader
+                    writer_or_last_reader = true;
+                    state.read_mode = false;
+                } else {
+                    // Case 2: Writer downgraded & was not the last reader
+                    writer_or_last_reader = false;
+                }
+            } else {
+                // Case 3: Writer did not downgrade
+                writer_or_last_reader = true;
+            }
+            if writer_or_last_reader {
+                // Nobody left inside; release the "reader cloud" lock.
+                (&self.access_lock).release();
+            }
+        })
+    }
+
+    /// To be called inside of the write_downgrade block.
+    pub fn downgrade<'a>(&self, token: RWLockWriteMode<'a>)
+                         -> RWLockReadMode<'a> {
+        if !((self as *RWLock) == (token.lock as *RWLock)) {
+            fail!("Can't downgrade() with a different rwlock's write_mode!");
+        }
+        unsafe {
+            let state = &mut *self.state.get();
+            assert!(!state.read_mode);
+            state.read_mode = true;
+            // If a reader attempts to enter at this point, both the
+            // downgrader and reader will set the mode flag. This is fine.
+            let old_count = state.read_count.fetch_add(1, atomics::Release);
+            // If another reader was already blocking, we need to hand-off
+            // the "reader cloud" access lock to them.
+            if old_count != 0 {
+                // Guaranteed not to let another writer in, because
+                // another reader was holding the order_lock. Hence they
+                // must be the one to get the access_lock (because all
+                // access_locks are acquired with order_lock held). See
+                // the comment in write_cond for more justification.
+                (&self.access_lock).release();
+            }
+        }
+        RWLockReadMode { lock: token.lock, nopod: marker::NoPod }
+    }
+}
+
+/// The "write permission" token used for rwlock.write_downgrade().
+
+pub struct RWLockWriteMode<'a> { priv lock: &'a RWLock, priv nopod: marker::NoPod }
+/// The "read permission" token used for rwlock.write_downgrade().
+pub struct RWLockReadMode<'a> { priv lock: &'a RWLock,
+                                   priv nopod: marker::NoPod }
+
+impl<'a> RWLockWriteMode<'a> {
+    /// Access the pre-downgrade rwlock in write mode.
+    pub fn write<U>(&self, blk: || -> U) -> U { blk() }
+    /// Access the pre-downgrade rwlock in write mode with a condvar.
+    pub fn write_cond<U>(&self, blk: |c: &Condvar| -> U) -> U {
+        // Need to make the condvar use the order lock when reacquiring the
+        // access lock. See comment in RWLock::write_cond for why.
+        blk(&Condvar { sem:        &self.lock.access_lock,
+                       order: Just(&self.lock.order_lock),
+                       nopod: marker::NoPod })
+    }
+}
+
+impl<'a> RWLockReadMode<'a> {
+    /// Access the post-downgrade rwlock in read mode.
+    pub fn read<U>(&self, blk: || -> U) -> U { blk() }
+}
+
+/// A barrier enables multiple tasks to synchronize the beginning
+/// of some computation.
+///
+/// ```rust
+/// use sync::Barrier;
+///
+/// let barrier = Barrier::new(10);
+/// for _ in range(0, 10) {
+///     let c = barrier.clone();
+///     // The same messages will be printed together.
+///     // You will NOT see any interleaving.
+///     spawn(proc() {
+///         println!("before wait");
+///         c.wait();
+///         println!("after wait");
+///     });
+/// }
+/// ```
+#[deriving(Clone)]
+pub struct Barrier {
+    priv arc: MutexArc<BarrierState>,
+    priv num_tasks: uint,
+}
+
+// The inner state of a double barrier
+struct BarrierState {
+    count: uint,
+    generation_id: uint,
+}
+
+impl Barrier {
+    /// Create a new barrier that can block a given number of tasks.
+    pub fn new(num_tasks: uint) -> Barrier {
+        Barrier {
+            arc: MutexArc::new(BarrierState {
+                count: 0,
+                generation_id: 0,
+            }),
+            num_tasks: num_tasks,
+        }
+    }
+
+    /// Block the current task until a certain number of tasks is waiting.
+    pub fn wait(&self) {
+        self.arc.access_cond(|state, cond| {
+            let local_gen = state.generation_id;
+            state.count += 1;
+            if state.count < self.num_tasks {
+                // We need a while loop to guard against spurious wakeups.
+                // http://en.wikipedia.org/wiki/Spurious_wakeup
+                while local_gen == state.generation_id && state.count < self.num_tasks {
+                    cond.wait();
+                }
+            } else {
+                state.count = 0;
+                state.generation_id += 1;
+                cond.broadcast();
+            }
+        });
+    }
+}
+
+/****************************************************************************
+ * Tests
+ ****************************************************************************/
+
+#[cfg(test)]
+mod tests {
+    use sync::{Semaphore, Mutex, RWLock, Barrier, Condvar};
+
+    use std::cast;
+    use std::result;
+    use std::task;
+    use std::comm::{SharedChan, Empty};
+
+    /************************************************************************
+     * Semaphore tests
+     ************************************************************************/
+    #[test]
+    fn test_sem_acquire_release() {
+        let s = Semaphore::new(1);
+        s.acquire();
+        s.release();
+        s.acquire();
+    }
+    #[test]
+    fn test_sem_basic() {
+        let s = Semaphore::new(1);
+        s.access(|| { })
+    }
+    #[test]
+    fn test_sem_as_mutex() {
+        let s = Semaphore::new(1);
+        let s2 = s.clone();
+        task::spawn(proc() {
+            s2.access(|| {
+                for _ in range(0, 5) { task::deschedule(); }
+            })
+        });
+        s.access(|| {
+            for _ in range(0, 5) { task::deschedule(); }
+        })
+    }
+    #[test]
+    fn test_sem_as_cvar() {
+        /* Child waits and parent signals */
+        let (p, c) = Chan::new();
+        let s = Semaphore::new(0);
+        let s2 = s.clone();
+        task::spawn(proc() {
+            s2.acquire();
+            c.send(());
+        });
+        for _ in range(0, 5) { task::deschedule(); }
+        s.release();
+        let _ = p.recv();
+
+        /* Parent waits and child signals */
+        let (p, c) = Chan::new();
+        let s = Semaphore::new(0);
+        let s2 = s.clone();
+        task::spawn(proc() {
+            for _ in range(0, 5) { task::deschedule(); }
+            s2.release();
+            let _ = p.recv();
+        });
+        s.acquire();
+        c.send(());
+    }
+    #[test]
+    fn test_sem_multi_resource() {
+        // Parent and child both get in the critical section at the same
+        // time, and shake hands.
+        let s = Semaphore::new(2);
+        let s2 = s.clone();
+        let (p1,c1) = Chan::new();
+        let (p2,c2) = Chan::new();
+        task::spawn(proc() {
+            s2.access(|| {
+                let _ = p2.recv();
+                c1.send(());
+            })
+        });
+        s.access(|| {
+            c2.send(());
+            let _ = p1.recv();
+        })
+    }
+    #[test]
+    fn test_sem_runtime_friendly_blocking() {
+        // Force the runtime to schedule two threads on the same sched_loop.
+        // When one blocks, it should schedule the other one.
+        let s = Semaphore::new(1);
+        let s2 = s.clone();
+        let (p, c) = Chan::new();
+        let mut child_data = Some((s2, c));
+        s.access(|| {
+            let (s2, c) = child_data.take_unwrap();
+            task::spawn(proc() {
+                c.send(());
+                s2.access(|| { });
+                c.send(());
+            });
+            let _ = p.recv(); // wait for child to come alive
+            for _ in range(0, 5) { task::deschedule(); } // let the child contend
+        });
+        let _ = p.recv(); // wait for child to be done
+    }
+    /************************************************************************
+     * Mutex tests
+     ************************************************************************/
+    #[test]
+    fn test_mutex_lock() {
+        // Unsafely achieve shared state, and do the textbook
+        // "load tmp = move ptr; inc tmp; store ptr <- tmp" dance.
+        let (p, c) = Chan::new();
+        let m = Mutex::new();
+        let m2 = m.clone();
+        let mut sharedstate = ~0;
+        {
+            let ptr: *int = &*sharedstate;
+            task::spawn(proc() {
+                let sharedstate: &mut int =
+                    unsafe { cast::transmute(ptr) };
+                access_shared(sharedstate, &m2, 10);
+                c.send(());
+            });
+        }
+        {
+            access_shared(sharedstate, &m, 10);
+            let _ = p.recv();
+
+            assert_eq!(*sharedstate, 20);
+        }
+
+        fn access_shared(sharedstate: &mut int, m: &Mutex, n: uint) {
+            for _ in range(0, n) {
+                m.lock(|| {
+                    let oldval = *sharedstate;
+                    task::deschedule();
+                    *sharedstate = oldval + 1;
+                })
+            }
+        }
+    }
+    #[test]
+    fn test_mutex_cond_wait() {
+        let m = Mutex::new();
+
+        // Child wakes up parent
+        m.lock_cond(|cond| {
+            let m2 = m.clone();
+            task::spawn(proc() {
+                m2.lock_cond(|cond| {
+                    let woken = cond.signal();
+                    assert!(woken);
+                })
+            });
+            cond.wait();
+        });
+        // Parent wakes up child
+        let (port,chan) = Chan::new();
+        let m3 = m.clone();
+        task::spawn(proc() {
+            m3.lock_cond(|cond| {
+                chan.send(());
+                cond.wait();
+                chan.send(());
+            })
+        });
+        let _ = port.recv(); // Wait until child gets in the mutex
+        m.lock_cond(|cond| {
+            let woken = cond.signal();
+            assert!(woken);
+        });
+        let _ = port.recv(); // Wait until child wakes up
+    }
+    #[cfg(test)]
+    fn test_mutex_cond_broadcast_helper(num_waiters: uint) {
+        let m = Mutex::new();
+        let mut ports = ~[];
+
+        for _ in range(0, num_waiters) {
+            let mi = m.clone();
+            let (port, chan) = Chan::new();
+            ports.push(port);
+            task::spawn(proc() {
+                mi.lock_cond(|cond| {
+                    chan.send(());
+                    cond.wait();
+                    chan.send(());
+                })
+            });
+        }
+
+        // wait until all children get in the mutex
+        for port in ports.mut_iter() { let _ = port.recv(); }
+        m.lock_cond(|cond| {
+            let num_woken = cond.broadcast();
+            assert_eq!(num_woken, num_waiters);
+        });
+        // wait until all children wake up
+        for port in ports.mut_iter() { let _ = port.recv(); }
+    }
+    #[test]
+    fn test_mutex_cond_broadcast() {
+        test_mutex_cond_broadcast_helper(12);
+    }
+    #[test]
+    fn test_mutex_cond_broadcast_none() {
+        test_mutex_cond_broadcast_helper(0);
+    }
+    #[test]
+    fn test_mutex_cond_no_waiter() {
+        let m = Mutex::new();
+        let m2 = m.clone();
+        let _ = task::try(proc() {
+            m.lock_cond(|_x| { })
+        });
+        m2.lock_cond(|cond| {
+            assert!(!cond.signal());
+        })
+    }
+    #[test]
+    fn test_mutex_killed_simple() {
+        // Mutex must get automatically unlocked if failed/killed within.
+        let m = Mutex::new();
+        let m2 = m.clone();
+
+        let result: result::Result<(), ~Any> = task::try(proc() {
+            m2.lock(|| {
+                fail!();
+            })
+        });
+        assert!(result.is_err());
+        // child task must have finished by the time try returns
+        m.lock(|| { })
+    }
+    #[ignore(reason = "linked failure")]
+    #[test]
+    fn test_mutex_killed_cond() {
+        // Getting killed during cond wait must not corrupt the mutex while
+        // unwinding (e.g. double unlock).
+        let m = Mutex::new();
+        let m2 = m.clone();
+
+        let result: result::Result<(), ~Any> = task::try(proc() {
+            let (p, c) = Chan::new();
+            task::spawn(proc() { // linked
+                let _ = p.recv(); // wait for sibling to get in the mutex
+                task::deschedule();
+                fail!();
+            });
+            m2.lock_cond(|cond| {
+                c.send(()); // tell sibling go ahead
+                cond.wait(); // block forever
+            })
+        });
+        assert!(result.is_err());
+        // child task must have finished by the time try returns
+        m.lock_cond(|cond| {
+            let woken = cond.signal();
+            assert!(!woken);
+        })
+    }
+    #[ignore(reason = "linked failure")]
+    #[test]
+    fn test_mutex_killed_broadcast() {
+        use std::unstable::finally::Finally;
+
+        let m = Mutex::new();
+        let m2 = m.clone();
+        let (p, c) = Chan::new();
+
+        let result: result::Result<(), ~Any> = task::try(proc() {
+            let mut sibling_convos = ~[];
+            for _ in range(0, 2) {
+                let (p, c) = Chan::new();
+                sibling_convos.push(p);
+                let mi = m2.clone();
+                // spawn sibling task
+                task::spawn(proc() { // linked
+                    mi.lock_cond(|cond| {
+                        c.send(()); // tell sibling to go ahead
+                        (|| {
+                            cond.wait(); // block forever
+                        }).finally(|| {
+                            error!("task unwinding and sending");
+                            c.send(());
+                            error!("task unwinding and done sending");
+                        })
+                    })
+                });
+            }
+            for p in sibling_convos.mut_iter() {
+                let _ = p.recv(); // wait for sibling to get in the mutex
+            }
+            m2.lock(|| { });
+            c.send(sibling_convos); // let parent wait on all children
+            fail!();
+        });
+        assert!(result.is_err());
+        // child task must have finished by the time try returns
+        let mut r = p.recv();
+        for p in r.mut_iter() { p.recv(); } // wait on all its siblings
+        m.lock_cond(|cond| {
+            let woken = cond.broadcast();
+            assert_eq!(woken, 0);
+        })
+    }
+    #[test]
+    fn test_mutex_cond_signal_on_0() {
+        // Tests that signal_on(0) is equivalent to signal().
+        let m = Mutex::new();
+        m.lock_cond(|cond| {
+            let m2 = m.clone();
+            task::spawn(proc() {
+                m2.lock_cond(|cond| {
+                    cond.signal_on(0);
+                })
+            });
+            cond.wait();
+        })
+    }
+    #[test]
+    #[ignore(reason = "linked failure?")]
+    fn test_mutex_different_conds() {
+        let result = task::try(proc() {
+            let m = Mutex::new_with_condvars(2);
+            let m2 = m.clone();
+            let (p, c) = Chan::new();
+            task::spawn(proc() {
+                m2.lock_cond(|cond| {
+                    c.send(());
+                    cond.wait_on(1);
+                })
+            });
+            let _ = p.recv();
+            m.lock_cond(|cond| {
+                if !cond.signal_on(0) {
+                    fail!(); // success; punt sibling awake.
+                }
+            })
+        });
+        assert!(result.is_err());
+    }
+    #[test]
+    fn test_mutex_no_condvars() {
+        let result = task::try(proc() {
+            let m = Mutex::new_with_condvars(0);
+            m.lock_cond(|cond| { cond.wait(); })
+        });
+        assert!(result.is_err());
+        let result = task::try(proc() {
+            let m = Mutex::new_with_condvars(0);
+            m.lock_cond(|cond| { cond.signal(); })
+        });
+        assert!(result.is_err());
+        let result = task::try(proc() {
+            let m = Mutex::new_with_condvars(0);
+            m.lock_cond(|cond| { cond.broadcast(); })
+        });
+        assert!(result.is_err());
+    }
+    /************************************************************************
+     * Reader/writer lock tests
+     ************************************************************************/
+    #[cfg(test)]
+    pub enum RWLockMode { Read, Write, Downgrade, DowngradeRead }
+    #[cfg(test)]
+    fn lock_rwlock_in_mode(x: &RWLock, mode: RWLockMode, blk: ||) {
+        match mode {
+            Read => x.read(blk),
+            Write => x.write(blk),
+            Downgrade =>
+                x.write_downgrade(|mode| {
+                    mode.write(|| { blk() });
+                }),
+            DowngradeRead =>
+                x.write_downgrade(|mode| {
+                    let mode = x.downgrade(mode);
+                    mode.read(|| { blk() });
+                }),
+        }
+    }
+    #[cfg(test)]
+    fn test_rwlock_exclusion(x: &RWLock,
+                                 mode1: RWLockMode,
+                                 mode2: RWLockMode) {
+        // Test mutual exclusion between readers and writers. Just like the
+        // mutex mutual exclusion test, a ways above.
+        let (p, c) = Chan::new();
+        let x2 = x.clone();
+        let mut sharedstate = ~0;
+        {
+            let ptr: *int = &*sharedstate;
+            task::spawn(proc() {
+                let sharedstate: &mut int =
+                    unsafe { cast::transmute(ptr) };
+                access_shared(sharedstate, &x2, mode1, 10);
+                c.send(());
+            });
+        }
+        {
+            access_shared(sharedstate, x, mode2, 10);
+            let _ = p.recv();
+
+            assert_eq!(*sharedstate, 20);
+        }
+
+        fn access_shared(sharedstate: &mut int, x: &RWLock, mode: RWLockMode,
+                         n: uint) {
+            for _ in range(0, n) {
+                lock_rwlock_in_mode(x, mode, || {
+                    let oldval = *sharedstate;
+                    task::deschedule();
+                    *sharedstate = oldval + 1;
+                })
+            }
+        }
+    }
+    #[test]
+    fn test_rwlock_readers_wont_modify_the_data() {
+        test_rwlock_exclusion(&RWLock::new(), Read, Write);
+        test_rwlock_exclusion(&RWLock::new(), Write, Read);
+        test_rwlock_exclusion(&RWLock::new(), Read, Downgrade);
+        test_rwlock_exclusion(&RWLock::new(), Downgrade, Read);
+    }
+    #[test]
+    fn test_rwlock_writers_and_writers() {
+        test_rwlock_exclusion(&RWLock::new(), Write, Write);
+        test_rwlock_exclusion(&RWLock::new(), Write, Downgrade);
+        test_rwlock_exclusion(&RWLock::new(), Downgrade, Write);
+        test_rwlock_exclusion(&RWLock::new(), Downgrade, Downgrade);
+    }
+    #[cfg(test)]
+    fn test_rwlock_handshake(x: &RWLock,
+                                 mode1: RWLockMode,
+                                 mode2: RWLockMode,
+                                 make_mode2_go_first: bool) {
+        // Much like sem_multi_resource.
+        let x2 = x.clone();
+        let (p1, c1) = Chan::new();
+        let (p2, c2) = Chan::new();
+        task::spawn(proc() {
+            if !make_mode2_go_first {
+                let _ = p2.recv(); // parent sends to us once it locks, or ...
+            }
+            lock_rwlock_in_mode(&x2, mode2, || {
+                if make_mode2_go_first {
+                    c1.send(()); // ... we send to it once we lock
+                }
+                let _ = p2.recv();
+                c1.send(());
+            })
+        });
+        if make_mode2_go_first {
+            let _ = p1.recv(); // child sends to us once it locks, or ...
+        }
+        lock_rwlock_in_mode(x, mode1, || {
+            if !make_mode2_go_first {
+                c2.send(()); // ... we send to it once we lock
+            }
+            c2.send(());
+            let _ = p1.recv();
+        })
+    }
+    #[test]
+    fn test_rwlock_readers_and_readers() {
+        test_rwlock_handshake(&RWLock::new(), Read, Read, false);
+        // The downgrader needs to get in before the reader gets in, otherwise
+        // they cannot end up reading at the same time.
+        test_rwlock_handshake(&RWLock::new(), DowngradeRead, Read, false);
+        test_rwlock_handshake(&RWLock::new(), Read, DowngradeRead, true);
+        // Two downgrade_reads can never both end up reading at the same time.
+    }
+    #[test]
+    fn test_rwlock_downgrade_unlock() {
+        // Tests that downgrade can unlock the lock in both modes
+        let x = RWLock::new();
+        lock_rwlock_in_mode(&x, Downgrade, || { });
+        test_rwlock_handshake(&x, Read, Read, false);
+        let y = RWLock::new();
+        lock_rwlock_in_mode(&y, DowngradeRead, || { });
+        test_rwlock_exclusion(&y, Write, Write);
+    }
+    #[test]
+    fn test_rwlock_read_recursive() {
+        let x = RWLock::new();
+        x.read(|| { x.read(|| { }) })
+    }
+    #[test]
+    fn test_rwlock_cond_wait() {
+        // As test_mutex_cond_wait above.
+        let x = RWLock::new();
+
+        // Child wakes up parent
+        x.write_cond(|cond| {
+            let x2 = x.clone();
+            task::spawn(proc() {
+                x2.write_cond(|cond| {
+                    let woken = cond.signal();
+                    assert!(woken);
+                })
+            });
+            cond.wait();
+        });
+        // Parent wakes up child
+        let (port, chan) = Chan::new();
+        let x3 = x.clone();
+        task::spawn(proc() {
+            x3.write_cond(|cond| {
+                chan.send(());
+                cond.wait();
+                chan.send(());
+            })
+        });
+        let _ = port.recv(); // Wait until child gets in the rwlock
+        x.read(|| { }); // Must be able to get in as a reader in the meantime
+        x.write_cond(|cond| { // Or as another writer
+            let woken = cond.signal();
+            assert!(woken);
+        });
+        let _ = port.recv(); // Wait until child wakes up
+        x.read(|| { }); // Just for good measure
+    }
+    #[cfg(test)]
+    fn test_rwlock_cond_broadcast_helper(num_waiters: uint,
+                                             dg1: bool,
+                                             dg2: bool) {
+        // Much like the mutex broadcast test. Downgrade-enabled.
+        fn lock_cond(x: &RWLock, downgrade: bool, blk: |c: &Condvar|) {
+            if downgrade {
+                x.write_downgrade(|mode| {
+                    mode.write_cond(|c| { blk(c) });
+                });
+            } else {
+                x.write_cond(|c| { blk(c) });
+            }
+        }
+        let x = RWLock::new();
+        let mut ports = ~[];
+
+        for _ in range(0, num_waiters) {
+            let xi = x.clone();
+            let (port, chan) = Chan::new();
+            ports.push(port);
+            task::spawn(proc() {
+                lock_cond(&xi, dg1, |cond| {
+                    chan.send(());
+                    cond.wait();
+                    chan.send(());
+                })
+            });
+        }
+
+        // wait until all children get in the mutex
+        for port in ports.mut_iter() { let _ = port.recv(); }
+        lock_cond(&x, dg2, |cond| {
+            let num_woken = cond.broadcast();
+            assert_eq!(num_woken, num_waiters);
+        });
+        // wait until all children wake up
+        for port in ports.mut_iter() { let _ = port.recv(); }
+    }
+    #[test]
+    fn test_rwlock_cond_broadcast() {
+        test_rwlock_cond_broadcast_helper(0, true, true);
+        test_rwlock_cond_broadcast_helper(0, true, false);
+        test_rwlock_cond_broadcast_helper(0, false, true);
+        test_rwlock_cond_broadcast_helper(0, false, false);
+        test_rwlock_cond_broadcast_helper(12, true, true);
+        test_rwlock_cond_broadcast_helper(12, true, false);
+        test_rwlock_cond_broadcast_helper(12, false, true);
+        test_rwlock_cond_broadcast_helper(12, false, false);
+    }
+    #[cfg(test)]
+    fn rwlock_kill_helper(mode1: RWLockMode, mode2: RWLockMode) {
+        // Mutex must get automatically unlocked if failed/killed within.
+        let x = RWLock::new();
+        let x2 = x.clone();
+
+        let result: result::Result<(), ~Any> = task::try(proc() {
+            lock_rwlock_in_mode(&x2, mode1, || {
+                fail!();
+            })
+        });
+        assert!(result.is_err());
+        // child task must have finished by the time try returns
+        lock_rwlock_in_mode(&x, mode2, || { })
+    }
+    #[test]
+    fn test_rwlock_reader_killed_writer() {
+        rwlock_kill_helper(Read, Write);
+    }
+    #[test]
+    fn test_rwlock_writer_killed_reader() {
+        rwlock_kill_helper(Write, Read);
+    }
+    #[test]
+    fn test_rwlock_reader_killed_reader() {
+        rwlock_kill_helper(Read, Read);
+    }
+    #[test]
+    fn test_rwlock_writer_killed_writer() {
+        rwlock_kill_helper(Write, Write);
+    }
+    #[test]
+    fn test_rwlock_kill_downgrader() {
+        rwlock_kill_helper(Downgrade, Read);
+        rwlock_kill_helper(Read, Downgrade);
+        rwlock_kill_helper(Downgrade, Write);
+        rwlock_kill_helper(Write, Downgrade);
+        rwlock_kill_helper(DowngradeRead, Read);
+        rwlock_kill_helper(Read, DowngradeRead);
+        rwlock_kill_helper(DowngradeRead, Write);
+        rwlock_kill_helper(Write, DowngradeRead);
+        rwlock_kill_helper(DowngradeRead, Downgrade);
+        rwlock_kill_helper(DowngradeRead, Downgrade);
+        rwlock_kill_helper(Downgrade, DowngradeRead);
+        rwlock_kill_helper(Downgrade, DowngradeRead);
+    }
+    #[test] #[should_fail]
+    fn test_rwlock_downgrade_cant_swap() {
+        // Tests that you can't downgrade with a different rwlock's token.
+        let x = RWLock::new();
+        let y = RWLock::new();
+        x.write_downgrade(|xwrite| {
+            let mut xopt = Some(xwrite);
+            y.write_downgrade(|_ywrite| {
+                y.downgrade(xopt.take_unwrap());
+                error!("oops, y.downgrade(x) should have failed!");
+            })
+        })
+    }
+
+    /************************************************************************
+     * Barrier tests
+     ************************************************************************/
+    #[test]
+    fn test_barrier() {
+        let barrier = Barrier::new(10);
+        let (port, chan) = SharedChan::new();
+
+        for _ in range(0, 9) {
+            let c = barrier.clone();
+            let chan = chan.clone();
+            spawn(proc() {
+                c.wait();
+                chan.send(true);
+            });
+        }
+
+        // At this point, all spawned tasks should be blocked,
+        // so we shouldn't get anything from the port
+        assert!(match port.try_recv() {
+            Empty => true,
+            _ => false,
+        });
+
+        barrier.wait();
+        // Now, the barrier is cleared and we should get data.
+        for _ in range(0, 9) {
+            port.recv();
+        }
+    }
+}
diff --git a/src/libsync/sync/mpsc_intrusive.rs b/src/libsync/sync/mpsc_intrusive.rs
new file mode 100644 (file)
index 0000000..0f13a49
--- /dev/null
@@ -0,0 +1,139 @@
+/* Copyright (c) 2010-2011 Dmitry Vyukov. All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY DMITRY VYUKOV "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL DMITRY VYUKOV OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are
+ * those of the authors and should not be interpreted as representing official
+ * policies, either expressed or implied, of Dmitry Vyukov.
+ */
+
+//! A mostly lock-free multi-producer, single consumer queue.
+//!
+//! This module implements an intrusive MPSC queue. This queue is incredibly
+//! unsafe (due to use of unsafe pointers for nodes), and hence is not public.
+
+// http://www.1024cores.net/home/lock-free-algorithms
+//                         /queues/intrusive-mpsc-node-based-queue
+
+use std::cast;
+use std::sync::atomics;
+
+// NB: all links are done as AtomicUint instead of AtomicPtr to allow for static
+// initialization.
+
+pub struct Node<T> {
+    next: atomics::AtomicUint,
+    data: T,
+}
+
+pub struct DummyNode {
+    next: atomics::AtomicUint,
+}
+
+pub struct Queue<T> {
+    head: atomics::AtomicUint,
+    tail: *mut Node<T>,
+    stub: DummyNode,
+}
+
+impl<T: Send> Queue<T> {
+    pub fn new() -> Queue<T> {
+        Queue {
+            head: atomics::AtomicUint::new(0),
+            tail: 0 as *mut Node<T>,
+            stub: DummyNode {
+                next: atomics::AtomicUint::new(0),
+            },
+        }
+    }
+
+    pub unsafe fn push(&mut self, node: *mut Node<T>) {
+        (*node).next.store(0, atomics::Release);
+        let prev = self.head.swap(node as uint, atomics::AcqRel);
+
+        // Note that this code is slightly modified to allow static
+        // initialization of these queues with rust's flavor of static
+        // initialization.
+        if prev == 0 {
+            self.stub.next.store(node as uint, atomics::Release);
+        } else {
+            let prev = prev as *mut Node<T>;
+            (*prev).next.store(node as uint, atomics::Release);
+        }
+    }
+
+    /// You'll note that the other MPSC queue in std::sync is non-intrusive and
+    /// returns a `PopResult` here to indicate when the queue is inconsistent.
+    /// An "inconsistent state" in the other queue means that a pusher has
+    /// pushed, but it hasn't finished linking the rest of the chain.
+    ///
+    /// This queue also suffers from this problem, but I currently haven't been
+    /// able to detangle when this actually happens. This code is translated
+    /// verbatim from the website above, and is more complicated than the
+    /// non-intrusive version.
+    ///
+    /// Right now consumers of this queue must be ready for this fact. Just
+    /// because `pop` returns `None` does not mean that there is not data
+    /// on the queue.
+    pub unsafe fn pop(&mut self) -> Option<*mut Node<T>> {
+        let tail = self.tail;
+        let mut tail = if !tail.is_null() {tail} else {
+            cast::transmute(&self.stub)
+        };
+        let mut next = (*tail).next(atomics::Relaxed);
+        if tail as uint == &self.stub as *DummyNode as uint {
+            if next.is_null() {
+                return None;
+            }
+            self.tail = next;
+            tail = next;
+            next = (*next).next(atomics::Relaxed);
+        }
+        if !next.is_null() {
+            self.tail = next;
+            return Some(tail);
+        }
+        let head = self.head.load(atomics::Acquire) as *mut Node<T>;
+        if tail != head {
+            return None;
+        }
+        let stub = cast::transmute(&self.stub);
+        self.push(stub);
+        next = (*tail).next(atomics::Relaxed);
+        if !next.is_null() {
+            self.tail = next;
+            return Some(tail);
+        }
+        return None
+    }
+}
+
+impl<T: Send> Node<T> {
+    pub fn new(t: T) -> Node<T> {
+        Node {
+            data: t,
+            next: atomics::AtomicUint::new(0),
+        }
+    }
+    pub unsafe fn next(&mut self, ord: atomics::Ordering) -> *mut Node<T> {
+        cast::transmute::<uint, *mut Node<T>>(self.next.load(ord))
+    }
+}
diff --git a/src/libsync/sync/mutex.rs b/src/libsync/sync/mutex.rs
new file mode 100644 (file)
index 0000000..f1a81d6
--- /dev/null
@@ -0,0 +1,557 @@
+// Copyright 2014 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.
+
+//! A proper mutex implementation regardless of the "flavor of task" which is
+//! acquiring the lock.
+
+// # Implementation of Rust mutexes
+//
+// Most answers to the question of "how do I use a mutex" are "use pthreads",
+// but for Rust this isn't quite sufficient. Green threads cannot acquire an OS
+// mutex because they can context switch among many OS threads, leading to
+// deadlocks with other green threads.
+//
+// Another problem for green threads grabbing an OS mutex is that POSIX dictates
+// that unlocking a mutex on a different thread from where it was locked is
+// undefined behavior. Remember that green threads can migrate among OS threads,
+// so this would mean that we would have to pin green threads to OS threads,
+// which is less than ideal.
+//
+// ## Using deschedule/reawaken
+//
+// We already have primitives for descheduling/reawakening tasks, so they're the
+// first obvious choice when implementing a mutex. The idea would be to have a
+// concurrent queue that everyone is pushed on to, and then the owner of the
+// mutex is the one popping from the queue.
+//
+// Unfortunately, this is not very performant for native tasks. The suspected
+// reason for this is that each native thread is suspended on its own condition
+// variable, unique from all the other threads. In this situation, the kernel
+// has no idea what the scheduling semantics are of the user program, so all of
+// the threads are distributed among all cores on the system. This ends up
+// having very expensive wakeups of remote cores high up in the profile when
+// handing off the mutex among native tasks. On the other hand, when using an OS
+// mutex, the kernel knows that all native threads are contended on the same
+// mutex, so they're in theory all migrated to a single core (fast context
+// switching).
+//
+// ## Mixing implementations
+//
+// From that above information, we have two constraints. The first is that
+// green threads can't touch os mutexes, and the second is that native tasks
+// pretty much *must* touch an os mutex.
+//
+// As a compromise, the queueing implementation is used for green threads and
+// the os mutex is used for native threads (why not have both?). This ends up
+// leading to fairly decent performance for both native threads and green
+// threads on various workloads (uncontended and contended).
+//
+// The crux of this implementation is an atomic work which is CAS'd on many many
+// times in order to manage a few flags about who's blocking where and whether
+// it's locked or not.
+
+use std::rt::local::Local;
+use std::rt::task::{BlockedTask, Task};
+use std::rt::thread::Thread;
+use std::sync::atomics;
+use std::unstable::mutex;
+
+use q = sync::mpsc_intrusive;
+
+pub static LOCKED: uint = 1 << 0;
+pub static GREEN_BLOCKED: uint = 1 << 1;
+pub static NATIVE_BLOCKED: uint = 1 << 2;
+
+/// A mutual exclusion primitive useful for protecting shared data
+///
+/// This mutex is an implementation of a lock for all flavors of tasks which may
+/// be grabbing. A common problem with green threads is that they cannot grab
+/// locks (if they reschedule during the lock a contender could deadlock the
+/// system), but this mutex does *not* suffer this problem.
+///
+/// This mutex will properly block tasks waiting for the lock to become
+/// available. The mutex can also be statically initialized or created via a
+/// `new` constructor.
+///
+/// # Example
+///
+/// ```rust
+/// use sync::mutex::Mutex;
+///
+/// let mut m = Mutex::new();
+/// let guard = m.lock();
+/// // do some work
+/// drop(guard); // unlock the lock
+/// ```
+pub struct Mutex {
+    priv lock: StaticMutex,
+}
+
+#[deriving(Eq)]
+enum Flavor {
+    Unlocked,
+    TryLockAcquisition,
+    GreenAcquisition,
+    NativeAcquisition,
+}
+
+/// The static mutex type is provided to allow for static allocation of mutexes.
+///
+/// Note that this is a separate type because using a Mutex correctly means that
+/// it needs to have a destructor run. In Rust, statics are not allowed to have
+/// destructors. As a result, a `StaticMutex` has one extra method when compared
+/// to a `Mutex`, a `destroy` method. This method is unsafe to call, and
+/// documentation can be found directly on the method.
+///
+/// # Example
+///
+/// ```rust
+/// use sync::mutex::{StaticMutex, MUTEX_INIT};
+///
+/// static mut LOCK: StaticMutex = MUTEX_INIT;
+///
+/// unsafe {
+///     let _g = LOCK.lock();
+///     // do some productive work
+/// }
+/// // lock is unlocked here.
+/// ```
+pub struct StaticMutex {
+    /// Current set of flags on this mutex
+    priv state: atomics::AtomicUint,
+    /// Type of locking operation currently on this mutex
+    priv flavor: Flavor,
+    /// uint-cast of the green thread waiting for this mutex
+    priv green_blocker: uint,
+    /// uint-cast of the native thread waiting for this mutex
+    priv native_blocker: uint,
+    /// an OS mutex used by native threads
+    priv lock: mutex::Mutex,
+
+    /// A concurrent mpsc queue used by green threads, along with a count used
+    /// to figure out when to dequeue and enqueue.
+    priv q: q::Queue<uint>,
+    priv green_cnt: atomics::AtomicUint,
+}
+
+/// An RAII implementation of a "scoped lock" of a mutex. When this structure is
+/// dropped (falls out of scope), the lock will be unlocked.
+pub struct Guard<'a> {
+    priv lock: &'a mut StaticMutex,
+}
+
+/// Static initialization of a mutex. This constant can be used to initialize
+/// other mutex constants.
+pub static MUTEX_INIT: StaticMutex = StaticMutex {
+    lock: mutex::MUTEX_INIT,
+    state: atomics::INIT_ATOMIC_UINT,
+    flavor: Unlocked,
+    green_blocker: 0,
+    native_blocker: 0,
+    green_cnt: atomics::INIT_ATOMIC_UINT,
+    q: q::Queue {
+        head: atomics::INIT_ATOMIC_UINT,
+        tail: 0 as *mut q::Node<uint>,
+        stub: q::DummyNode {
+            next: atomics::INIT_ATOMIC_UINT,
+        }
+    }
+};
+
+impl StaticMutex {
+    /// Attempts to grab this lock, see `Mutex::try_lock`
+    pub fn try_lock<'a>(&'a mut self) -> Option<Guard<'a>> {
+        // Attempt to steal the mutex from an unlocked state.
+        //
+        // FIXME: this can mess up the fairness of the mutex, seems bad
+        match self.state.compare_and_swap(0, LOCKED, atomics::SeqCst) {
+            0 => {
+                assert!(self.flavor == Unlocked);
+                self.flavor = TryLockAcquisition;
+                Some(Guard::new(self))
+            }
+            _ => None
+        }
+    }
+
+    /// Acquires this lock, see `Mutex::lock`
+    pub fn lock<'a>(&'a mut self) -> Guard<'a> {
+        // First, attempt to steal the mutex from an unlocked state. The "fast
+        // path" needs to have as few atomic instructions as possible, and this
+        // one cmpxchg is already pretty expensive.
+        //
+        // FIXME: this can mess up the fairness of the mutex, seems bad
+        match self.state.compare_and_swap(0, LOCKED, atomics::SeqCst) {
+            0 => {
+                assert!(self.flavor == Unlocked);
+                self.flavor = TryLockAcquisition;
+                return Guard::new(self)
+            }
+            _ => {}
+        }
+
+        // After we've failed the fast path, then we delegate to the differnet
+        // locking protocols for green/native tasks. This will select two tasks
+        // to continue further (one native, one green).
+        let t: ~Task = Local::take();
+        let can_block = t.can_block();
+        let native_bit;
+        if can_block {
+            self.native_lock(t);
+            native_bit = NATIVE_BLOCKED;
+        } else {
+            self.green_lock(t);
+            native_bit = GREEN_BLOCKED;
+        }
+
+        // After we've arbitrated among task types, attempt to re-acquire the
+        // lock (avoids a deschedule). This is very important to do in order to
+        // allow threads coming out of the native_lock function to try their
+        // best to not hit a cvar in deschedule.
+        let mut old = match self.state.compare_and_swap(0, LOCKED,
+                                                        atomics::SeqCst) {
+            0 => {
+                self.flavor = if can_block {
+                    NativeAcquisition
+                } else {
+                    GreenAcquisition
+                };
+                return Guard::new(self)
+            }
+            old => old,
+        };
+
+        // Alright, everything else failed. We need to deschedule ourselves and
+        // flag ourselves as waiting. Note that this case should only happen
+        // regularly in native/green contention. Due to try_lock and the header
+        // of lock stealing the lock, it's also possible for native/native
+        // contention to hit this location, but as less common.
+        let t: ~Task = Local::take();
+        t.deschedule(1, |task| {
+            let task = unsafe { task.cast_to_uint() };
+            if can_block {
+                assert_eq!(self.native_blocker, 0);
+                self.native_blocker = task;
+            } else {
+                assert_eq!(self.green_blocker, 0);
+                self.green_blocker = task;
+            }
+
+            loop {
+                assert_eq!(old & native_bit, 0);
+                // If the old state was locked, then we need to flag ourselves
+                // as blocking in the state. If the old state was unlocked, then
+                // we attempt to acquire the mutex. Everything here is a CAS
+                // loop that'll eventually make progress.
+                if old & LOCKED != 0 {
+                    old = match self.state.compare_and_swap(old,
+                                                            old | native_bit,
+                                                            atomics::SeqCst) {
+                        n if n == old => return Ok(()),
+                        n => n
+                    };
+                } else {
+                    assert_eq!(old, 0);
+                    old = match self.state.compare_and_swap(old,
+                                                            old | LOCKED,
+                                                            atomics::SeqCst) {
+                        n if n == old => {
+                            assert_eq!(self.flavor, Unlocked);
+                            if can_block {
+                                self.native_blocker = 0;
+                                self.flavor = NativeAcquisition;
+                            } else {
+                                self.green_blocker = 0;
+                                self.flavor = GreenAcquisition;
+                            }
+                            return Err(unsafe {
+                                BlockedTask::cast_from_uint(task)
+                            })
+                        }
+                        n => n,
+                    };
+                }
+            }
+        });
+
+        Guard::new(self)
+    }
+
+    // Tasks which can block are super easy. These tasks just call the blocking
+    // `lock()` function on an OS mutex
+    fn native_lock(&mut self, t: ~Task) {
+        Local::put(t);
+        unsafe { self.lock.lock(); }
+    }
+
+    fn native_unlock(&mut self) {
+        unsafe { self.lock.unlock(); }
+    }
+
+    fn green_lock(&mut self, t: ~Task) {
+        // Green threads flag their presence with an atomic counter, and if they
+        // fail to be the first to the mutex, they enqueue themselves on a
+        // concurrent internal queue with a stack-allocated node.
+        //
+        // FIXME: There isn't a cancellation currently of an enqueue, forcing
+        //        the unlocker to spin for a bit.
+        if self.green_cnt.fetch_add(1, atomics::SeqCst) == 0 {
+            Local::put(t);
+            return
+        }
+
+        let mut node = q::Node::new(0);
+        t.deschedule(1, |task| {
+            unsafe {
+                node.data = task.cast_to_uint();
+                self.q.push(&mut node);
+            }
+            Ok(())
+        });
+    }
+
+    fn green_unlock(&mut self) {
+        // If we're the only green thread, then no need to check the queue,
+        // otherwise the fixme above forces us to spin for a bit.
+        if self.green_cnt.fetch_sub(1, atomics::SeqCst) == 1 { return }
+        let node;
+        loop {
+            match unsafe { self.q.pop() } {
+                Some(t) => { node = t; break; }
+                None => Thread::yield_now(),
+            }
+        }
+        let task = unsafe { BlockedTask::cast_from_uint((*node).data) };
+        task.wake().map(|t| t.reawaken());
+    }
+
+    fn unlock(&mut self) {
+        // Unlocking this mutex is a little tricky. We favor any task that is
+        // manually blocked (not in each of the separate locks) in order to help
+        // provide a little fairness (green threads will wake up the pending
+        // native thread and native threads will wake up the pending green
+        // thread).
+        //
+        // There's also the question of when we unlock the actual green/native
+        // locking halves as well. If we're waking up someone, then we can wait
+        // to unlock until we've acquired the task to wake up (we're guaranteed
+        // the mutex memory is still valid when there's contenders), but as soon
+        // as we don't find any contenders we must unlock the mutex, and *then*
+        // flag the mutex as unlocked.
+        //
+        // This flagging can fail, leading to another round of figuring out if a
+        // task needs to be woken, and in this case it's ok that the "mutex
+        // halves" are unlocked, we're just mainly dealing with the atomic state
+        // of the outer mutex.
+        let flavor = self.flavor;
+        self.flavor = Unlocked;
+
+        let mut state = self.state.load(atomics::SeqCst);
+        let mut unlocked = false;
+        let task;
+        loop {
+            assert!(state & LOCKED != 0);
+            if state & GREEN_BLOCKED != 0 {
+                self.unset(state, GREEN_BLOCKED);
+                task = unsafe {
+                    BlockedTask::cast_from_uint(self.green_blocker)
+                };
+                self.green_blocker = 0;
+                self.flavor = GreenAcquisition;
+                break;
+            } else if state & NATIVE_BLOCKED != 0 {
+                self.unset(state, NATIVE_BLOCKED);
+                task = unsafe {
+                    BlockedTask::cast_from_uint(self.native_blocker)
+                };
+                self.native_blocker = 0;
+                self.flavor = NativeAcquisition;
+                break;
+            } else {
+                assert_eq!(state, LOCKED);
+                if !unlocked {
+                    match flavor {
+                        GreenAcquisition => { self.green_unlock(); }
+                        NativeAcquisition => { self.native_unlock(); }
+                        TryLockAcquisition => {}
+                        Unlocked => unreachable!()
+                    }
+                    unlocked = true;
+                }
+                match self.state.compare_and_swap(LOCKED, 0, atomics::SeqCst) {
+                    LOCKED => return,
+                    n => { state = n; }
+                }
+            }
+        }
+        if !unlocked {
+            match flavor {
+                GreenAcquisition => { self.green_unlock(); }
+                NativeAcquisition => { self.native_unlock(); }
+                TryLockAcquisition => {}
+                Unlocked => unreachable!()
+            }
+        }
+
+        task.wake().map(|t| t.reawaken());
+    }
+
+    /// Loops around a CAS to unset the `bit` in `state`
+    fn unset(&mut self, mut state: uint, bit: uint) {
+        loop {
+            assert!(state & bit != 0);
+            let new = state ^ bit;
+            match self.state.compare_and_swap(state, new, atomics::SeqCst) {
+                n if n == state => break,
+                n => { state = n; }
+            }
+        }
+    }
+
+    /// Deallocates resources associated with this static mutex.
+    ///
+    /// This method is unsafe because it provides no guarantees that there are
+    /// no active users of this mutex, and safety is not guaranteed if there are
+    /// active users of this mutex.
+    ///
+    /// This method is required to ensure that there are no memory leaks on
+    /// *all* platforms. It may be the case that some platforms do not leak
+    /// memory if this method is not called, but this is not guaranteed to be
+    /// true on all platforms.
+    pub unsafe fn destroy(&mut self) {
+        self.lock.destroy()
+    }
+}
+
+impl Mutex {
+    /// Creates a new mutex in an unlocked state ready for use.
+    pub fn new() -> Mutex {
+        Mutex {
+            lock: StaticMutex {
+                state: atomics::AtomicUint::new(0),
+                flavor: Unlocked,
+                green_blocker: 0,
+                native_blocker: 0,
+                green_cnt: atomics::AtomicUint::new(0),
+                q: q::Queue::new(),
+                lock: unsafe { mutex::Mutex::new() },
+            }
+        }
+    }
+
+    /// Attempts to acquire this lock.
+    ///
+    /// If the lock could not be acquired at this time, then `None` is returned.
+    /// Otherwise, an RAII guard is returned. The lock will be unlocked when the
+    /// guard is dropped.
+    ///
+    /// This function does not block.
+    pub fn try_lock<'a>(&'a mut self) -> Option<Guard<'a>> {
+        self.lock.try_lock()
+    }
+
+    /// Acquires a mutex, blocking the current task until it is able to do so.
+    ///
+    /// This function will block the local task until it is availble to acquire
+    /// the mutex. Upon returning, the task is the only task with the mutex
+    /// held. An RAII guard is returned to allow scoped unlock of the lock. When
+    /// the guard goes out of scope, the mutex will be unlocked.
+    pub fn lock<'a>(&'a mut self) -> Guard<'a> { self.lock.lock() }
+}
+
+impl<'a> Guard<'a> {
+    fn new<'b>(lock: &'b mut StaticMutex) -> Guard<'b> {
+        if cfg!(debug) {
+            assert!(lock.flavor != Unlocked);
+            assert!(lock.state.load(atomics::SeqCst) & LOCKED != 0);
+        }
+        Guard { lock: lock }
+    }
+}
+
+#[unsafe_destructor]
+impl<'a> Drop for Guard<'a> {
+    #[inline]
+    fn drop(&mut self) {
+        self.lock.unlock();
+    }
+}
+
+impl Drop for Mutex {
+    fn drop(&mut self) {
+        // This is actually safe b/c we know that there is no further usage of
+        // this mutex (it's up to the user to arrange for a mutex to get
+        // dropped, that's not our job)
+        unsafe { self.lock.destroy() }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    extern mod native;
+    use super::{Mutex, StaticMutex, MUTEX_INIT};
+
+    #[test]
+    fn smoke() {
+        let mut m = Mutex::new();
+        drop(m.lock());
+        drop(m.lock());
+    }
+
+    #[test]
+    fn smoke_static() {
+        static mut m: StaticMutex = MUTEX_INIT;
+        unsafe {
+            drop(m.lock());
+            drop(m.lock());
+            m.destroy();
+        }
+    }
+
+    #[test]
+    fn lots_and_lots() {
+        static mut m: StaticMutex = MUTEX_INIT;
+        static mut CNT: uint = 0;
+        static M: uint = 1000;
+        static N: uint = 3;
+
+        fn inc() {
+            for _ in range(0, M) {
+                unsafe {
+                    let _g = m.lock();
+                    CNT += 1;
+                }
+            }
+        }
+
+        let (p, c) = SharedChan::new();
+        for _ in range(0, N) {
+            let c2 = c.clone();
+            native::task::spawn(proc() { inc(); c2.send(()); });
+            let c2 = c.clone();
+            spawn(proc() { inc(); c2.send(()); });
+        }
+
+        drop(c);
+        for _ in range(0, 2 * N) {
+            p.recv();
+        }
+        assert_eq!(unsafe {CNT}, M * N * 2);
+        unsafe {
+            m.destroy();
+        }
+    }
+
+    #[test]
+    fn trylock() {
+        let mut m = Mutex::new();
+        assert!(m.try_lock().is_some());
+    }
+}
diff --git a/src/libsync/sync/one.rs b/src/libsync/sync/one.rs
new file mode 100644 (file)
index 0000000..93d818b
--- /dev/null
@@ -0,0 +1,168 @@
+// Copyright 2014 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.
+
+//! A "once initialization" primitive
+//!
+//! This primitive is meant to be used to run one-time initialization. An
+//! example use case would be for initializing an FFI library.
+
+use std::int;
+use std::sync::atomics;
+use sync::mutex::{StaticMutex, MUTEX_INIT};
+
+/// A type which can be used to run a one-time global initialization. This type
+/// is *unsafe* to use because it is built on top of the `Mutex` in this module.
+/// It does not know whether the currently running task is in a green or native
+/// context, and a blocking mutex should *not* be used under normal
+/// circumstances on a green task.
+///
+/// Despite its unsafety, it is often useful to have a one-time initialization
+/// routine run for FFI bindings or related external functionality. This type
+/// can only be statically constructed with the `ONCE_INIT` value.
+///
+/// # Example
+///
+/// ```rust
+/// use sync::one::{Once, ONCE_INIT};
+///
+/// static mut START: Once = ONCE_INIT;
+/// unsafe {
+///     START.doit(|| {
+///         // run initialization here
+///     });
+/// }
+/// ```
+pub struct Once {
+    priv mutex: StaticMutex,
+    priv cnt: atomics::AtomicInt,
+    priv lock_cnt: atomics::AtomicInt,
+}
+
+/// Initialization value for static `Once` values.
+pub static ONCE_INIT: Once = Once {
+    mutex: MUTEX_INIT,
+    cnt: atomics::INIT_ATOMIC_INT,
+    lock_cnt: atomics::INIT_ATOMIC_INT,
+};
+
+impl Once {
+    /// Perform an initialization routine once and only once. The given closure
+    /// will be executed if this is the first time `doit` has been called, and
+    /// otherwise the routine will *not* be invoked.
+    ///
+    /// This method will block the calling *os thread* if another initialization
+    /// routine is currently running.
+    ///
+    /// When this function returns, it is guaranteed that some initialization
+    /// has run and completed (it may not be the closure specified).
+    pub fn doit(&mut self, f: ||) {
+        // Implementation-wise, this would seem like a fairly trivial primitive.
+        // The stickler part is where our mutexes currently require an
+        // allocation, and usage of a `Once` should't leak this allocation.
+        //
+        // This means that there must be a deterministic destroyer of the mutex
+        // contained within (because it's not needed after the initialization
+        // has run).
+        //
+        // The general scheme here is to gate all future threads once
+        // initialization has completed with a "very negative" count, and to
+        // allow through threads to lock the mutex if they see a non negative
+        // count. For all threads grabbing the mutex, exactly one of them should
+        // be responsible for unlocking the mutex, and this should only be done
+        // once everyone else is done with the mutex.
+        //
+        // This atomicity is achieved by swapping a very negative value into the
+        // shared count when the initialization routine has completed. This will
+        // read the number of threads which will at some point attempt to
+        // acquire the mutex. This count is then squirreled away in a separate
+        // variable, and the last person on the way out of the mutex is then
+        // responsible for destroying the mutex.
+        //
+        // It is crucial that the negative value is swapped in *after* the
+        // initialization routine has completed because otherwise new threads
+        // calling `doit` will return immediately before the initialization has
+        // completed.
+
+        let prev = self.cnt.fetch_add(1, atomics::SeqCst);
+        if prev < 0 {
+            // Make sure we never overflow, we'll never have int::MIN
+            // simultaneous calls to `doit` to make this value go back to 0
+            self.cnt.store(int::MIN, atomics::SeqCst);
+            return
+        }
+
+        // If the count is negative, then someone else finished the job,
+        // otherwise we run the job and record how many people will try to grab
+        // this lock
+        {
+            let _guard = self.mutex.lock();
+            if self.cnt.load(atomics::SeqCst) > 0 {
+                f();
+                let prev = self.cnt.swap(int::MIN, atomics::SeqCst);
+                self.lock_cnt.store(prev, atomics::SeqCst);
+            }
+        }
+
+        // Last one out cleans up after everyone else, no leaks!
+        if self.lock_cnt.fetch_add(-1, atomics::SeqCst) == 1 {
+            unsafe { self.mutex.destroy() }
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::{ONCE_INIT, Once};
+    use std::task;
+
+    #[test]
+    fn smoke_once() {
+        static mut o: Once = ONCE_INIT;
+        let mut a = 0;
+        unsafe { o.doit(|| a += 1); }
+        assert_eq!(a, 1);
+        unsafe { o.doit(|| a += 1); }
+        assert_eq!(a, 1);
+    }
+
+    #[test]
+    fn stampede_once() {
+        static mut o: Once = ONCE_INIT;
+        static mut run: bool = false;
+
+        let (p, c) = SharedChan::new();
+        for _ in range(0, 10) {
+            let c = c.clone();
+            spawn(proc() {
+                for _ in range(0, 4) { task::deschedule() }
+                unsafe {
+                    o.doit(|| {
+                        assert!(!run);
+                        run = true;
+                    });
+                    assert!(run);
+                }
+                c.send(());
+            });
+        }
+
+        unsafe {
+            o.doit(|| {
+                assert!(!run);
+                run = true;
+            });
+            assert!(run);
+        }
+
+        for _ in range(0, 10) {
+            p.recv();
+        }
+    }
+}
diff --git a/src/libsync/task_pool.rs b/src/libsync/task_pool.rs
new file mode 100644 (file)
index 0000000..0d8cccf
--- /dev/null
@@ -0,0 +1,92 @@
+// Copyright 2012 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.
+
+#[allow(missing_doc)];
+
+/// A task pool abstraction. Useful for achieving predictable CPU
+/// parallelism.
+
+
+use std::task;
+use std::vec;
+
+enum Msg<T> {
+    Execute(proc(&T)),
+    Quit
+}
+
+pub struct TaskPool<T> {
+    priv channels: ~[Chan<Msg<T>>],
+    priv next_index: uint,
+}
+
+#[unsafe_destructor]
+impl<T> Drop for TaskPool<T> {
+    fn drop(&mut self) {
+        for channel in self.channels.mut_iter() {
+            channel.send(Quit);
+        }
+    }
+}
+
+impl<T> TaskPool<T> {
+    /// Spawns a new task pool with `n_tasks` tasks. If the `sched_mode`
+    /// is None, the tasks run on this scheduler; otherwise, they run on a
+    /// new scheduler with the given mode. The provided `init_fn_factory`
+    /// returns a function which, given the index of the task, should return
+    /// local data to be kept around in that task.
+    pub fn new(n_tasks: uint,
+               init_fn_factory: || -> proc(uint) -> T)
+               -> TaskPool<T> {
+        assert!(n_tasks >= 1);
+
+        let channels = vec::from_fn(n_tasks, |i| {
+            let (port, chan) = Chan::<Msg<T>>::new();
+            let init_fn = init_fn_factory();
+
+            let task_body: proc() = proc() {
+                let local_data = init_fn(i);
+                loop {
+                    match port.recv() {
+                        Execute(f) => f(&local_data),
+                        Quit => break
+                    }
+                }
+            };
+
+            // Run on this scheduler.
+            task::spawn(task_body);
+
+            chan
+        });
+
+        return TaskPool { channels: channels, next_index: 0 };
+    }
+
+    /// Executes the function `f` on a task in the pool. The function
+    /// receives a reference to the local data returned by the `init_fn`.
+    pub fn execute(&mut self, f: proc(&T)) {
+        self.channels[self.next_index].send(Execute(f));
+        self.next_index += 1;
+        if self.next_index == self.channels.len() { self.next_index = 0; }
+    }
+}
+
+#[test]
+fn test_task_pool() {
+    let f: || -> proc(uint) -> uint = || {
+        let g: proc(uint) -> uint = proc(i) i;
+        g
+    };
+    let mut pool = TaskPool::new(4, f);
+    for _ in range(0, 8) {
+        pool.execute(proc(i) println!("Hello from thread {}!", *i));
+    }
+}
index b1b2300466a5edb5fc56fee613b6dcd20a1dcc1e..4b505ec8117622b81d4cd3cc939d40e078fd2dd4 100644 (file)
 // This also serves as a pipes test, because Arcs are implemented with pipes.
 
 extern mod extra;
+extern mod sync;
 
-use extra::arc;
-use extra::future::Future;
+use sync::Arc;
+use sync::MutexArc;
+use sync::Future;
 use extra::time;
 use std::os;
 use std::uint;
 
 // A poor man's pipe.
-type pipe = arc::MutexArc<~[uint]>;
+type pipe = MutexArc<~[uint]>;
 
 fn send(p: &pipe, msg: uint) {
     unsafe {
@@ -46,7 +48,7 @@ fn recv(p: &pipe) -> uint {
 }
 
 fn init() -> (pipe,pipe) {
-    let m = arc::MutexArc::new(~[]);
+    let m = MutexArc::new(~[]);
     ((&m).clone(), m)
 }
 
index d7bd0f2f6bd3da361f406fd23a18f98c47443513..23b4f00b280da976a2d7b90fb8562ef36b7b95d9 100644 (file)
 // This also serves as a pipes test, because Arcs are implemented with pipes.
 
 extern mod extra;
+extern mod sync;
 
-use extra::arc;
-use extra::future::Future;
+use sync::RWArc;
+use sync::Future;
 use extra::time;
 use std::os;
 use std::uint;
 
 // A poor man's pipe.
-type pipe = arc::RWArc<~[uint]>;
+type pipe = RWArc<~[uint]>;
 
 fn send(p: &pipe, msg: uint) {
     p.write_cond(|state, cond| {
@@ -42,7 +43,7 @@ fn recv(p: &pipe) -> uint {
 }
 
 fn init() -> (pipe,pipe) {
-    let x = arc::RWArc::new(~[]);
+    let x = RWArc::new(~[]);
     ((&x).clone(), x)
 }
 
index da658e6d041f734889810987f9973864b4443095..c0e22f207b8f9c0a8e4b9065a2cd0be86e6b1736 100644 (file)
@@ -8,11 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-extern mod extra;
+extern mod sync;
 extern mod arena;
 
 use std::iter::range_step;
-use extra::future::Future;
+use sync::Future;
 use arena::TypedArena;
 
 enum Tree<'a> {
index d68ca4e0abbae800980bb452569c70bec031621c..9de62aaf960e8ba07bd5b21fd92cfca28b4aa948 100644 (file)
 
 // xfail-test arcs no longer unwrap
 
-extern mod extra;
+extern mod sync;
 
 use std::from_str::FromStr;
 use std::iter::count;
 use std::num::min;
 use std::os;
 use std::vec::from_elem;
-use extra::arc::Arc;
-use extra::arc::RWArc;
+use sync::Arc;
+use sync::RWArc;
 
 fn A(i: uint, j: uint) -> f64 {
     ((i + j) * (i + j + 1) / 2 + i + 1) as f64
index 49412b3aafdea57db2d703bf1ff0c6c7c90ef2b2..5c55f10ab4f2a8c7ed8bf46e659e05f19556cc20 100644 (file)
@@ -8,8 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-extern mod extra;
-use extra::arc::RWArc;
+extern mod sync;
+use sync::RWArc;
 
 fn main() {
     let arc1  = RWArc::new(true);
index c31a7bb244c72d5305a0f9f53a05a93bbfdba3ca..c9cd13278822567145669ac7f9fb0f8715f5fa1e 100644 (file)
@@ -9,10 +9,10 @@
 // except according to those terms.
 
 // error-pattern: lifetime of return value does not outlive the function call
-extern mod extra;
-use extra::arc;
+extern mod sync;
+use sync::RWArc;
 fn main() {
-    let x = ~arc::RWArc::new(1);
+    let x = ~RWArc::new(1);
     let mut y = None;
     x.write_cond(|_one, cond| y = Some(cond));
     y.unwrap().wait();
index 716dfe2c8b5c54e2b89af8f032d8615ac01fae77..dfdbd882acff6ed23749f209168734c5911e6ed7 100644 (file)
@@ -8,10 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-extern mod extra;
-use extra::arc;
+extern mod sync;
+use sync::RWArc;
 fn main() {
-    let x = ~arc::RWArc::new(1);
+    let x = ~RWArc::new(1);
     let mut y = None;
     x.write_downgrade(|write_mode| {
         y = Some(x.downgrade(write_mode));
index 7c129ae0dcaad33e0eeeeea78e3bc610563bb0ef..4bb7653d23e5c44d8d5c61dff4fe018b61fa3d5c 100644 (file)
@@ -8,10 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-extern mod extra;
-use extra::arc;
+extern mod sync;
+use sync::RWArc;
 fn main() {
-    let x = ~arc::RWArc::new(1);
+    let x = ~RWArc::new(1);
     let mut y = None; //~ ERROR lifetime of variable does not enclose its declaration
     x.write(|one| y = Some(one));
     *y.unwrap() = 2;
index 674cd5708889c4dfeeb54c81f6079b49f1189801..1410308107e948ac31473b689fe38933e28003a7 100644 (file)
@@ -9,10 +9,10 @@
 // except according to those terms.
 
 // error-pattern: lifetime of variable does not enclose its declaration
-extern mod extra;
-use extra::arc;
+extern mod sync;
+use sync::RWArc;
 fn main() {
-    let x = ~arc::RWArc::new(1);
+    let x = ~RWArc::new(1);
     let mut y = None;
     x.write_downgrade(|write_mode| {
         (&write_mode).write_cond(|_one, cond| {
index 213bf48a08750446aa6220ce09e65a24f71cc739..68226d96a18ef89af256de47ac1cb6d5d91e84cf 100644 (file)
@@ -9,10 +9,10 @@
 // except according to those terms.
 
 // error-pattern: lifetime of variable does not enclose its declaration
-extern mod extra;
-use extra::arc;
+extern mod sync;
+use sync::RWArc;
 fn main() {
-    let x = ~arc::RWArc::new(1);
+    let x = ~RWArc::new(1);
     let mut y = None;
     x.write_downgrade(|write_mode| y = Some(write_mode));
     y.unwrap();
index 00945ea84693cca38682064b87e42b53c06fbd8b..f2c9ba58228938fdf4f15954ead38b13f67b1e76 100644 (file)
@@ -11,8 +11,8 @@
 // issue 7327
 
 // xfail-fast #7103
-extern mod extra;
-use extra::arc::Arc;
+extern mod sync;
+use sync::Arc;
 
 struct A { y: Arc<int>, x: Arc<int> }
 
index aef5d0f9b04a6412b75223f6a7880b33120a708a..69a90275ec78baf49e6200babd9ea3fadc3f1149 100644 (file)
@@ -8,9 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-extern mod extra;
+extern mod sync;
 
-use extra::future::Future;
+use sync::Future;
 
 fn main() {
     let f = Future::from_value(());
index 24a141c4799d520708ea88020c67da576935e005..cdfdd29410e76a1d719ed54d796520621adc0ffa 100644 (file)
@@ -8,10 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-extern mod extra;
+extern mod sync;
 
 use std::task;
-use extra::arc::{MutexArc};
+use sync::MutexArc;
 
 fn test_mutex_arc_nested() {
     let arc = ~MutexArc::new(1);
index 5ae38e69ec0e30c52ba492dec58694705566a3c2..cc529abd6f94f2d0c8dfb4892177596b2588f9b9 100644 (file)
 
 // error-pattern: use of moved value
 
-extern mod extra;
-use extra::arc;
+extern mod sync;
+use sync::Arc;
 
 use std::task;
 
 fn main() {
     let v = ~[1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
-    let arc_v = arc::Arc::new(v);
+    let arc_v = Arc::new(v);
 
     task::spawn(proc() {
         let v = arc_v.get();
index c6c0ba41ab91a45ba21e0fb8af43b6566b61e662..204a0e1cdd4a077bb15a3528fe901a319bc1c950 100644 (file)
@@ -8,14 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-extern mod extra;
-use extra::arc;
+extern mod sync;
+use sync::Arc;
 
 use std::task;
 
 fn main() {
     let v = ~[1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
-    let arc_v = arc::Arc::new(v);
+    let arc_v = Arc::new(v);
 
     task::spawn(proc() {
         let v = arc_v.get();
index 8d5e2229b2e5dc0a10d99eb772db3c6aba21af20..a7e4f8de43704500553ddd13d6c96de68d97337a 100644 (file)
@@ -12,8 +12,8 @@
 // This program would segfault if it were legal.
 
 #[feature(once_fns)];
-extern mod extra;
-use extra::arc;
+extern mod sync;
+use sync::Arc;
 
 fn foo(blk: proc()) {
     blk();
@@ -21,7 +21,7 @@ fn foo(blk: proc()) {
 }
 
 fn main() {
-    let x = arc::Arc::new(true);
+    let x = Arc::new(true);
     foo(proc() {
         assert!(*x.get());
         drop(x);
index 71293555d499dbc6c895d6fe3863d91133f6b545..8b168dd67870ecfc5507348c5fced6999ee866e9 100644 (file)
@@ -12,8 +12,8 @@
 // This program would segfault if it were legal.
 
 #[feature(once_fns)];
-extern mod extra;
-use extra::arc;
+extern mod sync;
+use sync::Arc;
 
 fn foo(blk: once ||) {
     blk();
@@ -21,7 +21,7 @@ fn foo(blk: once ||) {
 }
 
 fn main() {
-    let x = arc::Arc::new(true);
+    let x = Arc::new(true);
     foo(|| {
         assert!(*x.get());
         drop(x);
index 7206b9bdb88eb36d1ac1fb4d87906b53f680b140..4fa6b6af7949e4545e4737aa7282e53dbef175dc 100644 (file)
@@ -11,8 +11,8 @@
 // Testing guarantees provided by once functions.
 // This program would segfault if it were legal.
 
-extern mod extra;
-use extra::arc;
+extern mod sync;
+use sync::Arc;
 
 fn foo(blk: ||) {
     blk();
@@ -20,7 +20,7 @@ fn foo(blk: ||) {
 }
 
 fn main() {
-    let x = arc::Arc::new(true);
+    let x = Arc::new(true);
     foo(|| {
         assert!(*x.get());
         drop(x); //~ ERROR cannot move out of captured outer variable
index 4df08b28eb896e125db87b54608cead6cee92bef..06b8ad6259b6ba4a728d154fb86b36cc299652d0 100644 (file)
@@ -9,8 +9,8 @@
 // except according to those terms.
 
 // error-pattern: lifetime of variable does not enclose its declaration
-extern mod extra;
-use extra::sync;
+extern mod sync;
+use sync::Mutex;
 
 fn main() {
     let m = ~sync::Mutex::new();
index d59eaf62abf84fa3196e06fe519c176454cd7f15..52466c122dd7f76a1d19e9230e50e1655d430ec1 100644 (file)
@@ -9,10 +9,10 @@
 // except according to those terms.
 
 // error-pattern: lifetime of method receiver does not outlive the method call
-extern mod extra;
-use extra::sync;
+extern mod sync;
+use sync::RWLock;
 fn main() {
-    let x = ~sync::RWLock::new();
+    let x = ~RWLock::new();
     let mut y = None;
     x.write_cond(|cond| {
         y = Some(cond);
index 0078841acb139b54a3a1c6c59c915ce4c20670be..0201f9dd51cbfeb76f57659f1b3054645867d267 100644 (file)
@@ -9,10 +9,10 @@
 // except according to those terms.
 
 // error-pattern: cannot infer an appropriate lifetime
-extern mod extra;
-use extra::sync;
+extern mod sync;
+use sync::RWLock;
 fn main() {
-    let x = ~sync::RWLock::new();
+    let x = ~RWLock::new();
     let mut y = None;
     x.write_downgrade(|write_mode| {
         y = Some(x.downgrade(write_mode));
index cbe5181d46f24762d61588083b48e12d90887db0..71a9dd100c395b129da55e0126defd1e17fd6002 100644 (file)
@@ -9,10 +9,10 @@
 // except according to those terms.
 
 // error-pattern: lifetime of variable does not enclose its declaration
-extern mod extra;
-use extra::sync;
+extern mod sync;
+use sync::RWLock;
 fn main() {
-    let x = ~sync::RWLock::new();
+    let x = ~RWLock::new();
     let mut y = None;
     x.write_downgrade(|write_mode| {
         (&write_mode).write_cond(|cond| {
index 6e9216830750b1d729d119a8ea32370860b14f6e..53966bf48a4939f2388e0331220819ec36797ec3 100644 (file)
@@ -9,10 +9,10 @@
 // except according to those terms.
 
 // error-pattern: lifetime of variable does not enclose its declaration
-extern mod extra;
-use extra::sync;
+extern mod sync;
+use sync::RWLock;
 fn main() {
-    let x = ~sync::RWLock::new();
+    let x = ~RWLock::new();
     let mut y = None;
     x.write_downgrade(|write_mode| {
         y = Some(write_mode);
index c1357988f7db59d0a8e58ac3367a1be2c969cd56..16f54e929236a16c978f35b9ddd673c89c6fa7a8 100644 (file)
 
 // error-pattern:explicit failure
 
-extern mod extra;
-use extra::arc;
+extern mod sync;
+use sync::Arc;
 
-enum e<T> { e(arc::Arc<T>) }
+enum e<T> { e(Arc<T>) }
 
 fn foo() -> e<int> {fail!();}
 
index a7a4aa9885e6e89f5bd6b8cb43dc9ac103dbfdf1..3a86357bdaad16c25f476a56e1a19fb9171cf50e 100644 (file)
@@ -9,12 +9,12 @@
 // except according to those terms.
 
 // xfail-fast
-extern mod extra;
-use extra::arc;
-fn dispose(_x: arc::Arc<bool>) { }
+extern mod sync;
+use sync::Arc;
+fn dispose(_x: Arc<bool>) { }
 
 pub fn main() {
-    let p = arc::Arc::new(true);
+    let p = Arc::new(true);
     let x = Some(p);
     match x {
         Some(z) => { dispose(z); },
index bc56712ee3bc1b2b2947c6e8c564b60f13e6a728..0ccf7b8f8a3e1276dd2a8a2cd724fa8cb45f891e 100644 (file)
 // xfail-fast
 
 #[feature(once_fns)];
-extern mod extra;
-use extra::arc;
+extern mod sync;
+use sync::Arc;
 
 fn foo(blk: proc()) {
     blk();
 }
 
 pub fn main() {
-    let x = arc::Arc::new(true);
+    let x = Arc::new(true);
     foo(proc() {
         assert!(*x.get());
         drop(x);
index 07dd5175a0fae1ae50f328b87cbb754a9c0d1d4a..e732d0c76a66354ef10d1bf95aedbdc2d04ed7a5 100644 (file)
 // xfail-fast
 
 #[feature(once_fns)];
-extern mod extra;
-use extra::arc;
+extern mod sync;
+use sync::Arc;
 
 fn foo(blk: once ||) {
     blk();
 }
 
 pub fn main() {
-    let x = arc::Arc::new(true);
+    let x = Arc::new(true);
     foo(|| {
         assert!(*x.get());
         drop(x);
index 2bf18e1ae1d5f67635e4b29eb3c0f8293f8b997f..454da6d2aaa072bae441c371f32d02fb512e316d 100644 (file)
@@ -15,9 +15,9 @@
 
 // xfail-fast
 
-extern mod extra;
+extern mod sync;
 
-use extra::arc;
+use sync::Arc;
 use std::task;
 
 trait Pet {
@@ -65,7 +65,7 @@ pub fn main() {
     let dogge1 = Dogge { bark_decibels: 100, tricks_known: 42, name: ~"alan_turing" };
     let dogge2 = Dogge { bark_decibels: 55,  tricks_known: 11, name: ~"albert_einstein" };
     let fishe = Goldfyshe { swim_speed: 998, name: ~"alec_guinness" };
-    let arc = arc::Arc::new(~[~catte  as ~Pet:Freeze+Send,
+    let arc = Arc::new(~[~catte  as ~Pet:Freeze+Send,
                          ~dogge1 as ~Pet:Freeze+Send,
                          ~fishe  as ~Pet:Freeze+Send,
                          ~dogge2 as ~Pet:Freeze+Send]);
@@ -83,21 +83,21 @@ pub fn main() {
     p3.recv();
 }
 
-fn check_legs(arc: arc::Arc<~[~Pet:Freeze+Send]>) {
+fn check_legs(arc: Arc<~[~Pet:Freeze+Send]>) {
     let mut legs = 0;
     for pet in arc.get().iter() {
         legs += pet.num_legs();
     }
     assert!(legs == 12);
 }
-fn check_names(arc: arc::Arc<~[~Pet:Freeze+Send]>) {
+fn check_names(arc: Arc<~[~Pet:Freeze+Send]>) {
     for pet in arc.get().iter() {
         pet.name(|name| {
             assert!(name[0] == 'a' as u8 && name[1] == 'l' as u8);
         })
     }
 }
-fn check_pedigree(arc: arc::Arc<~[~Pet:Freeze+Send]>) {
+fn check_pedigree(arc: Arc<~[~Pet:Freeze+Send]>) {
     for pet in arc.get().iter() {
         assert!(pet.of_good_pedigree());
     }