about summary refs log tree commit diff
path: root/src/rt/rust_task.cpp
diff options
context:
space:
mode:
authorBrian Anderson <banderson@mozilla.com>2011-09-06 18:31:41 -0700
committerBrian Anderson <banderson@mozilla.com>2011-09-07 10:32:58 -0700
commitc047cfb710f3ea161b71cc4eb830275ec2c47eea (patch)
tree5c1c47cae1a629a8578dcab2e180e4d85629b45a /src/rt/rust_task.cpp
parentc337fd5467f52b5f79f653b7e71f945cc8cf09d1 (diff)
downloadrust-c047cfb710f3ea161b71cc4eb830275ec2c47eea.tar.gz
rust-c047cfb710f3ea161b71cc4eb830275ec2c47eea.zip
Unwind the stack on task failure
When a task fails, we will throw an exception, then catch it at the bottom of
the stack.

On Windows we don't do this yet because the exception doesn't propagate
correctly.

No cleanups yet.

Issue #236
Diffstat (limited to 'src/rt/rust_task.cpp')
-rw-r--r--src/rt/rust_task.cpp48
1 files changed, 40 insertions, 8 deletions
diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp
index 31a3324f1d4..57b5d16e427 100644
--- a/src/rt/rust_task.cpp
+++ b/src/rt/rust_task.cpp
@@ -147,12 +147,6 @@ void task_exit(rust_closure_env *env, int rval, rust_task *task) {
         //env->td->free_glue(NULL, task, NULL, env->td->first_param, env);
         task->free(env);
     }
-    task->die();
-    task->lock.lock();
-    task->notify_tasks_waiting_to_join();
-    task->lock.unlock();
-
-    task->yield(1);
 }
 
 extern "C" CDECL
@@ -161,8 +155,37 @@ void task_start_wrapper(spawn_args *a)
     rust_task *task = a->task;
     int rval = 42;
 
-    a->f(&rval, task, a->a3, a->a4);
-    task_exit((rust_closure_env*)a->a3, rval, task);
+    bool failed = false;
+    try {
+        a->f(&rval, task, a->a3, a->a4);
+    } catch (rust_task *ex) {
+        A(task->sched, ex == task,
+          "Expected this task to be thrown for unwinding");
+        failed = true;
+    }
+
+    rust_closure_env* env = (rust_closure_env*)a->a3;
+    if(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);
+    }
+
+    if (failed) {
+#ifndef __WIN32__
+        task->conclude_failure();
+#else
+        A(task->sched, false, "Shouldn't happen");
+#endif
+    } else {
+        task->die();
+        task->lock.lock();
+        task->notify_tasks_waiting_to_join();
+        task->lock.unlock();
+        task->yield(1);
+    }
 }
 
 /* We spawn a rust (fastcc) function through a CDECL function
@@ -276,6 +299,15 @@ rust_task::fail() {
     // See note in ::kill() regarding who should call this.
     DLOG(sched, task, "task %s @0x%" PRIxPTR " failing", name, this);
     backtrace();
+#ifndef __WIN32__
+    throw this;
+#else
+    conclude_failure();
+#endif
+}
+
+void
+rust_task::conclude_failure() {
     die();
     // Unblock the task so it can unwind.
     unblock();