diff options
| author | Alex Crichton <alex@alexcrichton.com> | 2014-07-24 07:32:14 -0700 |
|---|---|---|
| committer | Alex Crichton <alex@alexcrichton.com> | 2014-07-30 08:33:53 -0700 |
| commit | 8643a0d61359dfb1ebe38d4aae615e7c836b3d18 (patch) | |
| tree | cc656602f919f34db3faaa7f2d72e58b94250499 /src/libgreen | |
| parent | 355c798ac3eba15bb2d53a6c553c6149391f9615 (diff) | |
| download | rust-8643a0d61359dfb1ebe38d4aae615e7c836b3d18.tar.gz rust-8643a0d61359dfb1ebe38d4aae615e7c836b3d18.zip | |
green: Prevent runtime corruption on spawn failure
Like with libnative, when a green task failed to spawn it would leave the world in a corrupt state where the local scheduler had been dropped as well as the local task. Also like libnative, this patch sets up a "bomb" which when it goes off will restore the state of the world.
Diffstat (limited to 'src/libgreen')
| -rw-r--r-- | src/libgreen/task.rs | 21 |
1 files changed, 18 insertions, 3 deletions
diff --git a/src/libgreen/task.rs b/src/libgreen/task.rs index 3d3b4133840..12d7b755697 100644 --- a/src/libgreen/task.rs +++ b/src/libgreen/task.rs @@ -442,15 +442,30 @@ impl Runtime for GreenTask { f: proc():Send) { self.put_task(cur_task); + // First, set up a bomb which when it goes off will restore the local + // task unless its disarmed. This will allow us to gracefully fail from + // inside of `configure` which allocates a new task. + struct Bomb { inner: Option<Box<GreenTask>> } + impl Drop for Bomb { + fn drop(&mut self) { + let _ = self.inner.take().map(|task| task.put()); + } + } + let mut bomb = Bomb { inner: Some(self) }; + // Spawns a task into the current scheduler. We allocate the new task's // stack from the scheduler's stack pool, and then configure it // accordingly to `opts`. Afterwards we bootstrap it immediately by // switching to it. // // Upon returning, our task is back in TLS and we're good to return. - let mut sched = self.sched.take_unwrap(); - let sibling = GreenTask::configure(&mut sched.stack_pool, opts, f); - sched.run_task(self, sibling) + let sibling = { + let sched = bomb.inner.get_mut_ref().sched.get_mut_ref(); + GreenTask::configure(&mut sched.stack_pool, opts, f) + }; + let mut me = bomb.inner.take().unwrap(); + let sched = me.sched.take().unwrap(); + sched.run_task(me, sibling) } // Local I/O is provided by the scheduler's event loop |
