Skip to content

Commit

Permalink
move concurrent stuff from libextra to libsync
Browse files Browse the repository at this point in the history
  • Loading branch information
jeremyletang committed Feb 5, 2014
1 parent ed885e3 commit dd21a51
Show file tree
Hide file tree
Showing 48 changed files with 224 additions and 145 deletions.
9 changes: 5 additions & 4 deletions mk/crates.mk
Expand Up @@ -49,25 +49,26 @@
# 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
Expand Down
108 changes: 75 additions & 33 deletions src/doc/guide-tasks.md
Expand Up @@ -39,26 +39,51 @@ 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
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

Expand Down Expand Up @@ -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
Expand All @@ -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;
Expand All @@ -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() {
Expand All @@ -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)))
Expand Down Expand Up @@ -348,39 +379,48 @@ 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.

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.
Expand Down Expand Up @@ -450,25 +490,27 @@ 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
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
Expand All @@ -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; }
# }
# }
Expand Down
1 change: 1 addition & 0 deletions src/doc/index.md
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion src/etc/licenseck.py
Expand Up @@ -41,7 +41,7 @@
"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):
Expand Down
15 changes: 7 additions & 8 deletions src/libextra/lib.rs
Expand Up @@ -34,17 +34,16 @@ Rust extras are part of the standard Rust distribution.
#[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

Expand Down
2 changes: 1 addition & 1 deletion src/libextra/workcache.rs
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/back/link.rs
Expand Up @@ -331,7 +331,7 @@ pub mod write {
}

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
Expand Down
1 change: 1 addition & 0 deletions src/librustc/lib.rs
Expand Up @@ -35,6 +35,7 @@ extern mod extra;
extern mod flate;
extern mod arena;
extern mod syntax;
extern mod sync;

use back::link;
use driver::session;
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/trans/base.rs
Expand Up @@ -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(|| {
Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/html/render.rs
Expand Up @@ -41,7 +41,7 @@ use std::io::{fs, File, BufferedWriter};
use std::str;
use std::vec;

use extra::arc::Arc;
use sync::Arc;
use extra::json::ToJson;
use syntax::ast;
use syntax::attr;
Expand Down
1 change: 1 addition & 0 deletions src/librustdoc/lib.rs
Expand Up @@ -18,6 +18,7 @@
extern mod syntax;
extern mod rustc;
extern mod extra;
extern mod sync;

use std::local_data;
use std::io;
Expand Down
8 changes: 4 additions & 4 deletions src/libextra/arc.rs → src/libsync/arc.rs
Expand Up @@ -18,7 +18,7 @@
* With simple pipes, without Arc, a copy would have to be made for each task.
*
* ```rust
* use extra::arc::Arc;
* use sync::Arc;
* use std::{rand, vec};
*
* let numbers = vec::from_fn(100, |i| (i as f32) * rand::random());
Expand All @@ -38,7 +38,7 @@
* ```
*/

#[allow(missing_doc)];
#[allow(missing_doc, dead_code)];


use sync;
Expand Down Expand Up @@ -424,7 +424,7 @@ impl<T:Freeze + Send> RWArc<T> {
* # Example
*
* ```rust
* use extra::arc::RWArc;
* use sync::RWArc;
*
* let arc = RWArc::new(1);
* arc.write_downgrade(|mut write_token| {
Expand Down Expand Up @@ -605,7 +605,7 @@ impl<T:Clone+Send+Freeze> Clone for CowArc<T> {
#[cfg(test)]
mod tests {

use arc::*;
use super::{Arc, RWArc, MutexArc, CowArc};

use std::task;

Expand Down
File renamed without changes.

5 comments on commit dd21a51

@bors
Copy link
Contributor

@bors bors commented on dd21a51 Feb 5, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

saw approval from alexcrichton
at jeremyletang@dd21a51

@bors
Copy link
Contributor

@bors bors commented on dd21a51 Feb 5, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merging JeremyLetang/rust/move-libsync = dd21a51 into auto

@bors
Copy link
Contributor

@bors bors commented on dd21a51 Feb 5, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JeremyLetang/rust/move-libsync = dd21a51 merged ok, testing candidate = 2bf575c

@bors
Copy link
Contributor

@bors bors commented on dd21a51 Feb 5, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bors
Copy link
Contributor

@bors bors commented on dd21a51 Feb 5, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fast-forwarding master to auto = 2bf575c

Please sign in to comment.