@@ -142,11 +142,11 @@ impl Scheduler {
142
142
local_ptr:: init_tls_key ( ) ;
143
143
144
144
// Create a task for the scheduler with an empty context.
145
- let sched_task = Task :: new_sched_task ( ) ;
145
+ let sched_task = ~ Task :: new_sched_task ( ) ;
146
146
147
147
// Now that we have an empty task struct for the scheduler
148
148
// task, put it in TLS.
149
- Local :: put:: ( ~ sched_task) ;
149
+ Local :: put :: ( sched_task) ;
150
150
151
151
// Now, as far as all the scheduler state is concerned, we are
152
152
// inside the "scheduler" context. So we can act like the
@@ -165,8 +165,6 @@ impl Scheduler {
165
165
// cleaning up the memory it uses. As we didn't actually call
166
166
// task.run() on the scheduler task we never get through all
167
167
// the cleanup code it runs.
168
-
169
- rtdebug ! ( "post sched.run(), cleaning up scheduler task" ) ;
170
168
let mut stask = Local :: take :: < Task > ( ) ;
171
169
stask. destroyed = true ;
172
170
}
@@ -224,6 +222,8 @@ impl Scheduler {
224
222
// 2) A shutdown is also easy, shutdown.
225
223
// 3) A pinned task - we resume immediately and do not return
226
224
// here.
225
+ // 4) A message from another scheduler with a non-homed task
226
+ // to run here.
227
227
228
228
let result = sched. interpret_message_queue ( ) ;
229
229
let sched = match result {
@@ -236,6 +236,8 @@ impl Scheduler {
236
236
}
237
237
} ;
238
238
239
+ // Second activity is to try resuming a task from the queue.
240
+
239
241
let result = sched. resume_task_from_queue ( ) ;
240
242
let mut sched = match result {
241
243
Some ( sched) => {
@@ -333,8 +335,7 @@ impl Scheduler {
333
335
return None ;
334
336
}
335
337
Some ( TaskFromFriend ( task) ) => {
336
- this. schedule_task_sched_context ( task) ;
337
- return None ;
338
+ return this. sched_schedule_task ( task) ;
338
339
}
339
340
Some ( Wake ) => {
340
341
this. sleepy = false ;
@@ -442,8 +443,6 @@ impl Scheduler {
442
443
}
443
444
}
444
445
445
- // * Task-context operations
446
-
447
446
/// Called by a running task to end execution, after which it will
448
447
/// be recycled by the scheduler for reuse in a new task.
449
448
pub fn terminate_current_task ( ~self ) {
@@ -457,10 +456,17 @@ impl Scheduler {
457
456
}
458
457
}
459
458
460
- // If a scheduling action is performed, return None. If not,
461
- // return Some(sched).
459
+ // Scheduling a task requires a few checks to make sure the task
460
+ // ends up in the appropriate location. The run_anything flag on
461
+ // the scheduler and the home on the task need to be checked. This
462
+ // helper performs that check. It takes a function that specifies
463
+ // how to queue the the provided task if that is the correct
464
+ // action. This is a "core" function that requires handling the
465
+ // returned Option correctly.
462
466
463
- pub fn schedule_task ( ~self , task : ~Task ) -> Option < ~Scheduler > {
467
+ pub fn schedule_task ( ~self , task : ~Task ,
468
+ schedule_fn : ~fn ( sched : ~Scheduler , task : ~Task ) )
469
+ -> Option < ~Scheduler > {
464
470
465
471
// is the task home?
466
472
let is_home = task. is_home_no_tls ( & self ) ;
@@ -474,9 +480,7 @@ impl Scheduler {
474
480
// here we know we are home, execute now OR we know we
475
481
// aren't homed, and that this sched doesn't care
476
482
rtdebug ! ( "task: %u is on ok sched, executing" , to_uint( task) ) ;
477
- do this. switch_running_tasks_and_then ( task) |sched, last_task| {
478
- sched. enqueue_blocked_task ( last_task) ;
479
- }
483
+ schedule_fn ( this, task) ;
480
484
return None ;
481
485
} else if !homed && !this. run_anything {
482
486
// the task isn't homed, but it can't be run here
@@ -489,35 +493,30 @@ impl Scheduler {
489
493
}
490
494
}
491
495
492
- // BAD BAD BAD BAD BAD
493
- // Do something instead of just copy-pasting this.
494
- pub fn schedule_task_sched_context ( ~self , task : ~Task ) -> Option < ~Scheduler > {
495
-
496
- // is the task home?
497
- let is_home = task. is_home_no_tls ( & self ) ;
498
-
499
- // does the task have a home?
500
- let homed = task. homed ( ) ;
501
-
502
- let mut this = self ;
503
-
504
- if is_home || ( !homed && this. run_anything ) {
505
- // here we know we are home, execute now OR we know we
506
- // aren't homed, and that this sched doesn't care
507
- rtdebug ! ( "task: %u is on ok sched, executing" , to_uint( task) ) ;
508
- this. resume_task_immediately ( task) ;
509
- return None ;
510
- } else if !homed && !this. run_anything {
511
- // the task isn't homed, but it can't be run here
512
- this. enqueue_task ( task) ;
513
- return Some ( this) ;
514
- } else {
515
- // task isn't home, so don't run it here, send it home
516
- Scheduler :: send_task_home ( task) ;
517
- return Some ( this) ;
496
+ // There are two contexts in which schedule_task can be called:
497
+ // inside the scheduler, and inside a task. These contexts handle
498
+ // executing the task slightly differently. In the scheduler
499
+ // context case we want to receive the scheduler as an input, and
500
+ // manually deal with the option. In the task context case we want
501
+ // to use TLS to find the scheduler, and deal with the option
502
+ // inside the helper.
503
+
504
+ pub fn sched_schedule_task ( ~self , task : ~Task ) -> Option < ~Scheduler > {
505
+ do self . schedule_task ( task) |sched, next_task| {
506
+ sched. resume_task_immediately ( next_task) ;
518
507
}
519
508
}
520
509
510
+ // Task context case - use TLS.
511
+ pub fn run_task ( task : ~Task ) {
512
+ let sched = Local :: take :: < Scheduler > ( ) ;
513
+ let opt = do sched. schedule_task ( task) |sched, next_task| {
514
+ do sched. switch_running_tasks_and_then ( next_task) |sched, last_task| {
515
+ sched. enqueue_blocked_task ( last_task) ;
516
+ }
517
+ } ;
518
+ opt. map_consume ( Local :: put) ;
519
+ }
521
520
522
521
// The primary function for changing contexts. In the current
523
522
// design the scheduler is just a slightly modified GreenTask, so
@@ -586,7 +585,7 @@ impl Scheduler {
586
585
Context :: swap ( current_task_context, next_task_context) ;
587
586
}
588
587
589
- // When the context swaps back to the scheduler we immediately
588
+ // When the context swaps back to this task we immediately
590
589
// run the cleanup job, as expected by the previously called
591
590
// swap_contexts function.
592
591
unsafe {
@@ -599,15 +598,8 @@ impl Scheduler {
599
598
}
600
599
}
601
600
602
- // There are a variety of "obvious" functions to be passed to
603
- // change_task_context, so we can make a few "named cases".
604
-
605
- // Enqueue the old task on the current scheduler.
606
- pub fn enqueue_old ( sched : & mut Scheduler , task : ~Task ) {
607
- sched. enqueue_task ( task) ;
608
- }
609
-
610
- // Sometimes we just want the old API though.
601
+ // Old API for task manipulation implemented over the new core
602
+ // function.
611
603
612
604
pub fn resume_task_immediately ( ~self , task : ~Task ) {
613
605
do self . change_task_context ( task) |sched, stask| {
@@ -668,13 +660,6 @@ impl Scheduler {
668
660
} ;
669
661
}
670
662
671
- // A helper that looks up the scheduler and runs a task. If it can
672
- // be run now it is run now.
673
- pub fn run_task ( new_task : ~Task ) {
674
- let sched = Local :: take :: < Scheduler > ( ) ;
675
- sched. schedule_task ( new_task) . map_consume ( Local :: put) ;
676
- }
677
-
678
663
// Returns a mutable reference to both contexts involved in this
679
664
// swap. This is unsafe - we are getting mutable internal
680
665
// references to keep even when we don't own the tasks. It looks
@@ -692,8 +677,6 @@ impl Scheduler {
692
677
}
693
678
}
694
679
695
- // * Other stuff
696
-
697
680
pub fn enqueue_cleanup_job ( & mut self , job : CleanupJob ) {
698
681
self . cleanup_job = Some ( job) ;
699
682
}
@@ -1004,22 +987,22 @@ mod test {
1004
987
let port = Cell :: new ( port) ;
1005
988
let chan = Cell :: new ( chan) ;
1006
989
1007
- let _thread_one = do Thread :: start {
990
+ let thread_one = do Thread :: start {
1008
991
let chan = Cell :: new ( chan. take ( ) ) ;
1009
992
do run_in_newsched_task_core {
1010
993
chan. take ( ) . send ( ( ) ) ;
1011
994
}
1012
995
} ;
1013
996
1014
- let _thread_two = do Thread :: start {
997
+ let thread_two = do Thread :: start {
1015
998
let port = Cell :: new ( port. take ( ) ) ;
1016
999
do run_in_newsched_task_core {
1017
1000
port. take ( ) . recv ( ) ;
1018
1001
}
1019
1002
} ;
1020
1003
1021
- thread1 . join ( ) ;
1022
- thread2 . join ( ) ;
1004
+ thread_two . join ( ) ;
1005
+ thread_one . join ( ) ;
1023
1006
}
1024
1007
}
1025
1008
0 commit comments