-
Notifications
You must be signed in to change notification settings - Fork 13.2k
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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() { | ||
|
@@ -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 | ||
|
@@ -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; | ||
|
@@ -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; | ||
|
@@ -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) | ||
} | ||
|
@@ -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); | ||
|
||
|
@@ -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>>; | ||
} | ||
|
||
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(); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is so slick, I wonder if the |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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> { | ||
|
@@ -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; | ||
|
||
|
@@ -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) | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||
|
||
// This structure is the glue between channels and the 1:1 scheduling mode. This | ||
// structure is allocated once per task. | ||
struct Ops { | ||
|
@@ -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() { | ||
|
@@ -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()); | ||
} | ||
} |
There was a problem hiding this comment.
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?