11
11
use option:: * ;
12
12
use sys;
13
13
use cast:: transmute;
14
- use libc:: c_void;
15
- use ptr:: mut_null;
16
14
17
15
use super :: work_queue:: WorkQueue ;
18
16
use super :: stack:: { StackPool , StackSegment } ;
19
17
use super :: rtio:: { EventLoop , EventLoopObject } ;
20
18
use super :: context:: Context ;
21
- use tls = super :: thread_local_storage;
22
19
23
20
#[ cfg( test) ] use super :: uvio:: UvEventLoop ;
24
21
#[ cfg( test) ] use unstable:: run_in_bare_thread;
@@ -110,18 +107,13 @@ pub impl Scheduler {
110
107
}
111
108
112
109
fn install ( ~self , f : & fn ( & mut Scheduler ) ) -> ~Scheduler {
113
- let mut tlsched = ThreadLocalScheduler :: new ( ) ;
114
- tlsched. put_scheduler ( self ) ;
115
- {
116
- let sched = tlsched. get_scheduler ( ) ;
117
- f ( sched) ;
110
+ do local:: install ( self ) {
111
+ local:: borrow ( f)
118
112
}
119
- return tlsched. take_scheduler ( ) ;
120
113
}
121
114
122
115
fn local ( f : & fn ( & mut Scheduler ) ) {
123
- let mut tlsched = ThreadLocalScheduler :: new ( ) ;
124
- f ( tlsched. get_scheduler ( ) ) ;
116
+ local:: borrow ( f)
125
117
}
126
118
127
119
// * Scheduler-context operations
@@ -329,15 +321,15 @@ pub impl Task {
329
321
// This is the first code to execute after the initial
330
322
// context switch to the task. The previous context may
331
323
// have asked us to do some cleanup.
332
- let mut sched = ThreadLocalScheduler :: new ( ) ;
333
- let sched = sched. get_scheduler ( ) ;
334
- sched . run_cleanup_job ( ) ;
324
+ do Scheduler :: local | sched| {
325
+ sched. run_cleanup_job ( ) ;
326
+ }
335
327
336
328
start ( ) ;
337
329
338
- let mut sched = ThreadLocalScheduler :: new ( ) ;
339
- let sched = sched. get_scheduler ( ) ;
340
- sched . terminate_current_task ( ) ;
330
+ do Scheduler :: local | sched| {
331
+ sched. terminate_current_task ( ) ;
332
+ }
341
333
} ;
342
334
return wrapper;
343
335
}
@@ -352,90 +344,103 @@ pub impl Task {
352
344
}
353
345
}
354
346
355
- // NB: This is a type so we can use make use of the &self region.
356
- struct ThreadLocalScheduler ( tls:: Key ) ;
347
+ mod local {
348
+
349
+ //! Access to the thread-local Scheduler
350
+
351
+ use ptr:: mut_null;
352
+ use libc:: c_void;
353
+ use cast:: transmute;
354
+
355
+ use super :: Scheduler ;
356
+ use tls = super :: super :: thread_local_storage;
357
+ #[ cfg( test) ] use super :: super :: uvio:: UvEventLoop ;
357
358
358
- impl ThreadLocalScheduler {
359
- fn new ( ) -> ThreadLocalScheduler {
359
+ /// Give the Scheduler to thread-local storage
360
+ pub fn put ( sched : ~ Scheduler ) {
360
361
unsafe {
361
- // NB: This assumes that the TLS key has been created prior.
362
- // Currently done in rust_start.
363
- let key: * mut c_void = rust_get_sched_tls_key ( ) ;
364
- let key: & mut tls:: Key = transmute ( key) ;
365
- ThreadLocalScheduler ( * key)
362
+ let key = tls_key ( ) ;
363
+ let void_sched: * mut c_void = transmute :: < ~Scheduler , * mut c_void > ( sched) ;
364
+ tls:: set ( key, void_sched) ;
366
365
}
367
366
}
368
367
369
- fn put_scheduler ( & mut self , scheduler : ~Scheduler ) {
368
+ /// Take ownership of the Scheduler from thread-local storage
369
+ pub fn take ( ) -> ~Scheduler {
370
370
unsafe {
371
- let key = match self { & ThreadLocalScheduler ( key) => key } ;
372
- let value: * mut c_void = transmute :: < ~Scheduler , * mut c_void > ( scheduler) ;
373
- tls:: set ( key, value) ;
371
+ let key = tls_key ( ) ;
372
+ let void_sched: * mut c_void = tls:: get ( key) ;
373
+ assert ! ( void_sched. is_not_null( ) ) ;
374
+ let sched = transmute :: < * mut c_void , ~Scheduler > ( void_sched) ;
375
+ tls:: set ( key, mut_null ( ) ) ;
376
+ return sched;
374
377
}
375
378
}
376
379
377
- fn get_scheduler ( & mut self ) -> & ' self mut Scheduler {
380
+ /// Give the Scheduler to thread-local storage for the duration of the block
381
+ pub fn install ( sched : ~Scheduler , f : & fn ( ) ) -> ~Scheduler {
382
+ put ( sched) ;
383
+ f ( ) ;
384
+ return take ( ) ;
385
+ }
386
+
387
+ /// Borrow a mutable reference to the thread-local Scheduler
388
+ /// # Safety Note
389
+ /// Because this leaves the Scheduler in thread-local storage it is possible
390
+ /// For the Scheduler pointer to be aliased
391
+ pub fn borrow ( f : & fn ( & mut Scheduler ) ) {
378
392
unsafe {
379
- let key = match self { & ThreadLocalScheduler ( key ) => key } ;
380
- let mut value : * mut c_void = tls:: get ( key) ;
381
- assert ! ( value . is_not_null( ) ) ;
393
+ let key = tls_key ( ) ;
394
+ let mut void_sched : * mut c_void = tls:: get ( key) ;
395
+ assert ! ( void_sched . is_not_null( ) ) ;
382
396
{
383
- let value_ptr = & mut value ;
397
+ let void_sched_ptr = & mut void_sched ;
384
398
let sched: & mut ~Scheduler = {
385
- transmute :: < & mut * mut c_void , & mut ~Scheduler > ( value_ptr )
399
+ transmute :: < & mut * mut c_void , & mut ~Scheduler > ( void_sched_ptr )
386
400
} ;
387
401
let sched: & mut Scheduler = & mut * * sched;
388
- return sched;
402
+ f ( sched) ;
389
403
}
390
404
}
391
405
}
392
406
393
- fn take_scheduler ( & mut self ) -> ~ Scheduler {
407
+ fn tls_key ( ) -> tls :: Key {
394
408
unsafe {
395
- let key = match self { & ThreadLocalScheduler ( key) => key } ;
396
- let value: * mut c_void = tls:: get ( key) ;
397
- assert ! ( value. is_not_null( ) ) ;
398
- let sched = transmute ( value) ;
399
- tls:: set ( key, mut_null ( ) ) ;
400
- return sched;
409
+ let key: * mut c_void = rust_get_sched_tls_key ( ) ;
410
+ let key: & mut tls:: Key = transmute ( key) ;
411
+ return * key;
401
412
}
402
413
}
403
- }
404
-
405
- extern {
406
- fn rust_get_sched_tls_key ( ) -> * mut c_void ;
407
- }
408
-
409
- #[ test]
410
- fn thread_local_scheduler_smoke_test ( ) {
411
- let scheduler = ~UvEventLoop :: new_scheduler ( ) ;
412
- let mut tls_scheduler = ThreadLocalScheduler :: new ( ) ;
413
- tls_scheduler. put_scheduler ( scheduler) ;
414
- {
415
- let _scheduler = tls_scheduler. get_scheduler ( ) ;
416
- }
417
- let _scheduler = tls_scheduler. take_scheduler ( ) ;
418
- }
419
414
420
- #[ test]
421
- fn thread_local_scheduler_two_instances ( ) {
422
- let scheduler = ~UvEventLoop :: new_scheduler ( ) ;
423
- let mut tls_scheduler = ThreadLocalScheduler :: new ( ) ;
424
- tls_scheduler. put_scheduler ( scheduler) ;
425
- {
415
+ extern {
416
+ fn rust_get_sched_tls_key ( ) -> * mut c_void ;
417
+ }
426
418
427
- let _scheduler = tls_scheduler. get_scheduler ( ) ;
419
+ #[ test]
420
+ fn thread_local_scheduler_smoke_test ( ) {
421
+ let scheduler = ~UvEventLoop :: new_scheduler ( ) ;
422
+ put ( scheduler) ;
423
+ let _scheduler = take ( ) ;
428
424
}
429
- {
430
- let scheduler = tls_scheduler. take_scheduler ( ) ;
431
- tls_scheduler. put_scheduler ( scheduler) ;
425
+
426
+ #[ test]
427
+ fn thread_local_scheduler_two_instances ( ) {
428
+ let scheduler = ~UvEventLoop :: new_scheduler ( ) ;
429
+ put ( scheduler) ;
430
+ let _scheduler = take ( ) ;
431
+ let scheduler = ~UvEventLoop :: new_scheduler ( ) ;
432
+ put ( scheduler) ;
433
+ let _scheduler = take ( ) ;
432
434
}
433
435
434
- let mut tls_scheduler = ThreadLocalScheduler :: new ( ) ;
435
- {
436
- let _scheduler = tls_scheduler. get_scheduler ( ) ;
436
+ #[ test]
437
+ fn install_borrow_smoke_test ( ) {
438
+ let scheduler = ~UvEventLoop :: new_scheduler ( ) ;
439
+ let _scheduler = do install ( scheduler) {
440
+ do borrow |_sched| {
441
+ }
442
+ } ;
437
443
}
438
- let _scheduler = tls_scheduler. take_scheduler ( ) ;
439
444
}
440
445
441
446
#[ test]
0 commit comments