]> git.lizzy.rs Git - rust.git/commitdiff
simplify task impl
authorNiko Matsakis <niko@alum.mit.edu>
Sat, 31 Dec 2011 04:46:08 +0000 (20:46 -0800)
committerNiko Matsakis <niko@alum.mit.edu>
Sat, 7 Jan 2012 06:40:31 +0000 (22:40 -0800)
src/comp/middle/trans_closure.rs
src/libcore/task.rs
src/libstd/test.rs
src/rt/rust.cpp
src/rt/rust_builtin.cpp
src/rt/rust_task.cpp
src/rt/rust_task.h
src/rt/test/rust_test_runtime.cpp

index 4a43b2ead875b3c7286b25e28cb7b348d170507c..81cb4a7f25c13bfdd192c17015613e5ac65b7967 100644 (file)
@@ -33,7 +33,7 @@
 // struct closure_box {
 //    unsigned ref_count; // only used for sharid environments
 //    struct closure {
-//      type_desc *tydesc;         // descriptor for the env type
+//      type_desc *tydesc;         // descriptor for the "struct closure" type
 //      type_desc *bound_tdescs[]; // bound descriptors
 //      struct {
 //          upvar1_t upvar1;
index 5de9c8347fe03f52db50bcaecfc09ebe8d7a3b00..07a859ad2f3d0778fa0c016acfcd56b8314b3bf4 100644 (file)
@@ -31,6 +31,7 @@
 import option::{some, none};
 import option = option::t;
 import ptr;
+import c = ctypes;
 
 export task;
 export joinable_task;
@@ -46,7 +47,6 @@
 export tr_failure;
 export get_task;
 export spawn;
-export spawn_notify;
 export spawn_joinable;
 
 #[abi = "rust-intrinsic"]
     fn task_sleep(task: *rust_task, time_in_us: uint, &killed: bool);
 }
 
+type rust_closure = {
+    fnptr: c::intptr_t, envptr: c::intptr_t
+};
+
 #[link_name = "rustrt"]
 #[abi = "cdecl"]
 native mod rustrt {
@@ -70,8 +74,7 @@
 
     fn migrate_alloc(alloc: *u8, target: task_id);
 
-    fn start_task(id: task, closure: *u8);
-
+    fn start_task(id: task, closure: *rust_closure);
 }
 
 /* Section: Types */
 */
 type task = task_id;
 
+/*
+Function: spawn
+
+Creates and executes a new child task
+
+Sets up a new task with its own call stack and schedules it to be
+executed.  Upon execution, the closure `f()` will be invoked.
+
+Parameters:
+
+f - A function to execute in the new task
+
+Returns:
+
+A handle to the new task
+*/
+fn spawn(-f: sendfn()) -> task unsafe {
+    let closure: *rust_closure = unsafe::reinterpret_cast(ptr::addr_of(f));
+    #debug("spawn: closure={%x,%x}", (*closure).fnptr, (*closure).envptr);
+    let id = rustrt::new_task();
+    rustrt::start_task(id, closure);
+    unsafe::leak(f);
+    ret id;
+}
+
 /*
 Type: joinable_task
 
 */
 type joinable_task = (task, comm::port<task_notification>);
 
+fn spawn_joinable(-f: sendfn()) -> joinable_task {
+    resource notify_rsrc(data: (comm::chan<task_notification>,
+                                task,
+                                @mutable task_result)) {
+        let (chan, task, tr) = data;
+        let msg = exit(task, *tr);
+        comm::send(chan, msg);
+    }
+
+    let notify_port = comm::port();
+    let notify_chan = comm::chan(notify_port);
+    let g = sendfn[copy notify_chan; move f]() {
+        let this_task = rustrt::get_task_id();
+        let result = @mutable tr_failure;
+        let _rsrc = notify_rsrc((notify_chan, this_task, result));
+        f();
+        *result = tr_success; // rsrc will fire msg when fn returns
+    };
+    let task = spawn(g);
+    ret (task, notify_port);
+}
+
 /*
 Tag: task_result
 
@@ -213,130 +263,6 @@ fn join(task_port: joinable_task) -> task_result {
 */
 fn unpin() { rustrt::unpin_task(); }
 
-/*
-Function: spawn
-
-Creates and executes a new child task
-
-Sets up a new task with its own call stack and schedules it to be executed.
-Upon execution the new task will call function `f` with the provided
-argument `data`.
-
-Function `f` is a bare function, meaning it may not close over any data, as do
-shared functions (fn@) and lambda blocks. `data` must be a uniquely owned
-type; it is moved into the new task and thus can no longer be accessed
-locally.
-
-Parameters:
-
-data - A unique-type value to pass to the new task
-f - A function to execute in the new task
-
-Returns:
-
-A handle to the new task
-*/
-fn spawn<T: send>(-data: T, f: fn(T)) -> task {
-    spawn_inner(data, f, none)
-}
-
-/*
-Function: spawn_notify
-
-Create and execute a new child task, requesting notification upon its
-termination
-
-Immediately before termination, either on success or failure, the spawned
-task will send a <task_notification> message on the provided channel.
-*/
-fn spawn_notify<T: send>(-data: T, f: fn(T),
-                         notify: comm::chan<task_notification>) -> task {
-    spawn_inner(data, f, some(notify))
-}
-
-/*
-Function: spawn_joinable
-
-Create and execute a task which can later be joined with the <join> function
-
-This is a convenience wrapper around spawn_notify which, when paired
-with <join> can be easily used to spawn a task then wait for it to
-complete.
-*/
-fn spawn_joinable<T: send>(-data: T, f: fn(T)) -> joinable_task {
-    let p = comm::port::<task_notification>();
-    let id = spawn_notify(data, f, comm::chan::<task_notification>(p));
-    ret (id, p);
-}
-
-// FIXME: To transition from the unsafe spawn that spawns a shared closure to
-// the safe spawn that spawns a bare function we're going to write
-// barefunc-spawn on top of unsafe-spawn.  Sadly, bind does not work reliably
-// enough to suite our needs (#1034, probably others yet to be discovered), so
-// we're going to copy the bootstrap data into a unique pointer, cast it to an
-// unsafe pointer then wrap up the bare function and the unsafe pointer in a
-// shared closure to spawn.
-//
-// After the transition this should all be rewritten.
-
-fn spawn_inner<T: send>(-data: T, f: fn(T),
-                          notify: option<comm::chan<task_notification>>)
-    -> task unsafe {
-
-    fn wrapper<T: send>(data: *u8, f: fn(T)) unsafe {
-        let data: ~T = unsafe::reinterpret_cast(data);
-        f(*data);
-    }
-
-    let data = ~data;
-    let dataptr: *u8 = unsafe::reinterpret_cast(data);
-    unsafe::leak(data);
-    let wrapped = bind wrapper(dataptr, f);
-    ret unsafe_spawn_inner(wrapped, notify);
-}
-
-// FIXME: This is the old spawn function that spawns a shared closure.
-// It is a hack and needs to be rewritten.
-fn unsafe_spawn_inner(-thunk: fn@(),
-                      notify: option<comm::chan<task_notification>>) ->
-   task unsafe {
-    let id = rustrt::new_task();
-
-    let raw_thunk: {code: uint, env: uint} = cast(thunk);
-
-    // set up the task pointer
-    let task_ptr <- rust_task_ptr(rustrt::get_task_pointer(id));
-
-    assert (ptr::null() != (**task_ptr).stack_ptr);
-
-    // copy the thunk from our stack to the new stack
-    let sp: uint = cast((**task_ptr).stack_ptr);
-    let ptrsize = sys::size_of::<*u8>();
-    let thunkfn: *mutable uint = cast(sp - ptrsize * 2u);
-    let thunkenv: *mutable uint = cast(sp - ptrsize);
-    *thunkfn = cast(raw_thunk.code);;
-    *thunkenv = cast(raw_thunk.env);;
-    // Advance the stack pointer. No need to align because
-    // the native code will do that for us
-    (**task_ptr).stack_ptr = cast(sp - ptrsize * 2u);
-
-    // set up notifications if they are enabled.
-    alt notify {
-      some(c) {
-        (**task_ptr).notify_enabled = 1;
-        (**task_ptr).notify_chan = c;
-      }
-      none { }
-    }
-
-    // give the thunk environment's allocation to the new task
-    rustrt::migrate_alloc(cast(raw_thunk.env), id);
-    rustrt::start_task(id, cast(thunkfn));
-    // don't cleanup the thunk in this task
-    unsafe::leak(thunk);
-    ret id;
-}
-
 // Local Variables:
 // mode: rust;
 // fill-column: 78;
index 43a869f0319485eb264dbb5090b0bee56354964c..f17029d3fcd8a2949efa79d406c5d1ee0f6e3f86 100644 (file)
@@ -49,7 +49,7 @@
 // to support isolation of tests into tasks.
 type test_fn<T> = T;
 
-type default_test_fn = test_fn<fn()>;
+type default_test_fn = test_fn<sendfn()>;
 
 // The definition of a single test. A test runner will run a list of
 // these.
@@ -336,11 +336,10 @@ fn run_test<T: copy>(test: test_desc<T>,
 // We need to run our tests in another task in order to trap test failures.
 // This function only works with functions that don't contain closures.
 fn default_test_to_task(&&f: default_test_fn) -> joinable {
-    fn run_task(f: default_test_fn) {
+    ret task::spawn_joinable(sendfn[copy f]() {
         configure_test_task();
         f();
-    }
-    ret task::spawn_joinable(copy f, run_task);
+    });
 }
 
 // Call from within a test task to make sure it's set up correctly
index 74e0db312473f1fce23729efce13edef99e0a734..a3b30c26e5b128cfaecebf76a2ada664f611f0d8 100644 (file)
@@ -98,7 +98,7 @@ rust_start(uintptr_t main_fn, int argc, char **argv, void* crate_map) {
         DLOG(sched, dom, "startup: arg[%d] = '%s'", i, args->argv[i]);
     }
 
-    root_task->start(main_fn, (uintptr_t)args->args);
+    root_task->start((spawn_fn)main_fn, (uintptr_t)args->args);
     root_task->deref();
     root_task = NULL;
 
@@ -119,6 +119,5 @@ rust_start(uintptr_t main_fn, int argc, char **argv, void* crate_map) {
 // indent-tabs-mode: nil
 // c-basic-offset: 4
 // buffer-file-coding-system: utf-8-unix
-// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
 // End:
 //
index 28c819879b64e909a7cecdeb73f341ad06924139..b387078a75ab5e3829ff263e3b682f3cd87dc5fa 100644 (file)
@@ -2,6 +2,7 @@
 
 #include "rust_internal.h"
 #include "rust_scheduler.h"
+#include "rust_task.h"
 
 #if !defined(__WIN32__)
 #include <sys/time.h>
@@ -424,18 +425,11 @@ struct fn_env_pair {
     intptr_t env;
 };
 
-// FIXME This is probably not needed at all anymore. Have to rearrange some
-// argument passing to remove it.
-void rust_spawn_wrapper(void* retptr, void* envptr,
-                        void(*func)(void*, void*)) {
-    func(retptr, envptr);
-}
-
 extern "C" CDECL void
 start_task(rust_task_id id, fn_env_pair *f) {
     rust_task *task = rust_scheduler::get_task();
     rust_task *target = task->kernel->get_task_by_id(id);
-    target->start((uintptr_t)rust_spawn_wrapper, f->f, f->env);
+    target->start((spawn_fn)f->f, f->env);
     target->deref();
 }
 
@@ -578,6 +572,5 @@ port_recv(uintptr_t *dptr, rust_port *port,
 // indent-tabs-mode: nil
 // c-basic-offset: 4
 // buffer-file-coding-system: utf-8-unix
-// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
 // End:
 //
index 2bf4c42a27750984a282e305793d5b611207668b..f63e8d8d4c0178fc20edd5fd4360cfac01fc884c 100644 (file)
@@ -292,14 +292,18 @@ rust_task::~rust_task()
 
 struct spawn_args {
     rust_task *task;
-    uintptr_t a3;
-    uintptr_t a4;
-    void (*CDECL f)(int *, uintptr_t, uintptr_t);
+    uintptr_t envptr;
+    spawn_fn f;
 };
 
-struct rust_closure_env {
+struct rust_closure {
+    const type_desc *td;
+    // ... see trans_closure.rs for full description ...
+};
+
+struct rust_boxed_closure {
     intptr_t ref_count;
-    type_desc *td;
+    rust_closure closure;
 };
 
 struct cleanup_args {
@@ -315,13 +319,12 @@ cleanup_task(cleanup_args *args) {
 
     cc::do_cc(task);
 
-    rust_closure_env* env = (rust_closure_env*)a->a3;
-    if(env) {
+    rust_boxed_closure* boxed_env = (rust_boxed_closure*)a->envptr;
+    if(boxed_env) {
         // free the environment.
-        I(task->sched, 1 == env->ref_count); // the ref count better be 1
-        //env->td->drop_glue(NULL, task, NULL, env->td->first_param, env);
-        //env->td->free_glue(NULL, task, NULL, env->td->first_param, env);
-        task->free(env);
+        rust_closure *env = &boxed_env->closure;
+        env->td->drop_glue(NULL, NULL, &env->td, env);
+        env->td->free_glue(NULL, NULL, &env->td, env);
     }
 
     task->die();
@@ -347,11 +350,12 @@ extern "C" CDECL
 void task_start_wrapper(spawn_args *a)
 {
     rust_task *task = a->task;
-    int rval = 42;
 
     bool failed = false;
     try {
-        a->f(&rval, a->a3, a->a4);
+        // The first argument is the return pointer; as the task fn 
+        // must have void return type, we can safely pass 0.
+        a->f(0, a->envptr);
     } catch (rust_task *ex) {
         A(task->sched, ex == task,
           "Expected this task to be thrown for unwinding");
@@ -367,12 +371,11 @@ void task_start_wrapper(spawn_args *a)
 }
 
 void
-rust_task::start(uintptr_t spawnee_fn,
-                 uintptr_t args,
+rust_task::start(spawn_fn spawnee_fn,
                  uintptr_t env)
 {
     LOG(this, task, "starting task from fn 0x%" PRIxPTR
-        " with args 0x%" PRIxPTR, spawnee_fn, args);
+        " with env 0x%" PRIxPTR, spawnee_fn, env);
 
     I(sched, stk->data != NULL);
 
@@ -383,23 +386,14 @@ rust_task::start(uintptr_t spawnee_fn,
     spawn_args *a = (spawn_args *)sp;
 
     a->task = this;
-    a->a3 = env;
-    a->a4 = args;
-    void **f = (void **)&a->f;
-    *f = (void *)spawnee_fn;
+    a->envptr = env;
+    a->f = spawnee_fn;
 
     ctx.call((void *)task_start_wrapper, a, sp);
 
     this->start();
 }
 
-void
-rust_task::start(uintptr_t spawnee_fn,
-                 uintptr_t args)
-{
-    start(spawnee_fn, args, 0);
-}
-
 void rust_task::start()
 {
     yield_timer.reset_us(0);
index 21d20691ac61adca655655baa20260a683dd5430..2c8e9809c7abd68ec256c786e31f27392fffae53 100644 (file)
@@ -21,6 +21,8 @@ struct chan_handle {
     rust_port_id port;
 };
 
+typedef void (*CDECL spawn_fn)(uintptr_t, uintptr_t);
+
 struct rust_box;
 
 struct stk_seg {
@@ -132,10 +134,7 @@ rust_task : public kernel_owned<rust_task>, rust_cond
 
     ~rust_task();
 
-    void start(uintptr_t spawnee_fn,
-               uintptr_t args,
-               uintptr_t env);
-    void start(uintptr_t spawnee_fn,
+    void start(spawn_fn spawnee_fn,
                uintptr_t args);
     void start();
     bool running();
@@ -212,7 +211,6 @@ rust_task : public kernel_owned<rust_task>, rust_cond
 // indent-tabs-mode: nil
 // c-basic-offset: 4
 // buffer-file-coding-system: utf-8-unix
-// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
 // End:
 //
 
index 520426eb256c169f2ec6e2ef97d80fd336db498c..644a23f28b1b92b2913a7d1b2e272d42360f81b5 100644 (file)
@@ -39,7 +39,7 @@ rust_domain_test::run() {
     return true;
 }
 
-void task_entry() {
+void task_entry(uintptr_t retptr, uintptr_t env) {
     printf("task entry\n");
 }
 
@@ -47,7 +47,7 @@ void
 rust_task_test::worker::run() {
     rust_task_id root_id = kernel->create_task(NULL, "main");
     rust_task *root_task = kernel->get_task_by_id(root_id);
-    root_task->start((uintptr_t)&task_entry, (uintptr_t)NULL);
+    root_task->start(&task_entry, (uintptr_t)NULL);
     root_task->sched->start_main_loop();
 }