@@ -5,6 +5,7 @@ use crate::io;
55use crate :: num:: NonZeroUsize ;
66use crate :: time:: Duration ;
77
8+ use super :: abi:: thread;
89use super :: abi:: usercalls;
910
1011pub struct Thread ( task_queue:: JoinHandle ) ;
@@ -13,8 +14,65 @@ pub const DEFAULT_MIN_STACK_SIZE: usize = 4096;
1314
1415pub use self :: task_queue:: JoinNotifier ;
1516
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+
1671mod task_queue {
72+ use super :: tcs_queue:: { self , Tcs } ;
1773 use super :: wait_notify;
74+ use crate :: ptr:: NonNull ;
75+ use crate :: sync:: mpsc;
1876 use crate :: sync:: { Mutex , MutexGuard , Once } ;
1977
2078 pub type JoinHandle = wait_notify:: Waiter ;
@@ -30,18 +88,24 @@ mod task_queue {
3088 pub ( super ) struct Task {
3189 p : Box < dyn FnOnce ( ) > ,
3290 done : JoinNotifier ,
91+ tcs : Tcs ,
3392 }
3493
3594 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 ) {
3796 let ( done, recv) = wait_notify:: new ( ) ;
3897 let done = JoinNotifier ( Some ( done) ) ;
39- ( Task { p, done } , recv)
98+ let task = Task { p, done, tcs } ;
99+ ( task, recv)
40100 }
41101
42102 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
45109 }
46110 }
47111
@@ -58,6 +122,13 @@ mod task_queue {
58122 TASK_QUEUE . as_ref ( ) . unwrap ( ) . lock ( ) . unwrap ( )
59123 }
60124 }
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+ }
61132}
62133
63134/// This module provides a synchronization primitive that does not use thread
@@ -105,17 +176,17 @@ pub mod wait_notify {
105176impl Thread {
106177 // unsafe: see thread::Builder::spawn_unchecked for safety requirements
107178 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) ;
112184 Ok ( Thread ( handle) )
113185 }
114186
115187 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" ) ;
119190 task. run ( )
120191 }
121192
0 commit comments