@@ -78,13 +78,13 @@ use cast::transmute;
78
78
use cast;
79
79
use cell:: Cell ;
80
80
use container:: MutableMap ;
81
- use comm:: { Chan , GenericChan } ;
81
+ use comm:: { Chan , GenericChan , oneshot } ;
82
82
use hashmap:: { HashSet , HashSetConsumeIterator } ;
83
83
use local_data;
84
84
use task:: local_data_priv:: { local_get, local_set, OldHandle } ;
85
85
use task:: rt:: rust_task;
86
86
use task:: rt;
87
- use task:: { Failure } ;
87
+ use task:: { Failure , SingleThreaded } ;
88
88
use task:: { Success , TaskOpts , TaskResult } ;
89
89
use task:: unkillable;
90
90
use to_bytes:: IterBytes ;
@@ -93,9 +93,11 @@ use util;
93
93
use unstable:: sync:: Exclusive ;
94
94
use rt:: { OldTaskContext , TaskContext , SchedulerContext , GlobalContext , context} ;
95
95
use rt:: local:: Local ;
96
- use rt:: task:: Task ;
96
+ use rt:: task:: { Task , Sched } ;
97
97
use rt:: kill:: KillHandle ;
98
98
use rt:: sched:: Scheduler ;
99
+ use rt:: uv:: uvio:: UvEventLoop ;
100
+ use rt:: thread:: Thread ;
99
101
100
102
#[ cfg( test) ] use task:: default_task_opts;
101
103
#[ cfg( test) ] use comm;
@@ -694,11 +696,81 @@ fn spawn_raw_newsched(mut opts: TaskOpts, f: ~fn()) {
694
696
}
695
697
} ;
696
698
697
- let mut task = if opts. watched {
698
- Task :: build_child ( child_wrapper)
699
- } else {
700
- // An unwatched task is a new root in the exit-code propagation tree
701
- Task :: build_root ( child_wrapper)
699
+ let mut task = unsafe {
700
+ if opts. sched . mode != SingleThreaded {
701
+ if opts. watched {
702
+ Task :: build_child ( child_wrapper)
703
+ } else {
704
+ Task :: build_root ( child_wrapper)
705
+ }
706
+ } else {
707
+ // Creating a 1:1 task:thread ...
708
+ let sched = Local :: unsafe_borrow :: < Scheduler > ( ) ;
709
+ let sched_handle = ( * sched) . make_handle ( ) ;
710
+
711
+ // Create a new scheduler to hold the new task
712
+ let new_loop = ~UvEventLoop :: new ( ) ;
713
+ let mut new_sched = ~Scheduler :: new_special ( new_loop,
714
+ ( * sched) . work_queue . clone ( ) ,
715
+ ( * sched) . sleeper_list . clone ( ) ,
716
+ false ,
717
+ Some ( sched_handle) ) ;
718
+ let mut new_sched_handle = new_sched. make_handle ( ) ;
719
+
720
+ // Allow the scheduler to exit when the pinned task exits
721
+ new_sched_handle. send ( Shutdown ) ;
722
+
723
+ // Pin the new task to the new scheduler
724
+ let new_task = if opts. watched {
725
+ Task :: build_homed_child ( child_wrapper, Sched ( new_sched_handle) )
726
+ } else {
727
+ Task :: build_homed_root ( child_wrapper, Sched ( new_sched_handle) )
728
+ } ;
729
+
730
+ // Create a task that will later be used to join with the new scheduler
731
+ // thread when it is ready to terminate
732
+ let ( thread_port, thread_chan) = oneshot ( ) ;
733
+ let thread_port_cell = Cell :: new ( thread_port) ;
734
+ let join_task = do Task :: build_child ( ) {
735
+ rtdebug ! ( "running join task" ) ;
736
+ let thread_port = thread_port_cell. take ( ) ;
737
+ let thread: Thread = thread_port. recv ( ) ;
738
+ thread. join ( ) ;
739
+ } ;
740
+
741
+ // Put the scheduler into another thread
742
+ let new_sched_cell = Cell :: new ( new_sched) ;
743
+ let orig_sched_handle_cell = Cell :: new ( ( * sched) . make_handle ( ) ) ;
744
+ let join_task_cell = Cell :: new ( join_task) ;
745
+
746
+ let thread = do Thread :: start {
747
+ let mut new_sched = new_sched_cell. take ( ) ;
748
+ let mut orig_sched_handle = orig_sched_handle_cell. take ( ) ;
749
+ let join_task = join_task_cell. take ( ) ;
750
+
751
+ let bootstrap_task = ~do Task :: new_root ( & mut new_sched. stack_pool ) || {
752
+ rtdebug ! ( "boostraping a 1:1 scheduler" ) ;
753
+ } ;
754
+ new_sched. bootstrap ( bootstrap_task) ;
755
+
756
+ rtdebug ! ( "enqueing join_task" ) ;
757
+ // Now tell the original scheduler to join with this thread
758
+ // by scheduling a thread-joining task on the original scheduler
759
+ orig_sched_handle. send ( TaskFromFriend ( join_task) ) ;
760
+
761
+ // NB: We can't simply send a message from here to another task
762
+ // because this code isn't running in a task and message passing doesn't
763
+ // work outside of tasks. Hence we're sending a scheduler message
764
+ // to execute a new task directly to a scheduler.
765
+ } ;
766
+
767
+ // Give the thread handle to the join task
768
+ thread_chan. send ( thread) ;
769
+
770
+ // When this task is enqueued on the current scheduler it will then get
771
+ // forwarded to the scheduler to which it is pinned
772
+ new_task
773
+ }
702
774
} ;
703
775
704
776
if opts. notify_chan . is_some ( ) {
0 commit comments