summary refs log tree commit diff
path: root/src/libstd/rt
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-08-06 10:32:00 -0700
committerbors <bors@rust-lang.org>2013-08-06 10:32:00 -0700
commit72080954b9deb3a6a5f793d2fd1ef32c3d5acb5d (patch)
tree456eb7e1919d304b7630dd7d89b5bd9b98a1a1ad /src/libstd/rt
parent3dfb55ab09a8533da7c5bf559c923685d5d64dc1 (diff)
parent1f95bd768444a4a0318951c2e76f3d28bbf3763a (diff)
downloadrust-72080954b9deb3a6a5f793d2fd1ef32c3d5acb5d.tar.gz
rust-72080954b9deb3a6a5f793d2fd1ef32c3d5acb5d.zip
auto merge of #8317 : bblum/rust/fast-spawn-unlinked, r=brson
This lazily initializes the taskgroup structs for ```spawn_unlinked``` tasks. If such a task never spawns another task linked to it (or a descendant of it), its taskgroup is simply never initialized at all. Also if an unlinked task spawns another unlinked task, neither of them will need to initialize their taskgroups. This works for the main task too.

I benchmarked this with the following test case and observed a ~~21% speedup (average over 4 runs: 7.85 sec -> 6.20 sec, 2.5 GHz)~~ 11% speedup, see comment below.
```
use std::task;
use std::cell::Cell;
use std::rt::comm;

static NUM: uint = 1024*256;

fn run(f: ~fn()) {
    let mut t = task::task();
    t.unlinked();
    t.spawn(f);
}

fn main() {
    do NUM.times {
        let (p,c) = comm::oneshot();
        let c = Cell::new(c);
        do run { c.take().send(()); }
        p.recv();
    }
}
```
Diffstat (limited to 'src/libstd/rt')
-rw-r--r--src/libstd/rt/kill.rs13
1 files changed, 8 insertions, 5 deletions
diff --git a/src/libstd/rt/kill.rs b/src/libstd/rt/kill.rs
index deec8dd37a6..3372c13b877 100644
--- a/src/libstd/rt/kill.rs
+++ b/src/libstd/rt/kill.rs
@@ -193,6 +193,10 @@ impl BlockedTask {
 
     /// Create a blocked task, unless the task was already killed.
     pub fn try_block(mut task: ~Task) -> Either<~Task, BlockedTask> {
+        // NB: As an optimization, we could give a free pass to being unkillable
+        // to tasks whose taskgroups haven't been initialized yet, but that
+        // introduces complications with select() and with the test cases below,
+        // and it's not clear the uncommon performance boost is worth it.
         if task.death.unkillable > 0 {
             Right(Unkillable(task))
         } else {
@@ -205,11 +209,10 @@ impl BlockedTask {
                 let flag_arc = match task.death.spare_kill_flag.take() {
                     Some(spare_flag) => spare_flag,
                     None => {
-                        // FIXME(#7544): Uncomment this when terminate_current_task
-                        // stops being *terrible*. That's the only place that violates
-                        // the assumption of "becoming unkillable will fail if the
-                        // task was killed".
-                        // rtassert!(task.unwinder.unwinding);
+                        // A task that kills us won't have a spare kill flag to
+                        // give back to us, so we restore it ourselves here. This
+                        // situation should only arise when we're already failing.
+                        rtassert!(task.unwinder.unwinding);
                         (*task.death.kill_handle.get_ref().get()).killed.clone()
                     }
                 };