@@ -5,6 +5,7 @@ use crate::io;
5
5
use crate :: num:: NonZeroUsize ;
6
6
use crate :: time:: Duration ;
7
7
8
+ use super :: abi:: thread;
8
9
use super :: abi:: usercalls;
9
10
10
11
pub struct Thread ( task_queue:: JoinHandle ) ;
@@ -13,8 +14,65 @@ pub const DEFAULT_MIN_STACK_SIZE: usize = 4096;
13
14
14
15
pub use self :: task_queue:: JoinNotifier ;
15
16
17
+ mod tcs_queue {
18
+ use super :: super :: abi:: mem as sgx_mem;
19
+ use super :: super :: abi:: thread;
20
+ use crate :: ptr:: NonNull ;
21
+ use crate :: sync:: { Mutex , MutexGuard , Once } ;
22
+
23
+ #[ derive( Clone , PartialEq , Eq , Debug ) ]
24
+ pub ( super ) struct Tcs {
25
+ address : NonNull < u8 > ,
26
+ }
27
+
28
+ impl Tcs {
29
+ fn new ( address : NonNull < u8 > ) -> Tcs {
30
+ Tcs { address }
31
+ }
32
+
33
+ pub ( super ) fn address ( & self ) -> & NonNull < u8 > {
34
+ & self . address
35
+ }
36
+ }
37
+
38
+ /// A queue of not running TCS structs
39
+ static mut TCS_QUEUE : Option < Mutex < Vec < Tcs > > > = None ;
40
+ static TCS_QUEUE_INIT : Once = Once :: new ( ) ;
41
+
42
+ fn init_tcs_queue ( ) -> Vec < Tcs > {
43
+ sgx_mem:: static_tcses ( )
44
+ . iter ( )
45
+ . filter_map ( |addr| if NonNull :: new ( * addr as _ ) != Some ( thread:: current ( ) ) {
46
+ Some ( Tcs :: new ( NonNull :: new ( * addr as _ ) . expect ( "Compile-time value unexpected NULL" ) ) )
47
+ } else {
48
+ None
49
+ } )
50
+ . collect ( )
51
+ }
52
+
53
+ fn lock ( ) -> MutexGuard < ' static , Vec < Tcs > > {
54
+ unsafe {
55
+ TCS_QUEUE_INIT . call_once ( || TCS_QUEUE = Some ( Mutex :: new ( init_tcs_queue ( ) ) ) ) ;
56
+ TCS_QUEUE . as_ref ( ) . unwrap ( ) . lock ( ) . unwrap ( )
57
+ }
58
+ }
59
+
60
+ pub ( super ) fn take_tcs ( ) -> Option < Tcs > {
61
+ let mut tcs_queue = lock ( ) ;
62
+ if let Some ( tcs) = tcs_queue. pop ( ) { Some ( tcs) } else { None }
63
+ }
64
+
65
+ pub ( super ) fn add_tcs ( tcs : Tcs ) {
66
+ let mut tcs_queue = lock ( ) ;
67
+ tcs_queue. insert ( 0 , tcs) ;
68
+ }
69
+ }
70
+
16
71
mod task_queue {
72
+ use super :: tcs_queue:: { self , Tcs } ;
17
73
use super :: wait_notify;
74
+ use crate :: ptr:: NonNull ;
75
+ use crate :: sync:: mpsc;
18
76
use crate :: sync:: { Mutex , MutexGuard , Once } ;
19
77
20
78
pub type JoinHandle = wait_notify:: Waiter ;
@@ -30,18 +88,24 @@ mod task_queue {
30
88
pub ( super ) struct Task {
31
89
p : Box < dyn FnOnce ( ) > ,
32
90
done : JoinNotifier ,
91
+ tcs : Tcs ,
33
92
}
34
93
35
94
impl Task {
36
- pub ( super ) fn new ( p : Box < dyn FnOnce ( ) > ) -> ( Task , JoinHandle ) {
95
+ pub ( super ) fn new ( tcs : Tcs , p : Box < dyn FnOnce ( ) > ) -> ( Task , JoinHandle ) {
37
96
let ( done, recv) = wait_notify:: new ( ) ;
38
97
let done = JoinNotifier ( Some ( done) ) ;
39
- ( Task { p, done } , recv)
98
+ let task = Task { p, done, tcs } ;
99
+ ( task, recv)
40
100
}
41
101
42
102
pub ( super ) fn run ( self ) -> JoinNotifier {
43
- ( self . p ) ( ) ;
44
- self . done
103
+ let Task { tcs, p, done } = self ;
104
+
105
+ p ( ) ;
106
+
107
+ tcs_queue:: add_tcs ( tcs) ;
108
+ done
45
109
}
46
110
}
47
111
@@ -58,6 +122,13 @@ mod task_queue {
58
122
TASK_QUEUE . as_ref ( ) . unwrap ( ) . lock ( ) . unwrap ( )
59
123
}
60
124
}
125
+
126
+ pub ( super ) fn take_task ( tcs : NonNull < u8 > ) -> Option < Task > {
127
+ let mut tasks = lock ( ) ;
128
+ let ( i, _) = tasks. iter ( ) . enumerate ( ) . find ( |( _i, task) | * task. tcs . address ( ) == tcs) ?;
129
+ let task = tasks. remove ( i) ;
130
+ Some ( task)
131
+ }
61
132
}
62
133
63
134
/// This module provides a synchronization primitive that does not use thread
@@ -105,17 +176,17 @@ pub mod wait_notify {
105
176
impl Thread {
106
177
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
107
178
pub unsafe fn new ( _stack : usize , p : Box < dyn FnOnce ( ) > ) -> io:: Result < Thread > {
108
- let mut queue_lock = task_queue:: lock ( ) ;
109
- unsafe { usercalls:: launch_thread ( ) ? } ;
110
- let ( task, handle) = task_queue:: Task :: new ( p) ;
111
- queue_lock. push ( task) ;
179
+ let tcs = tcs_queue:: take_tcs ( ) . ok_or ( io:: Error :: from ( io:: ErrorKind :: WouldBlock ) ) ?;
180
+ let mut tasks = task_queue:: lock ( ) ;
181
+ unsafe { usercalls:: launch_thread ( Some ( * tcs. address ( ) ) ) ? } ;
182
+ let ( task, handle) = task_queue:: Task :: new ( tcs, p) ;
183
+ tasks. push ( task) ;
112
184
Ok ( Thread ( handle) )
113
185
}
114
186
115
187
pub ( super ) fn entry ( ) -> JoinNotifier {
116
- let mut pending_tasks = task_queue:: lock ( ) ;
117
- let task = rtunwrap ! ( Some , pending_tasks. pop( ) ) ;
118
- drop ( pending_tasks) ; // make sure to not hold the task queue lock longer than necessary
188
+ let task = task_queue:: take_task ( thread:: current ( ) )
189
+ . expect ( "enclave entered through TCS unexpectedly" ) ;
119
190
task. run ( )
120
191
}
121
192
0 commit comments