diff options
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/lib.rs | 2 | ||||
| -rw-r--r-- | src/libstd/rt/mod.rs | 9 | ||||
| -rw-r--r-- | src/libstd/sync/future.rs | 31 | ||||
| -rw-r--r-- | src/libstd/sync/task_pool.rs | 16 | ||||
| -rw-r--r-- | src/libstd/sys/unix/process.rs | 16 | ||||
| -rw-r--r-- | src/libstd/task.rs | 128 |
6 files changed, 115 insertions, 87 deletions
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index c2363c9946a..e99aba9b673 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -171,6 +171,8 @@ pub use rustrt::c_str; pub use unicode::char; +pub use rustrt::thunk; + /* Exported macros */ pub mod macros; diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index 5ecd3ff04f1..eb517047ddc 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -52,6 +52,7 @@ use borrow::IntoCow; use failure; use rustrt; use os; +use thunk::Thunk; // Reexport some of our utilities which are expected by other crates. pub use self::util::{default_sched_threads, min_stack, running_on_valgrind}; @@ -87,10 +88,10 @@ static OS_DEFAULT_STACK_ESTIMATE: uint = 2 * (1 << 20); #[lang = "start"] fn lang_start(main: *const u8, argc: int, argv: *const *const u8) -> int { use mem; - start(argc, argv, proc() { + start(argc, argv, Thunk::new(move|| { let main: extern "Rust" fn() = unsafe { mem::transmute(main) }; main(); - }) + })) } /// Executes the given procedure after initializing the runtime with the given @@ -102,7 +103,7 @@ fn lang_start(main: *const u8, argc: int, argv: *const *const u8) -> int { /// /// This function will only return once *all* native threads in the system have /// exited. -pub fn start(argc: int, argv: *const *const u8, main: proc()) -> int { +pub fn start(argc: int, argv: *const *const u8, main: Thunk) -> int { use prelude::*; use rt; use rustrt::task::Task; @@ -144,7 +145,7 @@ pub fn start(argc: int, argv: *const *const u8, main: proc()) -> int { unsafe { rustrt::stack::record_os_managed_stack_bounds(my_stack_bottom, my_stack_top); } - (main.take().unwrap())(); + (main.take().unwrap()).invoke(()); exit_code = Some(os::get_exit_status()); }).destroy()); unsafe { rt::cleanup(); } diff --git a/src/libstd/sync/future.rs b/src/libstd/sync/future.rs index a8c9983e5aa..e5a1e09967c 100644 --- a/src/libstd/sync/future.rs +++ b/src/libstd/sync/future.rs @@ -17,7 +17,7 @@ //! use std::sync::Future; //! # fn fib(n: uint) -> uint {42}; //! # fn make_a_sandwich() {}; -//! let mut delayed_fib = Future::spawn(proc() { fib(5000) }); +//! let mut delayed_fib = Future::spawn(move|| { fib(5000) }); //! make_a_sandwich(); //! println!("fib(5000) = {}", delayed_fib.get()) //! ``` @@ -30,6 +30,7 @@ use core::mem::replace; use self::FutureState::*; use comm::{Receiver, channel}; use task::spawn; +use thunk::{Thunk}; /// A type encapsulating the result of a computation which may not be complete pub struct Future<A> { @@ -37,7 +38,7 @@ pub struct Future<A> { } enum FutureState<A> { - Pending(proc():Send -> A), + Pending(Thunk<(),A>), Evaluating, Forced(A) } @@ -78,7 +79,7 @@ impl<A> Future<A> { match replace(&mut self.state, Evaluating) { Forced(_) | Evaluating => panic!("Logic error."), Pending(f) => { - self.state = Forced(f()); + self.state = Forced(f.invoke(())); self.get_ref() } } @@ -97,7 +98,9 @@ impl<A> Future<A> { Future {state: Forced(val)} } - pub fn from_fn(f: proc():Send -> A) -> Future<A> { + pub fn from_fn<F>(f: F) -> Future<A> + where F : FnOnce() -> A, F : Send + { /*! * Create a future from a function. * @@ -106,7 +109,7 @@ impl<A> Future<A> { * function. It is not spawned into another task. */ - Future {state: Pending(f)} + Future {state: Pending(Thunk::new(f))} } } @@ -119,12 +122,14 @@ impl<A:Send> Future<A> { * waiting for the result to be received on the port. */ - Future::from_fn(proc() { + Future::from_fn(move|:| { rx.recv() }) } - pub fn spawn(blk: proc():Send -> A) -> Future<A> { + pub fn spawn<F>(blk: F) -> Future<A> + where F : FnOnce() -> A, F : Send + { /*! * Create a future from a unique closure. * @@ -134,7 +139,7 @@ impl<A:Send> Future<A> { let (tx, rx) = channel(); - spawn(proc() { + spawn(move |:| { // Don't panic if the other end has hung up let _ = tx.send_opt(blk()); }); @@ -166,7 +171,7 @@ mod test { #[test] fn test_from_fn() { - let mut f = Future::from_fn(proc() "brail".to_string()); + let mut f = Future::from_fn(move|| "brail".to_string()); assert_eq!(f.get(), "brail"); } @@ -190,14 +195,14 @@ mod test { #[test] fn test_spawn() { - let mut f = Future::spawn(proc() "bale".to_string()); + let mut f = Future::spawn(move|| "bale".to_string()); assert_eq!(f.get(), "bale"); } #[test] #[should_fail] fn test_future_panic() { - let mut f = Future::spawn(proc() panic!()); + let mut f = Future::spawn(move|| panic!()); let _x: String = f.get(); } @@ -205,8 +210,8 @@ mod test { fn test_sendable_future() { let expected = "schlorf"; let (tx, rx) = channel(); - let f = Future::spawn(proc() { expected }); - task::spawn(proc() { + let f = Future::spawn(move|| { expected }); + task::spawn(move|| { let mut f = f; tx.send(f.get()); }); diff --git a/src/libstd/sync/task_pool.rs b/src/libstd/sync/task_pool.rs index 4ae5cd054f6..a684c6502ae 100644 --- a/src/libstd/sync/task_pool.rs +++ b/src/libstd/sync/task_pool.rs @@ -72,7 +72,7 @@ pub struct TaskPool { // // This is the only such Sender, so when it is dropped all subtasks will // quit. - jobs: Sender<proc(): Send> + jobs: Sender<Thunk> } impl TaskPool { @@ -84,7 +84,7 @@ impl TaskPool { pub fn new(tasks: uint) -> TaskPool { assert!(tasks >= 1); - let (tx, rx) = channel::<proc(): Send>(); + let (tx, rx) = channel::<Thunk>(); let rx = Arc::new(Mutex::new(rx)); // Taskpool tasks. @@ -96,13 +96,15 @@ impl TaskPool { } /// Executes the function `job` on a task in the pool. - pub fn execute(&self, job: proc():Send) { - self.jobs.send(job); + pub fn execute<F>(&self, job: F) + where F : FnOnce(), F : Send + { + self.jobs.send(Thunk::new(job)); } } -fn spawn_in_pool(jobs: Arc<Mutex<Receiver<proc(): Send>>>) { - spawn(proc() { +fn spawn_in_pool(jobs: Arc<Mutex<Receiver<Thunk>>>) { + spawn(move |:| { // Will spawn a new task on panic unless it is cancelled. let sentinel = Sentinel::new(&jobs); @@ -115,7 +117,7 @@ fn spawn_in_pool(jobs: Arc<Mutex<Receiver<proc(): Send>>>) { }; match message { - Ok(job) => job(), + Ok(job) => job.invoke(()), // The Taskpool was dropped. Err(..) => break diff --git a/src/libstd/sys/unix/process.rs b/src/libstd/sys/unix/process.rs index dfbba0f335c..f71b34304ab 100644 --- a/src/libstd/sys/unix/process.rs +++ b/src/libstd/sys/unix/process.rs @@ -531,8 +531,11 @@ impl Process { } } -fn with_argv<T>(prog: &CString, args: &[CString], - cb: proc(*const *const libc::c_char) -> T) -> T { +fn with_argv<T,F>(prog: &CString, args: &[CString], + cb: F) + -> T + where F : FnOnce(*const *const libc::c_char) -> T +{ let mut ptrs: Vec<*const libc::c_char> = Vec::with_capacity(args.len()+1); // Convert the CStrings into an array of pointers. Note: the @@ -549,9 +552,12 @@ fn with_argv<T>(prog: &CString, args: &[CString], cb(ptrs.as_ptr()) } -fn with_envp<K, V, T>(env: Option<&collections::HashMap<K, V>>, - cb: proc(*const c_void) -> T) -> T - where K: BytesContainer + Eq + Hash, V: BytesContainer +fn with_envp<K,V,T,F>(env: Option<&collections::HashMap<K, V>>, + cb: F) + -> T + where F : FnOnce(*const c_void) -> T, + K : BytesContainer + Eq + Hash, + V : BytesContainer { // On posixy systems we can pass a char** for envp, which is a // null-terminated array of "k=v\0" strings. Since we must create diff --git a/src/libstd/task.rs b/src/libstd/task.rs index 5a1a5b4fb7a..340e283708a 100644 --- a/src/libstd/task.rs +++ b/src/libstd/task.rs @@ -35,7 +35,7 @@ //! ## Example //! //! ```rust -//! spawn(proc() { +//! spawn(move|| { //! println!("Hello, World!"); //! }) //! ``` @@ -47,6 +47,7 @@ use any::Any; use borrow::IntoCow; use boxed::Box; use comm::channel; +use core::ops::FnOnce; use io::{Writer, stdio}; use kinds::{Send, marker}; use option::Option; @@ -57,6 +58,7 @@ use rustrt::task::Task; use rustrt::task; use str::SendStr; use string::{String, ToString}; +use thunk::{Thunk}; use sync::Future; /// The task builder type. @@ -80,7 +82,7 @@ pub struct TaskBuilder { // Task-local stderr stderr: Option<Box<Writer + Send>>, // Optionally wrap the eventual task body - gen_body: Option<proc(v: proc():Send):Send -> proc():Send>, + gen_body: Option<Thunk<Thunk, Thunk>>, nocopy: marker::NoCopy, } @@ -129,41 +131,46 @@ impl TaskBuilder { } // Where spawning actually happens (whether yielding a future or not) - fn spawn_internal(self, f: proc():Send, - on_exit: Option<proc(Result<(), Box<Any + Send>>):Send>) { + fn spawn_internal( + self, + f: Thunk, + on_exit: Option<Thunk<task::Result>>) + { let TaskBuilder { name, stack_size, stdout, stderr, mut gen_body, nocopy: _ } = self; + let f = match gen_body.take() { - Some(gen) => gen(f), + Some(gen) => gen.invoke(f), None => f }; + let opts = task::TaskOpts { on_exit: on_exit, name: name, stack_size: stack_size, }; if stdout.is_some() || stderr.is_some() { - Task::spawn(opts, proc() { + Task::spawn(opts, move|:| { let _ = stdout.map(stdio::set_stdout); let _ = stderr.map(stdio::set_stderr); - f(); - }) + f.invoke(()); + }); } else { - Task::spawn(opts, f) + Task::spawn(opts, move|:| f.invoke(())) } } /// Creates and executes a new child task. /// /// Sets up a new task with its own call stack and schedules it to run - /// the provided proc. The task has the properties and behavior + /// the provided function. The task has the properties and behavior /// specified by the `TaskBuilder`. - pub fn spawn(self, f: proc():Send) { - self.spawn_internal(f, None) + pub fn spawn<F:FnOnce()+Send>(self, f: F) { + self.spawn_internal(Thunk::new(f), None) } - /// Execute a proc in a newly-spawned task and return a future representing + /// Execute a function in a newly-spawned task and return a future representing /// the task's result. The task has the properties and behavior /// specified by the `TaskBuilder`. /// @@ -178,20 +185,22 @@ impl TaskBuilder { /// `result::Result::Err` containing the argument to `panic!(...)` as an /// `Any` trait object. #[experimental = "Futures are experimental."] - pub fn try_future<T:Send>(self, f: proc():Send -> T) - -> Future<Result<T, Box<Any + Send>>> { - // currently, the on_exit proc provided by librustrt only works for unit + pub fn try_future<T:Send,F:FnOnce()->(T)+Send>(self, f: F) + -> Future<Result<T, Box<Any + Send>>> { + // currently, the on_exit fn provided by librustrt only works for unit // results, so we use an additional side-channel to communicate the // result. let (tx_done, rx_done) = channel(); // signal that task has exited let (tx_retv, rx_retv) = channel(); // return value from task - let on_exit = proc(res) { let _ = tx_done.send_opt(res); }; - self.spawn_internal(proc() { let _ = tx_retv.send_opt(f()); }, + let on_exit: Thunk<task::Result> = Thunk::with_arg(move |: res: task::Result| { + let _ = tx_done.send_opt(res); + }); + self.spawn_internal(Thunk::new(move |:| { let _ = tx_retv.send_opt(f()); }), Some(on_exit)); - Future::from_fn(proc() { + Future::from_fn(move|:| { rx_done.recv().map(|_| rx_retv.recv()) }) } @@ -199,7 +208,9 @@ impl TaskBuilder { /// Execute a function in a newly-spawnedtask and block until the task /// completes or panics. Equivalent to `.try_future(f).unwrap()`. #[unstable = "Error type may change."] - pub fn try<T:Send>(self, f: proc():Send -> T) -> Result<T, Box<Any + Send>> { + pub fn try<T,F>(self, f: F) -> Result<T, Box<Any + Send>> + where F : FnOnce() -> T, F : Send, T : Send + { self.try_future(f).into_inner() } } @@ -212,7 +223,7 @@ impl TaskBuilder { /// the provided unique closure. /// /// This function is equivalent to `TaskBuilder::new().spawn(f)`. -pub fn spawn(f: proc(): Send) { +pub fn spawn<F:FnOnce()+Send>(f: F) { TaskBuilder::new().spawn(f) } @@ -221,7 +232,9 @@ pub fn spawn(f: proc(): Send) { /// /// This is equivalent to `TaskBuilder::new().try`. #[unstable = "Error type may change."] -pub fn try<T: Send>(f: proc(): Send -> T) -> Result<T, Box<Any + Send>> { +pub fn try<T,F>(f: F) -> Result<T, Box<Any + Send>> + where T : Send, F : FnOnce() -> T, F : Send +{ TaskBuilder::new().try(f) } @@ -230,11 +243,12 @@ pub fn try<T: Send>(f: proc(): Send -> T) -> Result<T, Box<Any + Send>> { /// /// This is equivalent to `TaskBuilder::new().try_future`. #[experimental = "Futures are experimental."] -pub fn try_future<T:Send>(f: proc():Send -> T) -> Future<Result<T, Box<Any + Send>>> { +pub fn try_future<T,F>(f: F) -> Future<Result<T, Box<Any + Send>>> + where T:Send, F:FnOnce()->T, F:Send +{ TaskBuilder::new().try_future(f) } - /* Lifecycle functions */ /// Read the name of the current task. @@ -274,6 +288,8 @@ mod test { use result; use std::io::{ChanReader, ChanWriter}; use string::String; + use thunk::Thunk; + use prelude::*; use super::*; // !!! These tests are dangerous. If something is buggy, they will hang, !!! @@ -281,28 +297,28 @@ mod test { #[test] fn test_unnamed_task() { - try(proc() { + try(move|| { assert!(name().is_none()); }).map_err(|_| ()).unwrap(); } #[test] fn test_owned_named_task() { - TaskBuilder::new().named("ada lovelace".to_string()).try(proc() { + TaskBuilder::new().named("ada lovelace".to_string()).try(move|| { assert!(name().unwrap() == "ada lovelace"); }).map_err(|_| ()).unwrap(); } #[test] fn test_static_named_task() { - TaskBuilder::new().named("ada lovelace").try(proc() { + TaskBuilder::new().named("ada lovelace").try(move|| { assert!(name().unwrap() == "ada lovelace"); }).map_err(|_| ()).unwrap(); } #[test] fn test_send_named_task() { - TaskBuilder::new().named("ada lovelace".into_cow()).try(proc() { + TaskBuilder::new().named("ada lovelace".into_cow()).try(move|| { assert!(name().unwrap() == "ada lovelace"); }).map_err(|_| ()).unwrap(); } @@ -310,7 +326,7 @@ mod test { #[test] fn test_run_basic() { let (tx, rx) = channel(); - TaskBuilder::new().spawn(proc() { + TaskBuilder::new().spawn(move|| { tx.send(()); }); rx.recv(); @@ -318,10 +334,10 @@ mod test { #[test] fn test_try_future() { - let result = TaskBuilder::new().try_future(proc() {}); + let result = TaskBuilder::new().try_future(move|| {}); assert!(result.unwrap().is_ok()); - let result = TaskBuilder::new().try_future(proc() -> () { + let result = TaskBuilder::new().try_future(move|| -> () { panic!(); }); assert!(result.unwrap().is_err()); @@ -329,7 +345,7 @@ mod test { #[test] fn test_try_success() { - match try(proc() { + match try(move|| { "Success!".to_string() }).as_ref().map(|s| s.as_slice()) { result::Result::Ok("Success!") => (), @@ -339,7 +355,7 @@ mod test { #[test] fn test_try_panic() { - match try(proc() { + match try(move|| { panic!() }) { result::Result::Err(_) => (), @@ -355,7 +371,7 @@ mod test { fn f(i: int, tx: Sender<()>) { let tx = tx.clone(); - spawn(proc() { + spawn(move|| { if i == 0 { tx.send(()); } else { @@ -372,8 +388,8 @@ mod test { fn test_spawn_sched_childs_on_default_sched() { let (tx, rx) = channel(); - spawn(proc() { - spawn(proc() { + spawn(move|| { + spawn(move|| { tx.send(()); }); }); @@ -382,17 +398,17 @@ mod test { } fn avoid_copying_the_body<F>(spawnfn: F) where - F: FnOnce(proc():Send), + F: FnOnce(Thunk), { let (tx, rx) = channel::<uint>(); let x = box 1; let x_in_parent = (&*x) as *const int as uint; - spawnfn(proc() { + spawnfn(Thunk::new(move|| { let x_in_child = (&*x) as *const int as uint; tx.send(x_in_child); - }); + })); let x_in_child = rx.recv(); assert_eq!(x_in_parent, x_in_child); @@ -400,25 +416,21 @@ mod test { #[test] fn test_avoid_copying_the_body_spawn() { - avoid_copying_the_body(spawn); + avoid_copying_the_body(|t| spawn(move|| t.invoke(()))); } #[test] fn test_avoid_copying_the_body_task_spawn() { avoid_copying_the_body(|f| { let builder = TaskBuilder::new(); - builder.spawn(proc() { - f(); - }); + builder.spawn(move|| f.invoke(())); }) } #[test] fn test_avoid_copying_the_body_try() { avoid_copying_the_body(|f| { - let _ = try(proc() { - f() - }); + let _ = try(move|| f.invoke(())); }) } @@ -429,24 +441,24 @@ mod test { // (well, it would if the constant were 8000+ - I lowered it to be more // valgrind-friendly. try this at home, instead..!) static GENERATIONS: uint = 16; - fn child_no(x: uint) -> proc(): Send { - return proc() { + fn child_no(x: uint) -> Thunk { + return Thunk::new(move|| { if x < GENERATIONS { - TaskBuilder::new().spawn(child_no(x+1)); + TaskBuilder::new().spawn(move|| child_no(x+1).invoke(())); } - } + }); } - TaskBuilder::new().spawn(child_no(0)); + TaskBuilder::new().spawn(|| child_no(0).invoke(())); } #[test] fn test_simple_newsched_spawn() { - spawn(proc()()) + spawn(move|| ()) } #[test] fn test_try_panic_message_static_str() { - match try(proc() { + match try(move|| { panic!("static string"); }) { Err(e) => { @@ -460,7 +472,7 @@ mod test { #[test] fn test_try_panic_message_owned_str() { - match try(proc() { + match try(move|| { panic!("owned string".to_string()); }) { Err(e) => { @@ -474,7 +486,7 @@ mod test { #[test] fn test_try_panic_message_any() { - match try(proc() { + match try(move|| { panic!(box 413u16 as Box<Any + Send>); }) { Err(e) => { @@ -492,7 +504,7 @@ mod test { fn test_try_panic_message_unit_struct() { struct Juju; - match try(proc() { + match try(move|| { panic!(Juju) }) { Err(ref e) if e.is::<Juju>() => {} @@ -507,7 +519,7 @@ mod test { let stdout = ChanWriter::new(tx); let r = TaskBuilder::new().stdout(box stdout as Box<Writer + Send>) - .try(proc() { + .try(move|| { print!("Hello, world!"); }); assert!(r.is_ok()); @@ -527,7 +539,7 @@ fn task_abort_no_kill_runtime() { use mem; let tb = TaskBuilder::new(); - let rx = tb.try_future(proc() {}); + let rx = tb.try_future(move|| {}); mem::drop(rx); timer::sleep(Duration::milliseconds(1000)); } |
