提交 a23511a6 编写于 作者: A Aaron Turon 提交者: Alex Crichton

Revamp TaskBuilder API

This patch consolidates and cleans up the task spawning APIs:

* Removes the problematic `future_result` method from `std::task::TaskBuilder`,
  and adds a `try_future` that both spawns the task and returns a future
  representing its eventual result (or failure).

* Removes the public `opts` field from `TaskBuilder`, instead adding appropriate
  builder methods to configure the task.

* Adds extension traits to libgreen and libnative that add methods to
  `TaskBuilder` for spawning the task as a green or native thread.

Previously, there was no way to benefit from the `TaskBuilder` functionality and
also set the scheduler to spawn within.

With this change, all task spawning scenarios are supported through the
`TaskBuilder` interface.

Closes #3725.

[breaking-change]
上级 8e9e17d1
......@@ -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;
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 @@ pub fn new(config: PoolConfig) -> 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 @@ pub fn task(&mut self, opts: TaskOpts, f: proc():Send) -> Box<GreenTask> {
/// 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 @@ fn drop(&mut self) {
}
}
}
/// 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();
}
}
......@@ -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
//! });
//! }
......@@ -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
......@@ -65,6 +69,8 @@
use std::rt;
use std::str;
pub use task::NativeTaskBuilder;
pub mod io;
pub mod task;
......
......@@ -27,6 +27,7 @@
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)
}
}
// 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 @@ fn spawn_inherits() {
});
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());
}
}
此差异已折叠。
// 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.
use std::io::{ChanReader, ChanWriter};
use std::task::build;
fn main() {
let (tx, rx) = channel();
let mut reader = ChanReader::new(rx);
let stderr = ChanWriter::new(tx);
let res = build().stderr(box stderr as Box<Writer + Send>).try(proc() -> () {
fail!("Hello, world!")
});
assert!(res.is_err());
let output = reader.read_to_str().unwrap();
assert!(output.as_slice().contains("Hello, world!"));
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册