@@ -26,7 +26,7 @@ use rt::local::Local;
26
26
use rt:: rtio:: { RemoteCallback , PausibleIdleCallback } ;
27
27
use borrow:: { to_uint} ;
28
28
use cell:: Cell ;
29
- use rand:: { XorShiftRng , Rng , Rand } ;
29
+ use rand:: { XorShiftRng , Rng } ;
30
30
use iter:: range;
31
31
use vec:: { OwnedVector } ;
32
32
@@ -78,14 +78,7 @@ pub struct Scheduler {
78
78
/// A fast XorShift rng for scheduler use
79
79
rng : XorShiftRng ,
80
80
/// A toggleable idle callback
81
- idle_callback : Option < ~PausibleIdleCallback > ,
82
- /// A countdown that starts at a random value and is decremented
83
- /// every time a yield check is performed. When it hits 0 a task
84
- /// will yield.
85
- yield_check_count : uint ,
86
- /// A flag to tell the scheduler loop it needs to do some stealing
87
- /// in order to introduce randomness as part of a yield
88
- steal_for_yield : bool
81
+ idle_callback : Option < ~PausibleIdleCallback >
89
82
}
90
83
91
84
/// An indication of how hard to work on a given operation, the difference
@@ -96,13 +89,6 @@ enum EffortLevel {
96
89
GiveItYourBest
97
90
}
98
91
99
- static MAX_YIELD_CHECKS : uint = 200 ;
100
-
101
- fn reset_yield_check ( rng : & mut XorShiftRng ) -> uint {
102
- let r: uint = Rand :: rand ( rng) ;
103
- r % MAX_YIELD_CHECKS + 1
104
- }
105
-
106
92
impl Scheduler {
107
93
108
94
// * Initialization Functions
@@ -127,7 +113,7 @@ impl Scheduler {
127
113
friend : Option < SchedHandle > )
128
114
-> Scheduler {
129
115
130
- let mut sched = Scheduler {
116
+ Scheduler {
131
117
sleeper_list : sleeper_list,
132
118
message_queue : MessageQueue :: new ( ) ,
133
119
sleepy : false ,
@@ -141,14 +127,8 @@ impl Scheduler {
141
127
run_anything : run_anything,
142
128
friend_handle : friend,
143
129
rng : XorShiftRng :: new ( ) ,
144
- idle_callback : None ,
145
- yield_check_count : 0 ,
146
- steal_for_yield : false
147
- } ;
148
-
149
- sched. yield_check_count = reset_yield_check ( & mut sched. rng ) ;
150
-
151
- return sched;
130
+ idle_callback : None
131
+ }
152
132
}
153
133
154
134
// XXX: This may eventually need to be refactored so that
@@ -327,7 +307,8 @@ impl Scheduler {
327
307
}
328
308
Some ( TaskFromFriend ( task) ) => {
329
309
rtdebug ! ( "got a task from a friend. lovely!" ) ;
330
- this. process_task ( task, Scheduler :: resume_task_immediately_cl) ;
310
+ this. process_task ( task,
311
+ Scheduler :: resume_task_immediately_cl) . map_move ( Local :: put) ;
331
312
return None ;
332
313
}
333
314
Some ( Wake ) => {
@@ -371,8 +352,8 @@ impl Scheduler {
371
352
match this. find_work ( ) {
372
353
Some ( task) => {
373
354
rtdebug ! ( "found some work! processing the task" ) ;
374
- this. process_task ( task, Scheduler :: resume_task_immediately_cl ) ;
375
- return None ;
355
+ return this. process_task ( task,
356
+ Scheduler :: resume_task_immediately_cl ) ;
376
357
}
377
358
None => {
378
359
rtdebug ! ( "no work was found, returning the scheduler struct" ) ;
@@ -392,35 +373,14 @@ impl Scheduler {
392
373
// there, trying to steal from the remote work queues.
393
374
fn find_work ( & mut self ) -> Option < ~Task > {
394
375
rtdebug ! ( "scheduler looking for work" ) ;
395
- if !self . steal_for_yield {
396
- match self . work_queue . pop ( ) {
397
- Some ( task) => {
398
- rtdebug ! ( "found a task locally" ) ;
399
- return Some ( task)
400
- }
401
- None => {
402
- rtdebug ! ( "scheduler trying to steal" ) ;
403
- return self . try_steals ( ) ;
404
- }
376
+ match self . work_queue . pop ( ) {
377
+ Some ( task) => {
378
+ rtdebug ! ( "found a task locally" ) ;
379
+ return Some ( task)
405
380
}
406
- } else {
407
- // During execution of the last task, it performed a 'yield',
408
- // so we're doing some work stealing in order to introduce some
409
- // scheduling randomness. Otherwise we would just end up popping
410
- // that same task again. This is pretty lame and is to work around
411
- // the problem that work stealing is not designed for 'non-strict'
412
- // (non-fork-join) task parallelism.
413
- self . steal_for_yield = false ;
414
- match self . try_steals ( ) {
415
- Some ( task) => {
416
- rtdebug ! ( "stole a task after yielding" ) ;
417
- return Some ( task) ;
418
- }
419
- None => {
420
- rtdebug ! ( "did not steal a task after yielding" ) ;
421
- // Back to business
422
- return self . find_work ( ) ;
423
- }
381
+ None => {
382
+ rtdebug ! ( "scheduler trying to steal" ) ;
383
+ return self . try_steals ( ) ;
424
384
}
425
385
}
426
386
}
@@ -449,7 +409,7 @@ impl Scheduler {
449
409
// place.
450
410
451
411
fn process_task ( ~self , task : ~Task ,
452
- schedule_fn : SchedulingFn ) {
412
+ schedule_fn : SchedulingFn ) -> Option < ~ Scheduler > {
453
413
let mut this = self ;
454
414
let mut task = task;
455
415
@@ -462,23 +422,23 @@ impl Scheduler {
462
422
rtdebug ! ( "sending task home" ) ;
463
423
task. give_home ( Sched ( home_handle) ) ;
464
424
Scheduler :: send_task_home ( task) ;
465
- Local :: put ( this) ;
425
+ return Some ( this) ;
466
426
} else {
467
427
rtdebug ! ( "running task here" ) ;
468
428
task. give_home ( Sched ( home_handle) ) ;
469
- schedule_fn ( this, task) ;
429
+ return schedule_fn ( this, task) ;
470
430
}
471
431
}
472
432
AnySched if this. run_anything => {
473
433
rtdebug ! ( "running anysched task here" ) ;
474
434
task. give_home ( AnySched ) ;
475
- schedule_fn ( this, task) ;
435
+ return schedule_fn ( this, task) ;
476
436
}
477
437
AnySched => {
478
438
rtdebug ! ( "sending task to friend" ) ;
479
439
task. give_home ( AnySched ) ;
480
440
this. send_to_friend ( task) ;
481
- Local :: put ( this) ;
441
+ return Some ( this) ;
482
442
}
483
443
}
484
444
}
@@ -647,14 +607,15 @@ impl Scheduler {
647
607
648
608
// * Context Swapping Helpers - Here be ugliness!
649
609
650
- pub fn resume_task_immediately ( ~self , task : ~Task ) {
610
+ pub fn resume_task_immediately ( ~self , task : ~Task ) -> Option < ~ Scheduler > {
651
611
do self . change_task_context ( task) |sched, stask| {
652
612
sched. sched_task = Some ( stask) ;
653
613
}
614
+ return None ;
654
615
}
655
616
656
617
fn resume_task_immediately_cl ( sched : ~Scheduler ,
657
- task : ~Task ) {
618
+ task : ~Task ) -> Option < ~ Scheduler > {
658
619
sched. resume_task_immediately ( task)
659
620
}
660
621
@@ -701,10 +662,11 @@ impl Scheduler {
701
662
}
702
663
}
703
664
704
- fn switch_task ( sched : ~Scheduler , task : ~Task ) {
665
+ fn switch_task ( sched : ~Scheduler , task : ~Task ) -> Option < ~ Scheduler > {
705
666
do sched. switch_running_tasks_and_then ( task) |sched, last_task| {
706
667
sched. enqueue_blocked_task ( last_task) ;
707
668
} ;
669
+ return None ;
708
670
}
709
671
710
672
// * Task Context Helpers
@@ -724,7 +686,7 @@ impl Scheduler {
724
686
725
687
pub fn run_task ( task : ~Task ) {
726
688
let sched: ~Scheduler = Local :: take ( ) ;
727
- sched. process_task ( task, Scheduler :: switch_task) ;
689
+ sched. process_task ( task, Scheduler :: switch_task) . map_move ( Local :: put ) ;
728
690
}
729
691
730
692
pub fn run_task_later ( next_task : ~Task ) {
@@ -734,33 +696,6 @@ impl Scheduler {
734
696
} ;
735
697
}
736
698
737
- /// Yield control to the scheduler, executing another task. This is guaranteed
738
- /// to introduce some amount of randomness to the scheduler. Currently the
739
- /// randomness is a result of performing a round of work stealing (which
740
- /// may end up stealing from the current scheduler).
741
- pub fn yield_now ( ~self ) {
742
- let mut this = self ;
743
- this. yield_check_count = reset_yield_check ( & mut this. rng ) ;
744
- // Tell the scheduler to start stealing on the next iteration
745
- this. steal_for_yield = true ;
746
- do this. deschedule_running_task_and_then |sched, task| {
747
- sched. enqueue_blocked_task ( task) ;
748
- }
749
- }
750
-
751
- pub fn maybe_yield ( ~self ) {
752
- // The number of times to do the yield check before yielding, chosen arbitrarily.
753
- let mut this = self ;
754
- rtassert ! ( this. yield_check_count > 0 ) ;
755
- this. yield_check_count -= 1 ;
756
- if this. yield_check_count == 0 {
757
- this. yield_now ( ) ;
758
- } else {
759
- Local :: put ( this) ;
760
- }
761
- }
762
-
763
-
764
699
// * Utility Functions
765
700
766
701
pub fn sched_id ( & self ) -> uint { to_uint ( self ) }
@@ -783,7 +718,7 @@ impl Scheduler {
783
718
784
719
// Supporting types
785
720
786
- type SchedulingFn = ~fn ( ~Scheduler , ~Task ) ;
721
+ type SchedulingFn = ~fn ( ~Scheduler , ~Task ) -> Option < ~ Scheduler > ;
787
722
788
723
pub enum SchedMessage {
789
724
Wake ,
@@ -1296,40 +1231,4 @@ mod test {
1296
1231
}
1297
1232
}
1298
1233
}
1299
-
1300
- #[ test]
1301
- fn dont_starve_2 ( ) {
1302
- use rt:: comm:: oneshot;
1303
-
1304
- do stress_factor ( ) . times {
1305
- do run_in_newsched_task {
1306
- let ( port, chan) = oneshot ( ) ;
1307
- let ( _port2, chan2) = stream ( ) ;
1308
-
1309
- // This task should not be able to starve the other task.
1310
- // The sends should eventually yield.
1311
- do spawntask {
1312
- while !port. peek ( ) {
1313
- chan2. send ( ( ) ) ;
1314
- }
1315
- }
1316
-
1317
- chan. send ( ( ) ) ;
1318
- }
1319
- }
1320
- }
1321
-
1322
- // Regression test for a logic bug that would cause single-threaded schedulers
1323
- // to sleep forever after yielding and stealing another task.
1324
- #[ test]
1325
- fn single_threaded_yield ( ) {
1326
- use task:: { spawn, spawn_sched, SingleThreaded , deschedule} ;
1327
- use num:: Times ;
1328
-
1329
- do spawn_sched ( SingleThreaded ) {
1330
- do 5 . times { deschedule ( ) ; }
1331
- }
1332
- do spawn { }
1333
- do spawn { }
1334
- }
1335
1234
}
0 commit comments