Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

std::task - Revamp TaskBuilder API #14989

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 67 additions & 11 deletions src/libgreen/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,16 +159,19 @@
//!
//! # Using a scheduler pool
//!
//! This library adds a `GreenTaskBuilder` trait that extends the methods
//! available on `std::task::TaskBuilder` to allow spawning a green task,
//! possibly pinned to a particular scheduler thread:
//!
//! ```rust
//! use std::rt::task::TaskOpts;
//! use green::{SchedPool, PoolConfig};
//! use green::sched::{PinnedTask, TaskFromFriend};
//! use std::task::TaskBuilder;
//! use green::{SchedPool, PoolConfig, GreenTaskBuilder};
//!
//! let config = PoolConfig::new();
//! let mut pool = SchedPool::new(config);
//!
//! // Spawn tasks into the pool of schedulers
//! pool.spawn(TaskOpts::new(), proc() {
//! TaskBuilder::new().green(&mut pool).spawn(proc() {
//! // this code is running inside the pool of schedulers
//!
//! spawn(proc() {
Expand All @@ -181,12 +184,9 @@
//! let mut handle = pool.spawn_sched();
//!
//! // Pin a task to the spawned scheduler
//! let task = pool.task(TaskOpts::new(), proc() { /* ... */ });
//! handle.send(PinnedTask(task));
//!
//! // Schedule a task on this new scheduler
//! let task = pool.task(TaskOpts::new(), proc() { /* ... */ });
//! handle.send(TaskFromFriend(task));
//! TaskBuilder::new().green_pinned(&mut pool, &mut handle).spawn(proc() {
//! /* ... */
//! });
//!
//! // Handles keep schedulers alive, so be sure to drop all handles before
//! // destroying the sched pool
Expand All @@ -209,6 +209,8 @@
// NB this does *not* include globs, please keep it that way.
#![feature(macro_rules, phase)]
#![allow(visible_private_types)]
#![allow(deprecated)]
#![feature(default_type_params)]

#[cfg(test)] #[phase(plugin, link)] extern crate log;
#[cfg(test)] extern crate rustuv;
Expand All @@ -224,8 +226,9 @@ use std::rt::task::TaskOpts;
use std::rt;
use std::sync::atomics::{SeqCst, AtomicUint, INIT_ATOMIC_UINT};
use std::sync::deque;
use std::task::{TaskBuilder, Spawner};

use sched::{Shutdown, Scheduler, SchedHandle, TaskFromFriend, NewNeighbor};
use sched::{Shutdown, Scheduler, SchedHandle, TaskFromFriend, PinnedTask, NewNeighbor};
use sleeper_list::SleeperList;
use stack::StackPool;
use task::GreenTask;
Expand Down Expand Up @@ -444,6 +447,7 @@ impl SchedPool {
/// This is useful to create a task which can then be sent to a specific
/// scheduler created by `spawn_sched` (and possibly pin it to that
/// scheduler).
#[deprecated = "use the green and green_pinned methods of GreenTaskBuilder instead"]
pub fn task(&mut self, opts: TaskOpts, f: proc():Send) -> Box<GreenTask> {
GreenTask::configure(&mut self.stack_pool, opts, f)
}
Expand All @@ -454,6 +458,7 @@ impl SchedPool {
/// New tasks are spawned in a round-robin fashion to the schedulers in this
/// pool, but tasks can certainly migrate among schedulers once they're in
/// the pool.
#[deprecated = "use the green and green_pinned methods of GreenTaskBuilder instead"]
pub fn spawn(&mut self, opts: TaskOpts, f: proc():Send) {
let task = self.task(opts, f);

Expand Down Expand Up @@ -563,3 +568,54 @@ impl Drop for SchedPool {
}
}
}

/// A spawner for green tasks
pub struct GreenSpawner<'a>{
pool: &'a mut SchedPool,
handle: Option<&'a mut SchedHandle>
}

impl<'a> Spawner for GreenSpawner<'a> {
#[inline]
fn spawn(self, opts: TaskOpts, f: proc():Send) {
let GreenSpawner { pool, handle } = self;
match handle {
None => pool.spawn(opts, f),
Some(h) => h.send(PinnedTask(pool.task(opts, f)))
}
}
}

/// An extension trait adding `green` configuration methods to `TaskBuilder`.
pub trait GreenTaskBuilder {
fn green<'a>(self, &'a mut SchedPool) -> TaskBuilder<GreenSpawner<'a>>;
fn green_pinned<'a>(self, &'a mut SchedPool, &'a mut SchedHandle)
-> TaskBuilder<GreenSpawner<'a>>;
}
Copy link
Member

Choose a reason for hiding this comment

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

Could you update the crate documentation with a reference to this trait?


impl<S: Spawner> GreenTaskBuilder for TaskBuilder<S> {
fn green<'a>(self, pool: &'a mut SchedPool) -> TaskBuilder<GreenSpawner<'a>> {
self.spawner(GreenSpawner {pool: pool, handle: None})
}

fn green_pinned<'a>(self, pool: &'a mut SchedPool, handle: &'a mut SchedHandle)
-> TaskBuilder<GreenSpawner<'a>> {
self.spawner(GreenSpawner {pool: pool, handle: Some(handle)})
}
}

#[cfg(test)]
mod test {
use std::task::TaskBuilder;
use super::{SchedPool, PoolConfig, GreenTaskBuilder};

#[test]
fn test_green_builder() {
let mut pool = SchedPool::new(PoolConfig::new());
let res = TaskBuilder::new().green(&mut pool).try(proc() {
"Success!".to_string()
});
assert_eq!(res.ok().unwrap(), "Success!".to_string());
pool.shutdown();
}
Copy link
Member

Choose a reason for hiding this comment

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

This is so slick, I wonder if the SchedPool api should be scaled back...

}
10 changes: 8 additions & 2 deletions src/libnative/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,13 @@
//! ```rust
//! extern crate native;
//!
//! use std::task::TaskBuilder;
//! use native::NativeTaskBuilder;
//!
//! fn main() {
//! // We're not sure whether this main function is run in 1:1 or M:N mode.
//!
//! native::task::spawn(proc() {
//! TaskBuilder::new().native().spawn(proc() {
//! // this code is guaranteed to be run on a native thread
//! });
//! }
Expand All @@ -50,7 +53,8 @@
html_root_url = "http://doc.rust-lang.org/")]
#![deny(unused_result, unused_must_use)]
#![allow(non_camel_case_types)]
#![feature(macro_rules)]
#![allow(deprecated)]
#![feature(default_type_params)]

// NB this crate explicitly does *not* allow glob imports, please seriously
// consider whether they're needed before adding that feature here (the
Expand All @@ -65,6 +69,8 @@ use std::os;
use std::rt;
use std::str;

pub use task::NativeTaskBuilder;

pub mod io;
pub mod task;

Expand Down
34 changes: 33 additions & 1 deletion src/libnative/task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ use std::rt;

use io;
use task;
use std::task::{TaskBuilder, Spawner};

/// Creates a new Task which is ready to execute as a 1:1 task.
pub fn new(stack_bounds: (uint, uint)) -> Box<Task> {
Expand All @@ -48,12 +49,14 @@ fn ops() -> Box<Ops> {
}

/// Spawns a function with the default configuration
#[deprecated = "use the native method of NativeTaskBuilder instead"]
pub fn spawn(f: proc():Send) {
spawn_opts(TaskOpts { name: None, stack_size: None, on_exit: None }, f)
}

/// Spawns a new task given the configuration options and a procedure to run
/// inside the task.
#[deprecated = "use the native method of NativeTaskBuilder instead"]
pub fn spawn_opts(opts: TaskOpts, f: proc():Send) {
let TaskOpts { name, stack_size, on_exit } = opts;

Expand Down Expand Up @@ -95,6 +98,26 @@ pub fn spawn_opts(opts: TaskOpts, f: proc():Send) {
})
}

/// A spawner for native tasks
pub struct NativeSpawner;

impl Spawner for NativeSpawner {
fn spawn(self, opts: TaskOpts, f: proc():Send) {
spawn_opts(opts, f)
}
}

/// An extension trait adding a `native` configuration method to `TaskBuilder`.
pub trait NativeTaskBuilder {
fn native(self) -> TaskBuilder<NativeSpawner>;
}

impl<S: Spawner> NativeTaskBuilder for TaskBuilder<S> {
fn native(self) -> TaskBuilder<NativeSpawner> {
self.spawner(NativeSpawner)
}
}
Copy link
Member

Choose a reason for hiding this comment

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

This does sort of add "yet another way" to spawn a native task. It's less ergonomic than native::task::spawn due to importing a trait, but perhaps native::task::spawn should be considered for removal?


// This structure is the glue between channels and the 1:1 scheduling mode. This
// structure is allocated once per task.
struct Ops {
Expand Down Expand Up @@ -259,7 +282,8 @@ mod tests {
use std::rt::local::Local;
use std::rt::task::{Task, TaskOpts};
use std::task;
use super::{spawn, spawn_opts, Ops};
use std::task::TaskBuilder;
use super::{spawn, spawn_opts, Ops, NativeTaskBuilder};

#[test]
fn smoke() {
Expand Down Expand Up @@ -347,4 +371,12 @@ mod tests {
});
rx.recv();
}

#[test]
fn test_native_builder() {
let res = TaskBuilder::new().native().try(proc() {
"Success!".to_string()
});
assert_eq!(res.ok().unwrap(), "Success!".to_string());
}
}
17 changes: 7 additions & 10 deletions src/librustc/driver/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -366,22 +366,19 @@ fn monitor(f: proc():Send) {
#[cfg(not(rtopt))]
static STACK_SIZE: uint = 20000000; // 20MB

let mut task_builder = TaskBuilder::new().named("rustc");
let (tx, rx) = channel();
let w = io::ChanWriter::new(tx);
let mut r = io::ChanReader::new(rx);

let mut task = TaskBuilder::new().named("rustc").stderr(box w);

// FIXME: Hacks on hacks. If the env is trying to override the stack size
// then *don't* set it explicitly.
if os::getenv("RUST_MIN_STACK").is_none() {
task_builder.opts.stack_size = Some(STACK_SIZE);
task = task.stack_size(STACK_SIZE);
}

let (tx, rx) = channel();
let w = io::ChanWriter::new(tx);
let mut r = io::ChanReader::new(rx);

match task_builder.try(proc() {
io::stdio::set_stderr(box w);
f()
}) {
match task.try(f) {
Ok(()) => { /* fallthrough */ }
Err(value) => {
// Task failed without emitting a fatal diagnostic
Expand Down
Loading