@@ -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