@@ -20,6 +20,7 @@ use super::context::Context;
20
20
#[ cfg( test) ] use super :: uvio:: UvEventLoop ;
21
21
#[ cfg( test) ] use unstable:: run_in_bare_thread;
22
22
#[ cfg( test) ] use int;
23
+ #[ cfg( test) ] use cell:: Cell ;
23
24
24
25
mod local;
25
26
@@ -46,14 +47,14 @@ pub struct Scheduler {
46
47
// complaining
47
48
type UnsafeTaskReceiver = sys:: Closure ;
48
49
trait HackAroundBorrowCk {
49
- fn from_fn ( & fn ( & mut Scheduler , ~Task ) ) -> Self ;
50
- fn to_fn ( self ) -> & fn ( & mut Scheduler , ~Task ) ;
50
+ fn from_fn ( & fn ( ~Task ) ) -> Self ;
51
+ fn to_fn ( self ) -> & fn ( ~Task ) ;
51
52
}
52
53
impl HackAroundBorrowCk for UnsafeTaskReceiver {
53
- fn from_fn ( f : & fn ( & mut Scheduler , ~Task ) ) -> UnsafeTaskReceiver {
54
+ fn from_fn ( f : & fn ( ~Task ) ) -> UnsafeTaskReceiver {
54
55
unsafe { transmute ( f) }
55
56
}
56
- fn to_fn ( self ) -> & fn ( & mut Scheduler , ~Task ) {
57
+ fn to_fn ( self ) -> & fn ( ~Task ) {
57
58
unsafe { transmute ( self ) }
58
59
}
59
60
}
@@ -97,10 +98,12 @@ pub impl Scheduler {
97
98
98
99
let scheduler = Scheduler :: unsafe_local_borrow ( ) ;
99
100
fn run_scheduler_once ( ) {
100
- let scheduler = Scheduler :: unsafe_local_borrow ( ) ;
101
+ let scheduler = Scheduler :: local_take ( ) ;
101
102
if scheduler. resume_task_from_queue ( ) {
102
103
// Ok, a task ran. Nice! We'll do it again later
103
- scheduler. event_loop . callback ( run_scheduler_once) ;
104
+ do Scheduler :: local_borrow |scheduler| {
105
+ scheduler. event_loop . callback ( run_scheduler_once) ;
106
+ }
104
107
}
105
108
}
106
109
@@ -124,9 +127,13 @@ pub impl Scheduler {
124
127
local:: put ( sched) ;
125
128
}
126
129
130
+ fn local_take ( ) -> ~Scheduler {
131
+ local:: take ( )
132
+ }
133
+
127
134
// * Scheduler-context operations
128
135
129
- fn resume_task_from_queue ( & mut self ) -> bool {
136
+ fn resume_task_from_queue ( ~ self ) -> bool {
130
137
assert ! ( !self . in_task_context( ) ) ;
131
138
132
139
let mut self = self ;
@@ -137,12 +144,14 @@ pub impl Scheduler {
137
144
}
138
145
None => {
139
146
rtdebug ! ( "no tasks in queue" ) ;
147
+ local:: put ( self ) ;
140
148
return false ;
141
149
}
142
150
}
143
151
}
144
152
145
- fn resume_task_immediately ( & mut self , task : ~Task ) {
153
+ fn resume_task_immediately ( ~self , task : ~Task ) {
154
+ let mut self = self ;
146
155
assert ! ( !self . in_task_context( ) ) ;
147
156
148
157
rtdebug ! ( "scheduling a task" ) ;
@@ -151,39 +160,46 @@ pub impl Scheduler {
151
160
self . current_task = Some ( task) ;
152
161
self . enqueue_cleanup_job ( DoNothing ) ;
153
162
163
+ local:: put ( self ) ;
164
+
154
165
// Take pointers to both the task and scheduler's saved registers.
155
- {
156
- let ( sched_context, _, next_task_context) = self . get_contexts ( ) ;
157
- let next_task_context = next_task_context. unwrap ( ) ;
158
- // Context switch to the task, restoring it's registers
159
- // and saving the scheduler's
160
- Context :: swap ( sched_context, next_task_context) ;
161
- }
166
+ let sched = Scheduler :: unsafe_local_borrow ( ) ;
167
+ let ( sched_context, _, next_task_context) = sched. get_contexts ( ) ;
168
+ let next_task_context = next_task_context. unwrap ( ) ;
169
+ // Context switch to the task, restoring it's registers
170
+ // and saving the scheduler's
171
+ Context :: swap ( sched_context, next_task_context) ;
162
172
173
+ let sched = Scheduler :: unsafe_local_borrow ( ) ;
163
174
// The running task should have passed ownership elsewhere
164
- assert ! ( self . current_task. is_none( ) ) ;
175
+ assert ! ( sched . current_task. is_none( ) ) ;
165
176
166
177
// Running tasks may have asked us to do some cleanup
167
- self . run_cleanup_job ( ) ;
178
+ sched . run_cleanup_job ( ) ;
168
179
}
169
180
170
181
171
182
// * Task-context operations
172
183
173
184
/// Called by a running task to end execution, after which it will
174
185
/// be recycled by the scheduler for reuse in a new task.
175
- fn terminate_current_task ( & mut self ) {
186
+ fn terminate_current_task ( ~self ) {
187
+ let mut self = self ;
176
188
assert ! ( self . in_task_context( ) ) ;
177
189
178
190
rtdebug ! ( "ending running task" ) ;
179
191
180
192
let dead_task = self . current_task . swap_unwrap ( ) ;
181
193
self . enqueue_cleanup_job ( RecycleTask ( dead_task) ) ;
182
- {
183
- let ( sched_context, last_task_context, _) = self . get_contexts ( ) ;
184
- let last_task_context = last_task_context. unwrap ( ) ;
185
- Context :: swap ( last_task_context, sched_context) ;
186
- }
194
+
195
+ local:: put ( self ) ;
196
+
197
+ let sched = Scheduler :: unsafe_local_borrow ( ) ;
198
+ let ( sched_context, last_task_context, _) = sched. get_contexts ( ) ;
199
+ let last_task_context = last_task_context. unwrap ( ) ;
200
+ Context :: swap ( last_task_context, sched_context) ;
201
+
202
+ // Control never reaches here
187
203
}
188
204
189
205
/// Block a running task, context switch to the scheduler, then pass the
@@ -194,22 +210,25 @@ pub impl Scheduler {
194
210
/// The closure here is a *stack* closure that lives in the
195
211
/// running task. It gets transmuted to the scheduler's lifetime
196
212
/// and called while the task is blocked.
197
- fn deschedule_running_task_and_then ( & mut self , f : & fn ( & mut Scheduler , ~Task ) ) {
213
+ fn deschedule_running_task_and_then ( ~self , f : & fn ( ~Task ) ) {
214
+ let mut self = self ;
198
215
assert ! ( self . in_task_context( ) ) ;
199
216
200
217
rtdebug ! ( "blocking task" ) ;
201
218
202
219
let blocked_task = self . current_task . swap_unwrap ( ) ;
203
220
let f_fake_region = unsafe {
204
- transmute :: < & fn ( & mut Scheduler , ~Task ) , & fn ( & mut Scheduler , ~Task ) > ( f)
221
+ transmute :: < & fn ( ~Task ) , & fn ( ~Task ) > ( f)
205
222
} ;
206
223
let f_opaque = HackAroundBorrowCk :: from_fn ( f_fake_region) ;
207
224
self . enqueue_cleanup_job ( GiveTask ( blocked_task, f_opaque) ) ;
208
- {
209
- let ( sched_context, last_task_context, _) = self . get_contexts ( ) ;
210
- let last_task_context = last_task_context. unwrap ( ) ;
211
- Context :: swap ( last_task_context, sched_context) ;
212
- }
225
+
226
+ local:: put ( self ) ;
227
+
228
+ let sched = Scheduler :: unsafe_local_borrow ( ) ;
229
+ let ( sched_context, last_task_context, _) = sched. get_contexts ( ) ;
230
+ let last_task_context = last_task_context. unwrap ( ) ;
231
+ Context :: swap ( last_task_context, sched_context) ;
213
232
214
233
// We could be executing in a different thread now
215
234
let sched = Scheduler :: unsafe_local_borrow ( ) ;
@@ -219,20 +238,23 @@ pub impl Scheduler {
219
238
/// Switch directly to another task, without going through the scheduler.
220
239
/// You would want to think hard about doing this, e.g. if there are
221
240
/// pending I/O events it would be a bad idea.
222
- fn resume_task_from_running_task_direct ( & mut self , next_task : ~Task ) {
241
+ fn resume_task_from_running_task_direct ( ~self , next_task : ~Task ) {
242
+ let mut self = self ;
223
243
assert ! ( self . in_task_context( ) ) ;
224
244
225
245
rtdebug ! ( "switching tasks" ) ;
226
246
227
247
let old_running_task = self . current_task . swap_unwrap ( ) ;
228
248
self . enqueue_cleanup_job ( RescheduleTask ( old_running_task) ) ;
229
249
self . current_task = Some ( next_task) ;
230
- {
231
- let ( _, last_task_context, next_task_context) = self . get_contexts ( ) ;
232
- let last_task_context = last_task_context. unwrap ( ) ;
233
- let next_task_context = next_task_context. unwrap ( ) ;
234
- Context :: swap ( last_task_context, next_task_context) ;
235
- }
250
+
251
+ local:: put ( self ) ;
252
+
253
+ let sched = Scheduler :: unsafe_local_borrow ( ) ;
254
+ let ( _, last_task_context, next_task_context) = sched. get_contexts ( ) ;
255
+ let last_task_context = last_task_context. unwrap ( ) ;
256
+ let next_task_context = next_task_context. unwrap ( ) ;
257
+ Context :: swap ( last_task_context, next_task_context) ;
236
258
237
259
// We could be executing in a different thread now
238
260
let sched = Scheduler :: unsafe_local_borrow ( ) ;
@@ -261,7 +283,7 @@ pub impl Scheduler {
261
283
self . task_queue . push_front ( task) ;
262
284
}
263
285
RecycleTask ( task) => task. recycle ( & mut self . stack_pool ) ,
264
- GiveTask ( task, f) => ( f. to_fn ( ) ) ( self , task)
286
+ GiveTask ( task, f) => ( f. to_fn ( ) ) ( task)
265
287
}
266
288
}
267
289
@@ -338,7 +360,7 @@ pub impl Task {
338
360
339
361
start ( ) ;
340
362
341
- let sched = Scheduler :: unsafe_local_borrow ( ) ;
363
+ let sched = Scheduler :: local_take ( ) ;
342
364
sched. terminate_current_task ( ) ;
343
365
} ;
344
366
return wrapper;
@@ -398,7 +420,7 @@ fn test_swap_tasks() {
398
420
let mut sched = ~UvEventLoop :: new_scheduler ( ) ;
399
421
let task1 = ~do Task :: new ( & mut sched. stack_pool ) {
400
422
unsafe { * count_ptr = * count_ptr + 1 ; }
401
- let sched = Scheduler :: unsafe_local_borrow ( ) ;
423
+ let mut sched = Scheduler :: local_take ( ) ;
402
424
let task2 = ~do Task :: new ( & mut sched. stack_pool ) {
403
425
unsafe { * count_ptr = * count_ptr + 1 ; }
404
426
} ;
@@ -463,7 +485,7 @@ fn test_run_a_lot_of_tasks_direct() {
463
485
assert ! ( count == MAX ) ;
464
486
465
487
fn run_task ( count_ptr : * mut int ) {
466
- let sched = Scheduler :: unsafe_local_borrow ( ) ;
488
+ let mut sched = Scheduler :: local_take ( ) ;
467
489
let task = ~do Task :: new ( & mut sched. stack_pool ) {
468
490
unsafe {
469
491
* count_ptr = * count_ptr + 1 ;
@@ -483,11 +505,14 @@ fn test_block_task() {
483
505
do run_in_bare_thread {
484
506
let mut sched = ~UvEventLoop : : new_scheduler ( ) ;
485
507
let task = ~do Task :: new ( & mut sched. stack_pool ) {
486
- let sched = Scheduler :: unsafe_local_borrow ( ) ;
508
+ let sched = Scheduler :: local_take ( ) ;
487
509
assert ! ( sched. in_task_context( ) ) ;
488
- do sched. deschedule_running_task_and_then ( ) |sched, task| {
489
- assert ! ( !sched. in_task_context( ) ) ;
490
- sched. task_queue . push_back ( task) ;
510
+ do sched. deschedule_running_task_and_then ( ) |task| {
511
+ let task = Cell ( task) ;
512
+ do Scheduler :: local_borrow |sched| {
513
+ assert ! ( !sched. in_task_context( ) ) ;
514
+ sched. task_queue . push_back ( task. take ( ) ) ;
515
+ }
491
516
}
492
517
} ;
493
518
sched. task_queue . push_back ( task) ;
0 commit comments