@@ -78,13 +78,13 @@ use cast::transmute;
7878use cast;
7979use cell:: Cell ;
8080use container:: MutableMap ;
81- use comm:: { Chan , GenericChan } ;
81+ use comm:: { Chan , GenericChan , oneshot } ;
8282use hashmap:: { HashSet , HashSetConsumeIterator } ;
8383use local_data;
8484use task:: local_data_priv:: { local_get, local_set, OldHandle } ;
8585use task:: rt:: rust_task;
8686use task:: rt;
87- use task:: { Failure } ;
87+ use task:: { Failure , SingleThreaded } ;
8888use task:: { Success , TaskOpts , TaskResult } ;
8989use task:: unkillable;
9090use to_bytes:: IterBytes ;
@@ -93,9 +93,11 @@ use util;
9393use unstable:: sync:: Exclusive ;
9494use rt:: { OldTaskContext , TaskContext , SchedulerContext , GlobalContext , context} ;
9595use rt:: local:: Local ;
96- use rt:: task:: Task ;
96+ use rt:: task:: { Task , Sched } ;
9797use rt:: kill:: KillHandle ;
9898use rt:: sched:: Scheduler ;
99+ use rt:: uv:: uvio:: UvEventLoop ;
100+ use rt:: thread:: Thread ;
99101
100102#[ cfg( test) ] use task:: default_task_opts;
101103#[ cfg( test) ] use comm;
@@ -694,11 +696,81 @@ fn spawn_raw_newsched(mut opts: TaskOpts, f: ~fn()) {
694696 }
695697 } ;
696698
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+ }
702774 } ;
703775
704776 if opts. notify_chan . is_some ( ) {
0 commit comments