@@ -280,11 +280,9 @@ pub impl Scheduler {
280
280
281
281
rtdebug ! ( "ending running task" ) ;
282
282
283
- do self. deschedule_running_task_and_then |dead_task| {
283
+ do self. deschedule_running_task_and_then |sched , dead_task| {
284
284
let dead_task = Cell ( dead_task) ;
285
- do Local :: borrow :: < Scheduler > |sched| {
286
- dead_task. take ( ) . recycle ( & mut sched. stack_pool ) ;
287
- }
285
+ dead_task. take ( ) . recycle ( & mut sched. stack_pool ) ;
288
286
}
289
287
290
288
abort ! ( "control reached end of task" ) ;
@@ -293,22 +291,18 @@ pub impl Scheduler {
293
291
fn schedule_new_task ( ~self , task : ~Coroutine ) {
294
292
assert ! ( self . in_task_context( ) ) ;
295
293
296
- do self. switch_running_tasks_and_then ( task) |last_task| {
294
+ do self. switch_running_tasks_and_then ( task) |sched , last_task| {
297
295
let last_task = Cell ( last_task) ;
298
- do Local :: borrow :: < Scheduler > |sched| {
299
- sched. enqueue_task ( last_task. take ( ) ) ;
300
- }
296
+ sched. enqueue_task ( last_task. take ( ) ) ;
301
297
}
302
298
}
303
299
304
300
fn schedule_task ( ~self , task : ~Coroutine ) {
305
301
assert ! ( self . in_task_context( ) ) ;
306
302
307
- do self. switch_running_tasks_and_then ( task) |last_task| {
303
+ do self. switch_running_tasks_and_then ( task) |sched , last_task| {
308
304
let last_task = Cell ( last_task) ;
309
- do Local :: borrow :: < Scheduler > |sched| {
310
- sched. enqueue_task ( last_task. take ( ) ) ;
311
- }
305
+ sched. enqueue_task ( last_task. take ( ) ) ;
312
306
}
313
307
}
314
308
@@ -352,15 +346,20 @@ pub impl Scheduler {
352
346
/// The closure here is a *stack* closure that lives in the
353
347
/// running task. It gets transmuted to the scheduler's lifetime
354
348
/// and called while the task is blocked.
355
- fn deschedule_running_task_and_then ( ~self , f : & fn ( ~Coroutine ) ) {
349
+ ///
350
+ /// This passes a Scheduler pointer to the fn after the context switch
351
+ /// in order to prevent that fn from performing further scheduling operations.
352
+ /// Doing further scheduling could easily result in infinite recursion.
353
+ fn deschedule_running_task_and_then ( ~self , f : & fn ( & mut Scheduler , ~Coroutine ) ) {
356
354
let mut this = self ;
357
355
assert ! ( this. in_task_context( ) ) ;
358
356
359
357
rtdebug ! ( "blocking task" ) ;
360
358
361
359
unsafe {
362
360
let blocked_task = this. current_task . swap_unwrap ( ) ;
363
- let f_fake_region = transmute :: < & fn ( ~Coroutine ) , & fn ( ~Coroutine ) > ( f) ;
361
+ let f_fake_region = transmute :: < & fn ( & mut Scheduler , ~Coroutine ) ,
362
+ & fn ( & mut Scheduler , ~Coroutine ) > ( f) ;
364
363
let f_opaque = ClosureConverter :: from_fn ( f_fake_region) ;
365
364
this. enqueue_cleanup_job ( GiveTask ( blocked_task, f_opaque) ) ;
366
365
}
@@ -382,14 +381,18 @@ pub impl Scheduler {
382
381
/// Switch directly to another task, without going through the scheduler.
383
382
/// You would want to think hard about doing this, e.g. if there are
384
383
/// pending I/O events it would be a bad idea.
385
- fn switch_running_tasks_and_then ( ~self , next_task : ~Coroutine , f : & fn ( ~Coroutine ) ) {
384
+ fn switch_running_tasks_and_then ( ~self , next_task : ~Coroutine ,
385
+ f : & fn ( & mut Scheduler , ~Coroutine ) ) {
386
386
let mut this = self ;
387
387
assert ! ( this. in_task_context( ) ) ;
388
388
389
389
rtdebug ! ( "switching tasks" ) ;
390
390
391
391
let old_running_task = this. current_task . swap_unwrap ( ) ;
392
- let f_fake_region = unsafe { transmute :: < & fn ( ~Coroutine ) , & fn ( ~Coroutine ) > ( f) } ;
392
+ let f_fake_region = unsafe {
393
+ transmute :: < & fn ( & mut Scheduler , ~Coroutine ) ,
394
+ & fn ( & mut Scheduler , ~Coroutine ) > ( f)
395
+ } ;
393
396
let f_opaque = ClosureConverter :: from_fn ( f_fake_region) ;
394
397
this. enqueue_cleanup_job ( GiveTask ( old_running_task, f_opaque) ) ;
395
398
this. current_task = Some ( next_task) ;
@@ -426,7 +429,7 @@ pub impl Scheduler {
426
429
let cleanup_job = self . cleanup_job . swap_unwrap ( ) ;
427
430
match cleanup_job {
428
431
DoNothing => { }
429
- GiveTask ( task, f) => ( f. to_fn ( ) ) ( task)
432
+ GiveTask ( task, f) => ( f. to_fn ( ) ) ( self , task)
430
433
}
431
434
}
432
435
@@ -535,12 +538,12 @@ pub impl Coroutine {
535
538
// complaining
536
539
type UnsafeTaskReceiver = sys:: Closure ;
537
540
trait ClosureConverter {
538
- fn from_fn ( & fn ( ~Coroutine ) ) -> Self ;
539
- fn to_fn ( self ) -> & fn ( ~Coroutine ) ;
541
+ fn from_fn ( & fn ( & mut Scheduler , ~Coroutine ) ) -> Self ;
542
+ fn to_fn ( self ) -> & fn ( & mut Scheduler , ~Coroutine ) ;
540
543
}
541
544
impl ClosureConverter for UnsafeTaskReceiver {
542
- fn from_fn ( f : & fn ( ~Coroutine ) ) -> UnsafeTaskReceiver { unsafe { transmute ( f) } }
543
- fn to_fn ( self ) -> & fn ( ~Coroutine ) { unsafe { transmute ( self ) } }
545
+ fn from_fn ( f : & fn ( & mut Scheduler , ~Coroutine ) ) -> UnsafeTaskReceiver { unsafe { transmute ( f) } }
546
+ fn to_fn ( self ) -> & fn ( & mut Scheduler , ~Coroutine ) { unsafe { transmute ( self ) } }
544
547
}
545
548
546
549
#[ cfg( test) ]
@@ -604,11 +607,9 @@ mod test {
604
607
unsafe { * count_ptr = * count_ptr + 1 ; }
605
608
} ;
606
609
// Context switch directly to the new task
607
- do sched. switch_running_tasks_and_then ( task2) |task1| {
610
+ do sched. switch_running_tasks_and_then ( task2) |sched , task1| {
608
611
let task1 = Cell ( task1) ;
609
- do Local :: borrow :: < Scheduler > |sched| {
610
- sched. enqueue_task ( task1. take ( ) ) ;
611
- }
612
+ sched. enqueue_task ( task1. take ( ) ) ;
612
613
}
613
614
unsafe { * count_ptr = * count_ptr + 1 ; }
614
615
} ;
@@ -658,12 +659,10 @@ mod test {
658
659
let task = ~do Coroutine :: new ( & mut sched. stack_pool ) {
659
660
let sched = Local :: take :: < Scheduler > ( ) ;
660
661
assert ! ( sched. in_task_context( ) ) ;
661
- do sched. deschedule_running_task_and_then ( ) |task| {
662
+ do sched. deschedule_running_task_and_then ( ) |sched , task| {
662
663
let task = Cell ( task) ;
663
- do Local :: borrow :: < Scheduler > |sched| {
664
- assert ! ( !sched. in_task_context( ) ) ;
665
- sched. enqueue_task ( task. take ( ) ) ;
666
- }
664
+ assert ! ( !sched. in_task_context( ) ) ;
665
+ sched. enqueue_task ( task. take ( ) ) ;
667
666
}
668
667
} ;
669
668
sched. enqueue_task ( task) ;
@@ -680,16 +679,14 @@ mod test {
680
679
do run_in_newsched_task {
681
680
do spawn {
682
681
let sched = Local :: take :: < Scheduler > ( ) ;
683
- do sched. deschedule_running_task_and_then |task| {
684
- let mut sched = Local :: take :: < Scheduler > ( ) ;
682
+ do sched. deschedule_running_task_and_then |sched, task| {
685
683
let task = Cell ( task) ;
686
684
do sched. event_loop . callback_ms ( 10 ) {
687
685
rtdebug ! ( "in callback" ) ;
688
686
let mut sched = Local :: take :: < Scheduler > ( ) ;
689
687
sched. enqueue_task ( task. take ( ) ) ;
690
688
Local :: put ( sched) ;
691
689
}
692
- Local :: put ( sched) ;
693
690
}
694
691
}
695
692
}
0 commit comments