about summary refs log tree commit diff
path: root/src/libstd/rt/task.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstd/rt/task.rs')
-rw-r--r--src/libstd/rt/task.rs215
1 files changed, 161 insertions, 54 deletions
diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs
index c1b799796d1..bc603bede97 100644
--- a/src/libstd/rt/task.rs
+++ b/src/libstd/rt/task.rs
@@ -30,21 +30,34 @@ use rt::context::Context;
 use task::spawn::Taskgroup;
 use cell::Cell;
 
+// The Task struct represents all state associated with a rust
+// task. There are at this point two primary "subtypes" of task,
+// however instead of using a subtype we just have a "task_type" field
+// in the struct. This contains a pointer to another struct that holds
+// the type-specific state.
+
 pub struct Task {
     heap: LocalHeap,
     gc: GarbageCollector,
     storage: LocalStorage,
     logger: StdErrLogger,
     unwinder: Unwinder,
-    home: Option<SchedHome>,
     taskgroup: Option<Taskgroup>,
     death: Death,
     destroyed: bool,
     coroutine: Option<~Coroutine>,
     // FIXME(#6874/#7599) use StringRef to save on allocations
     name: Option<~str>,
+    sched: Option<~Scheduler>,
+    task_type: TaskType
+}
+
+pub enum TaskType {
+    GreenTask(Option<~SchedHome>),
+    SchedTask
 }
 
+/// A coroutine is nothing more than a (register context, stack) pair.
 pub struct Coroutine {
     /// The segment of stack on which the task is currently running or
     /// if the task is blocked, on which the task will resume
@@ -54,6 +67,7 @@ pub struct Coroutine {
     saved_context: Context
 }
 
+/// Some tasks have a deciated home scheduler that they must run on.
 pub enum SchedHome {
     AnySched,
     Sched(SchedHandle)
@@ -68,6 +82,58 @@ pub struct Unwinder {
 
 impl Task {
 
+    // A helper to build a new task using the dynamically found
+    // scheduler and task. Only works in GreenTask context.
+    pub fn build_homed_child(f: ~fn(), home: SchedHome) -> ~Task {
+        let f = Cell::new(f);
+        let home = Cell::new(home);
+        do Local::borrow::<Task, ~Task> |running_task| {
+            let mut sched = running_task.sched.take_unwrap();
+            let new_task = ~running_task.new_child_homed(&mut sched.stack_pool,
+                                                         home.take(),
+                                                         f.take());
+            running_task.sched = Some(sched);
+            new_task
+        }
+    }
+
+    pub fn build_child(f: ~fn()) -> ~Task {
+        Task::build_homed_child(f, AnySched)
+    }
+
+    pub fn build_homed_root(f: ~fn(), home: SchedHome) -> ~Task {
+        let f = Cell::new(f);
+        let home = Cell::new(home);
+        do Local::borrow::<Task, ~Task> |running_task| {
+            let mut sched = running_task.sched.take_unwrap();
+            let new_task = ~Task::new_root_homed(&mut sched.stack_pool,
+                                                    home.take(),
+                                                    f.take());
+            running_task.sched = Some(sched);
+            new_task
+        }
+    }
+
+    pub fn build_root(f: ~fn()) -> ~Task {
+        Task::build_homed_root(f, AnySched)
+    }
+
+    pub fn new_sched_task() -> Task {
+        Task {
+            heap: LocalHeap::new(),
+            gc: GarbageCollector,
+            storage: LocalStorage(ptr::null(), None),
+            logger: StdErrLogger,
+            unwinder: Unwinder { unwinding: false },
+            taskgroup: None,
+            death: Death::new(),
+            destroyed: false,
+            coroutine: Some(~Coroutine::empty()),
+            sched: None,
+            task_type: SchedTask
+        }
+    }
+
     pub fn new_root(stack_pool: &mut StackPool,
                     start: ~fn()) -> Task {
         Task::new_root_homed(stack_pool, AnySched, start)
@@ -88,12 +154,13 @@ impl Task {
             storage: LocalStorage(ptr::null(), None),
             logger: StdErrLogger,
             unwinder: Unwinder { unwinding: false },
-            home: Some(home),
             taskgroup: None,
             death: Death::new(),
             destroyed: false,
             coroutine: Some(~Coroutine::new(stack_pool, start)),
             name: None,
+            sched: None,
+            task_type: GreenTask(Some(~home))
         }
     }
 
@@ -106,7 +173,6 @@ impl Task {
             gc: GarbageCollector,
             storage: LocalStorage(ptr::null(), None),
             logger: StdErrLogger,
-            home: Some(home),
             unwinder: Unwinder { unwinding: false },
             taskgroup: None,
             // FIXME(#7544) make watching optional
@@ -114,19 +180,35 @@ impl Task {
             destroyed: false,
             coroutine: Some(~Coroutine::new(stack_pool, start)),
             name: None,
+            sched: None,
+            task_type: GreenTask(Some(~home))
         }
     }
 
     pub fn give_home(&mut self, new_home: SchedHome) {
-        self.home = Some(new_home);
+        match self.task_type {
+            GreenTask(ref mut home) => {
+                *home = Some(~new_home);
+            }
+            SchedTask => {
+                rtabort!("type error: used SchedTask as GreenTask");
+            }
+        }
     }
 
-    pub fn run(&mut self, f: &fn()) {
-        // This is just an assertion that `run` was called unsafely
-        // and this instance of Task is still accessible.
-        do Local::borrow::<Task, ()> |task| {
-            assert!(borrow::ref_eq(task, self));
+    pub fn take_unwrap_home(&mut self) -> SchedHome {
+        match self.task_type {
+            GreenTask(ref mut home) => {
+                let out = home.take_unwrap();
+                return *out;
+            }
+            SchedTask => {
+                rtabort!("type error: used SchedTask as GreenTask");
+            }
         }
+    }
+
+    pub fn run(&mut self, f: &fn()) {
 
         self.unwinder.try(f);
         { let _ = self.taskgroup.take(); }
@@ -141,6 +223,8 @@ impl Task {
     /// thread-local-storage.
     fn destroy(&mut self) {
 
+        rtdebug!("DESTROYING TASK: %u", borrow::to_uint(self));
+
         do Local::borrow::<Task, ()> |task| {
             assert!(borrow::ref_eq(task, self));
         }
@@ -158,63 +242,68 @@ impl Task {
         self.destroyed = true;
     }
 
-    /// Check if *task* is currently home.
-    pub fn is_home(&self) -> bool {
-        do Local::borrow::<Scheduler,bool> |sched| {
-            match self.home {
-                Some(AnySched) => { false }
-                Some(Sched(SchedHandle { sched_id: ref id, _ })) => {
-                    *id == sched.sched_id()
-                }
-                None => { rtabort!("task home of None") }
-            }
-        }
-    }
+    // New utility functions for homes.
 
     pub fn is_home_no_tls(&self, sched: &~Scheduler) -> bool {
-        match self.home {
-            Some(AnySched) => { false }
-            Some(Sched(SchedHandle { sched_id: ref id, _ })) => {
+        match self.task_type {
+            GreenTask(Some(~AnySched)) => { false }
+            GreenTask(Some(~Sched(SchedHandle { sched_id: ref id, _}))) => {
                 *id == sched.sched_id()
             }
-            None => {rtabort!("task home of None") }
-        }
-    }
-
-    pub fn is_home_using_id(sched_id: uint) -> bool {
-        do Local::borrow::<Task,bool> |task| {
-            match task.home {
-                Some(Sched(SchedHandle { sched_id: ref id, _ })) => {
-                    *id == sched_id
-                }
-                Some(AnySched) => { false }
-                None => { rtabort!("task home of None") }
+            GreenTask(None) => {
+                rtabort!("task without home");
+            }
+            SchedTask => {
+                // Awe yea
+                rtabort!("type error: expected: GreenTask, found: SchedTask");
             }
         }
     }
 
-    /// Check if this *task* has a home.
     pub fn homed(&self) -> bool {
-        match self.home {
-            Some(AnySched) => { false }
-            Some(Sched(_)) => { true }
-            None => {
-                rtabort!("task home of None")
+        match self.task_type {
+            GreenTask(Some(~AnySched)) => { false }
+            GreenTask(Some(~Sched(SchedHandle { _ }))) => { true }
+            GreenTask(None) => {
+                rtabort!("task without home");
+            }
+            SchedTask => {
+                rtabort!("type error: expected: GreenTask, found: SchedTask");
             }
         }
     }
 
-    /// On a special scheduler?
-    pub fn on_special() -> bool {
-        do Local::borrow::<Scheduler,bool> |sched| {
-            !sched.run_anything
+    // Grab both the scheduler and the task from TLS and check if the
+    // task is executing on an appropriate scheduler.
+    pub fn on_appropriate_sched() -> bool {
+        do Local::borrow::<Task,bool> |task| {
+            let sched_id = task.sched.get_ref().sched_id();
+            let sched_run_anything = task.sched.get_ref().run_anything;
+            match task.task_type {
+                GreenTask(Some(~AnySched)) => {
+                    rtdebug!("anysched task in sched check ****");
+                    sched_run_anything
+                }
+                GreenTask(Some(~Sched(SchedHandle { sched_id: ref id, _ }))) => {
+                    rtdebug!("homed task in sched check ****");
+                    *id == sched_id
+                }
+                GreenTask(None) => {
+                    rtabort!("task without home");
+                }
+                SchedTask => {
+                    rtabort!("type error: expected: GreenTask, found: SchedTask");
+                }
+            }
         }
     }
-
 }
 
 impl Drop for Task {
-    fn drop(&self) { assert!(self.destroyed) }
+    fn drop(&self) {
+        rtdebug!("called drop for a task");
+        assert!(self.destroyed)
+    }
 }
 
 // Coroutines represent nothing more than a context and a stack
@@ -234,19 +323,33 @@ impl Coroutine {
         }
     }
 
+    pub fn empty() -> Coroutine {
+        Coroutine {
+            current_stack_segment: StackSegment::new(0),
+            saved_context: Context::empty()
+        }
+    }
+
     fn build_start_wrapper(start: ~fn()) -> ~fn() {
         let start_cell = Cell::new(start);
         let wrapper: ~fn() = || {
             // First code after swap to this new context. Run our
             // cleanup job.
             unsafe {
-                let sched = Local::unsafe_borrow::<Scheduler>();
-                (*sched).run_cleanup_job();
 
-                let sched = Local::unsafe_borrow::<Scheduler>();
-                let task = (*sched).current_task.get_mut_ref();
+                // Again - might work while safe, or it might not.
+                do Local::borrow::<Scheduler,()> |sched| {
+                    (sched).run_cleanup_job();
+                }
+
+                // To call the run method on a task we need a direct
+                // reference to it. The task is in TLS, so we can
+                // simply unsafe_borrow it to get this reference. We
+                // need to still have the task in TLS though, so we
+                // need to unsafe_borrow.
+                let task = Local::unsafe_borrow::<Task>();
 
-                do task.run {
+                do (*task).run {
                     // N.B. Removing `start` from the start wrapper
                     // closure by emptying a cell is critical for
                     // correctness. The ~Task pointer, and in turn the
@@ -262,8 +365,11 @@ impl Coroutine {
                 };
             }
 
+            // We remove the sched from the Task in TLS right now.
             let sched = Local::take::<Scheduler>();
-            sched.terminate_current_task();
+            // ... allowing us to give it away when performing a
+            // scheduling operation.
+            sched.terminate_current_task()
         };
         return wrapper;
     }
@@ -465,3 +571,4 @@ mod test {
         }
     }
 }
+