Skip to content

Commit c047cfb

Browse files
committed
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
1 parent c337fd5 commit c047cfb

File tree

2 files changed

+41
-8
lines changed

2 files changed

+41
-8
lines changed

src/rt/rust_task.cpp

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -147,12 +147,6 @@ void task_exit(rust_closure_env *env, int rval, rust_task *task) {
147147
//env->td->free_glue(NULL, task, NULL, env->td->first_param, env);
148148
task->free(env);
149149
}
150-
task->die();
151-
task->lock.lock();
152-
task->notify_tasks_waiting_to_join();
153-
task->lock.unlock();
154-
155-
task->yield(1);
156150
}
157151

158152
extern "C" CDECL
@@ -161,8 +155,37 @@ void task_start_wrapper(spawn_args *a)
161155
rust_task *task = a->task;
162156
int rval = 42;
163157

164-
a->f(&rval, task, a->a3, a->a4);
165-
task_exit((rust_closure_env*)a->a3, rval, task);
158+
bool failed = false;
159+
try {
160+
a->f(&rval, task, a->a3, a->a4);
161+
} catch (rust_task *ex) {
162+
A(task->sched, ex == task,
163+
"Expected this task to be thrown for unwinding");
164+
failed = true;
165+
}
166+
167+
rust_closure_env* env = (rust_closure_env*)a->a3;
168+
if(env) {
169+
// free the environment.
170+
I(task->sched, 1 == env->ref_count); // the ref count better be 1
171+
//env->td->drop_glue(NULL, task, NULL, env->td->first_param, env);
172+
//env->td->free_glue(NULL, task, NULL, env->td->first_param, env);
173+
task->free(env);
174+
}
175+
176+
if (failed) {
177+
#ifndef __WIN32__
178+
task->conclude_failure();
179+
#else
180+
A(task->sched, false, "Shouldn't happen");
181+
#endif
182+
} else {
183+
task->die();
184+
task->lock.lock();
185+
task->notify_tasks_waiting_to_join();
186+
task->lock.unlock();
187+
task->yield(1);
188+
}
166189
}
167190

168191
/* We spawn a rust (fastcc) function through a CDECL function
@@ -276,6 +299,15 @@ rust_task::fail() {
276299
// See note in ::kill() regarding who should call this.
277300
DLOG(sched, task, "task %s @0x%" PRIxPTR " failing", name, this);
278301
backtrace();
302+
#ifndef __WIN32__
303+
throw this;
304+
#else
305+
conclude_failure();
306+
#endif
307+
}
308+
309+
void
310+
rust_task::conclude_failure() {
279311
die();
280312
// Unblock the task so it can unwind.
281313
unblock();

src/rt/rust_task.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ rust_task : public kernel_owned<rust_task>, rust_cond
155155

156156
// Fail self, assuming caller-on-stack is this task.
157157
void fail();
158+
void conclude_failure();
158159

159160
// Disconnect from our supervisor.
160161
void unsupervise();

0 commit comments

Comments
 (0)