@@ -30,6 +30,7 @@ use cell::Cell;
30
30
use rand:: { XorShiftRng , RngUtil } ;
31
31
use iterator:: { range} ;
32
32
use vec:: { OwnedVector } ;
33
+ use rt:: uv:: idle:: IdleWatcher ;
33
34
34
35
/// The Scheduler is responsible for coordinating execution of Coroutines
35
36
/// on a single thread. When the scheduler is running it is owned by
@@ -76,8 +77,11 @@ pub struct Scheduler {
76
77
/// them to.
77
78
friend_handle : Option < SchedHandle > ,
78
79
/// A fast XorShift rng for scheduler use
79
- rng : XorShiftRng
80
-
80
+ rng : XorShiftRng ,
81
+ /// An IdleWatcher
82
+ idle_watcher : IdleWatcher ,
83
+ /// A flag to indicate whether or not the idle callback is active.
84
+ idle_flag : bool
81
85
}
82
86
83
87
pub struct SchedHandle {
@@ -124,6 +128,9 @@ impl Scheduler {
124
128
friend : Option < SchedHandle > )
125
129
-> Scheduler {
126
130
131
+ let mut event_loop = event_loop;
132
+ let idle_watcher = IdleWatcher :: new ( event_loop. uvio . uv_loop ( ) ) ;
133
+
127
134
Scheduler {
128
135
sleeper_list : sleeper_list,
129
136
message_queue : MessageQueue :: new ( ) ,
@@ -138,7 +145,9 @@ impl Scheduler {
138
145
metrics : SchedMetrics :: new ( ) ,
139
146
run_anything : run_anything,
140
147
friend_handle : friend,
141
- rng : XorShiftRng :: new ( )
148
+ rng : XorShiftRng :: new ( ) ,
149
+ idle_watcher : idle_watcher,
150
+ idle_flag : true
142
151
}
143
152
}
144
153
@@ -151,6 +160,8 @@ impl Scheduler {
151
160
// scheduler task and bootstrap into it.
152
161
pub fn bootstrap ( ~self , task : ~Task ) {
153
162
163
+ let mut this = self ;
164
+
154
165
// Initialize the TLS key.
155
166
local_ptr:: init_tls_key ( ) ;
156
167
@@ -161,10 +172,17 @@ impl Scheduler {
161
172
// task, put it in TLS.
162
173
Local :: put :: ( sched_task) ;
163
174
175
+ // Before starting our first task, make sure the idle callback
176
+ // is active. As we do not start in the sleep state this is
177
+ // important.
178
+ do this. idle_watcher . start |_idle_watcher, _status| {
179
+ Scheduler :: run_sched_once ( ) ;
180
+ }
181
+
164
182
// Now, as far as all the scheduler state is concerned, we are
165
183
// inside the "scheduler" context. So we can act like the
166
184
// scheduler and resume the provided task.
167
- self . resume_task_immediately ( task) ;
185
+ this . resume_task_immediately ( task) ;
168
186
169
187
// Now we are back in the scheduler context, having
170
188
// successfully run the input task. Start by running the
@@ -201,7 +219,7 @@ impl Scheduler {
201
219
// Always run through the scheduler loop at least once so that
202
220
// we enter the sleep state and can then be woken up by other
203
221
// schedulers.
204
- self_sched. event_loop . callback ( Scheduler :: run_sched_once) ;
222
+ // self_sched.event_loop.callback(Scheduler::run_sched_once);
205
223
206
224
// This is unsafe because we need to place the scheduler, with
207
225
// the event_loop inside, inside our task. But we still need a
@@ -235,7 +253,11 @@ impl Scheduler {
235
253
// already have a scheduler stored in our local task, so we
236
254
// start off by taking it. This is the only path through the
237
255
// scheduler where we get the scheduler this way.
238
- let sched = Local :: take :: < Scheduler > ( ) ;
256
+ let mut sched = Local :: take :: < Scheduler > ( ) ;
257
+
258
+ // Assume that we need to continue idling unless we reach the
259
+ // end of this function without performing an action.
260
+ sched. activate_idle ( ) ;
239
261
240
262
// Our first task is to read mail to see if we have important
241
263
// messages.
@@ -282,15 +304,40 @@ impl Scheduler {
282
304
sched. sleepy = true ;
283
305
let handle = sched. make_handle ( ) ;
284
306
sched. sleeper_list . push ( handle) ;
307
+ // Since we are sleeping, deactivate the idle callback.
308
+ sched. pause_idle ( ) ;
285
309
} else {
286
310
rtdebug ! ( "not sleeping, already doing so or no_sleep set" ) ;
311
+ // We may not be sleeping, but we still need to deactivate
312
+ // the idle callback.
313
+ sched. pause_idle ( ) ;
287
314
}
288
315
289
316
// Finished a cycle without using the Scheduler. Place it back
290
317
// in TLS.
291
318
Local :: put ( sched) ;
292
319
}
293
320
321
+ fn activate_idle ( & mut self ) {
322
+ if self . idle_flag {
323
+ rtdebug ! ( "idle flag already set, not reactivating idle watcher" ) ;
324
+ } else {
325
+ rtdebug ! ( "idle flag was false, reactivating idle watcher" ) ;
326
+ self . idle_flag = true ;
327
+ self . idle_watcher . restart ( ) ;
328
+ }
329
+ }
330
+
331
+ fn pause_idle ( & mut self ) {
332
+ if !self . idle_flag {
333
+ rtdebug ! ( "idle flag false, not stopping idle watcher" ) ;
334
+ } else {
335
+ rtdebug ! ( "idle flag true, stopping idle watcher" ) ;
336
+ self . idle_flag = false ;
337
+ self . idle_watcher . stop ( ) ;
338
+ }
339
+ }
340
+
294
341
pub fn make_handle ( & mut self ) -> SchedHandle {
295
342
let remote = self . event_loop . remote_callback ( Scheduler :: run_sched_once) ;
296
343
@@ -312,7 +359,7 @@ impl Scheduler {
312
359
313
360
// We push the task onto our local queue clone.
314
361
this. work_queue . push ( task) ;
315
- this. event_loop . callback ( Scheduler :: run_sched_once) ;
362
+ // this.event_loop.callback(Scheduler::run_sched_once);
316
363
317
364
// We've made work available. Notify a
318
365
// sleeping scheduler.
@@ -346,30 +393,34 @@ impl Scheduler {
346
393
// * Scheduler-context operations
347
394
348
395
// This function returns None if the scheduler is "used", or it
349
- // returns the still-available scheduler.
396
+ // returns the still-available scheduler. Note: currently
397
+ // considers *any* message receive a use and returns None.
350
398
fn interpret_message_queue ( ~self ) -> Option < ~Scheduler > {
351
399
352
400
let mut this = self ;
353
401
match this. message_queue . pop ( ) {
354
402
Some ( PinnedTask ( task) ) => {
355
- this. event_loop . callback ( Scheduler :: run_sched_once) ;
403
+ // this.event_loop.callback(Scheduler::run_sched_once);
356
404
let mut task = task;
357
405
task. give_home ( Sched ( this. make_handle ( ) ) ) ;
358
406
this. resume_task_immediately ( task) ;
359
407
return None ;
360
408
}
361
409
Some ( TaskFromFriend ( task) ) => {
362
- this. event_loop . callback ( Scheduler :: run_sched_once) ;
410
+ // this.event_loop.callback(Scheduler::run_sched_once);
363
411
rtdebug ! ( "got a task from a friend. lovely!" ) ;
364
- return this. sched_schedule_task ( task) ;
412
+ this. sched_schedule_task ( task) . map_move ( Local :: put) ;
413
+ return None ;
365
414
}
366
415
Some ( Wake ) => {
367
- this. event_loop . callback ( Scheduler :: run_sched_once) ;
416
+ // this.event_loop.callback(Scheduler::run_sched_once);
368
417
this. sleepy = false ;
369
- return Some ( this) ;
418
+ Local :: put ( this) ;
419
+ return None ;
420
+ // return Some(this);
370
421
}
371
422
Some ( Shutdown ) => {
372
- this. event_loop . callback ( Scheduler :: run_sched_once) ;
423
+ // this.event_loop.callback(Scheduler::run_sched_once);
373
424
if this. sleepy {
374
425
// There may be an outstanding handle on the
375
426
// sleeper list. Pop them all to make sure that's
@@ -388,11 +439,10 @@ impl Scheduler {
388
439
// event loop references we will shut down.
389
440
this. no_sleep = true ;
390
441
this. sleepy = false ;
391
- // YYY: Does a shutdown count as a "use" of the
392
- // scheduler? This seems to work - so I'm leaving it
393
- // this way despite not having a solid rational for
394
- // why I should return the scheduler here.
395
- return Some ( this) ;
442
+
443
+ Local :: put ( this) ;
444
+ return None ;
445
+ // return Some(this);
396
446
}
397
447
None => {
398
448
return Some ( this) ;
0 commit comments