14
14
15
15
use core:: prelude:: * ;
16
16
17
+ use libc;
17
18
use boxed:: Box ;
18
19
use vec:: Vec ;
19
- use sync:: atomic;
20
+ use sync:: { atomic, Once , ONCE_INIT } ;
20
21
use mem;
21
22
use thunk:: Thunk ;
22
23
23
24
use rt:: exclusive:: Exclusive ;
24
25
25
26
type Queue = Exclusive < Vec < Thunk > > ;
26
27
28
+ static INIT : Once = ONCE_INIT ;
27
29
static QUEUE : atomic:: AtomicUint = atomic:: INIT_ATOMIC_UINT ;
28
30
static RUNNING : atomic:: AtomicBool = atomic:: INIT_ATOMIC_BOOL ;
29
31
30
- pub fn init ( ) {
32
+ fn init ( ) {
31
33
let state: Box < Queue > = box Exclusive :: new ( Vec :: new ( ) ) ;
32
34
unsafe {
33
- rtassert ! ( !RUNNING . load( atomic:: SeqCst ) ) ;
34
- assert ! ( QUEUE . swap( mem:: transmute( state) , atomic:: SeqCst ) == 0 ) ;
35
- }
36
- }
37
-
38
- pub fn push ( f : Thunk ) {
39
- unsafe {
40
- // Note that the check against 0 for the queue pointer is not atomic at
41
- // all with respect to `run`, meaning that this could theoretically be a
42
- // use-after-free. There's not much we can do to protect against that,
43
- // however. Let's just assume a well-behaved runtime and go from there!
44
- rtassert ! ( !RUNNING . load( atomic:: SeqCst ) ) ;
45
- let queue = QUEUE . load ( atomic:: SeqCst ) ;
46
- rtassert ! ( queue != 0 ) ;
47
- ( * ( queue as * const Queue ) ) . lock ( ) . push ( f) ;
35
+ QUEUE . store ( mem:: transmute ( state) , atomic:: SeqCst ) ;
36
+ libc:: atexit ( run) ;
48
37
}
49
38
}
50
39
51
- pub fn run ( ) {
40
+ // Note: this is private and so can only be called via atexit above,
41
+ // which guarantees initialization.
42
+ extern fn run ( ) {
52
43
let cur = unsafe {
53
44
rtassert ! ( !RUNNING . load( atomic:: SeqCst ) ) ;
54
45
let queue = QUEUE . swap ( 0 , atomic:: SeqCst ) ;
@@ -63,3 +54,17 @@ pub fn run() {
63
54
to_run. invoke ( ( ) ) ;
64
55
}
65
56
}
57
+
58
+ pub fn push ( f : Thunk ) {
59
+ INIT . doit ( init) ;
60
+ unsafe {
61
+ // Note that the check against 0 for the queue pointer is not atomic at
62
+ // all with respect to `run`, meaning that this could theoretically be a
63
+ // use-after-free. There's not much we can do to protect against that,
64
+ // however. Let's just assume a well-behaved runtime and go from there!
65
+ rtassert ! ( !RUNNING . load( atomic:: SeqCst ) ) ;
66
+ let queue = QUEUE . load ( atomic:: SeqCst ) ;
67
+ rtassert ! ( queue != 0 ) ;
68
+ ( * ( queue as * const Queue ) ) . lock ( ) . push ( f) ;
69
+ }
70
+ }
0 commit comments