@@ -27,8 +27,8 @@ use std::boxed::FnBox;
2727use std:: cell:: UnsafeCell ;
2828use std:: io;
2929use std:: mem;
30- use std:: sync :: Arc ;
31- use std:: sync:: mpsc:: { self , Sender , Receiver } ;
30+ use std:: ptr ;
31+ use std:: sync:: mpsc:: { self , Receiver , Sender } ;
3232use std:: thread:: { self , Builder } ;
3333use std:: time:: Duration ;
3434
@@ -40,14 +40,23 @@ use coroutine::{self, Coroutine, State, Handle, SendableCoroutinePtr};
4040use options:: Options ;
4141use scheduler:: Scheduler ;
4242
43- thread_local ! ( static PROCESSOR : UnsafeCell <Option <Processor >> = UnsafeCell :: new( None ) ) ;
43+ // TODO:
44+ // Reconsider making PROCESSOR a static object instead of a pointer.
45+ // This would simplify storage of Processor and improve performance of Processor::current()
46+ // Blockers:
47+ // - std::thread::LocalKeyState is unstable (to avoid triggering the lazy init.).
48+ // - Investigate if LLVM generates dynamic or non-dynamic ELF TLS.
49+ // "dynamic" TLS is allocated lazily at first access of the store (which is what we want)
50+ // instead of being allocated statically for every thread.
51+ // ELF TLS Paper: "ELF Handling For Thread-Local Storage".
52+ thread_local ! ( static PROCESSOR : UnsafeCell <* mut Processor > = UnsafeCell :: new( ptr:: null_mut( ) ) ) ;
4453
4554#[ derive( Debug ) ]
4655pub struct ForceUnwind ;
4756
4857/// Processing unit of a thread
4958pub struct Processor {
50- scheduler : Arc < Scheduler > ,
59+ scheduler : * mut Scheduler ,
5160
5261 main_coro : Handle ,
5362 cur_running : Option < * mut Coroutine > ,
@@ -70,7 +79,7 @@ unsafe impl Send for Processor {}
7079
7180impl Processor {
7281 fn new_with_neighbors ( _processor_id : usize ,
73- sched : Arc < Scheduler > ,
82+ sched : * mut Scheduler ,
7483 neigh : Vec < Stealer < SendableCoroutinePtr > > )
7584 -> Processor {
7685 let main_coro = unsafe { Coroutine :: empty ( ) } ;
@@ -99,28 +108,37 @@ impl Processor {
99108 }
100109 }
101110
102- fn set_and_get_tls ( p : Processor ) -> & ' static mut Processor {
103- PROCESSOR . with ( move |proc_opt| unsafe {
104- * proc_opt. get ( ) = Some ( p) ;
105- ( * proc_opt. get ( ) ) . as_mut ( ) . unwrap ( )
111+ fn set_tls ( p : & mut Processor ) {
112+ PROCESSOR . with ( |proc_opt| unsafe {
113+ * proc_opt. get ( ) = p;
114+ } )
115+ }
116+
117+ fn unset_tls ( ) {
118+ PROCESSOR . with ( |proc_opt| unsafe {
119+ * proc_opt. get ( ) = ptr:: null_mut ( ) ;
106120 } )
107121 }
108122
109123 #[ inline]
110124 pub fn run_with_neighbors ( processor_id : usize ,
111- sched : Arc < Scheduler > ,
125+ sched : * mut Scheduler ,
112126 neigh : Vec < Stealer < SendableCoroutinePtr > > )
113127 -> ( thread:: JoinHandle < ( ) > ,
114128 Sender < ProcMessage > ,
115129 Stealer < SendableCoroutinePtr > ) {
116- let p = Processor :: new_with_neighbors ( processor_id, sched, neigh) ;
130+ let mut p = Processor :: new_with_neighbors ( processor_id, sched, neigh) ;
117131 let msg = p. handle ( ) ;
118132 let st = p. stealer ( ) ;
133+
119134 let hdl = Builder :: new ( )
120135 . name ( format ! ( "Processor #{}" , processor_id) )
121136 . spawn ( move || {
122- let mut p = Processor :: set_and_get_tls ( p) ;
123- if let Err ( err) = p. schedule ( ) {
137+ Processor :: set_tls ( & mut p) ;
138+ let err = p. schedule ( ) ;
139+ Processor :: unset_tls ( ) ;
140+
141+ if let Err ( err) = err {
124142 panic ! ( "Processor::schedule return Err: {:?}" , err) ;
125143 }
126144 } )
@@ -131,7 +149,7 @@ impl Processor {
131149
132150 #[ inline]
133151 pub fn run_main < M , T > ( processor_id : usize ,
134- sched : Arc < Scheduler > ,
152+ sched : * mut Scheduler ,
135153 f : M )
136154 -> ( thread:: JoinHandle < ( ) > ,
137155 Sender < ProcMessage > ,
@@ -140,35 +158,49 @@ impl Processor {
140158 where M : FnOnce ( ) -> T + Send + ' static ,
141159 T : Send + ' static
142160 {
143- let p = Processor :: new_with_neighbors ( processor_id, sched, Vec :: new ( ) ) ;
161+ let mut p = Processor :: new_with_neighbors ( processor_id, sched, Vec :: new ( ) ) ;
144162 let ( msg, st) = ( p. handle ( ) , p. stealer ( ) ) ;
145163 let ( tx, rx) = :: std:: sync:: mpsc:: channel ( ) ;
146- let hdl = Builder :: new ( ) . name ( format ! ( "Processor #{}" , processor_id) ) . spawn ( move || {
147- let mut p = Processor :: set_and_get_tls ( p) ;
148- let wrapper = move || {
149- let ret = unsafe { :: try ( move || f ( ) ) } ;
164+
165+ let hdl = Builder :: new ( ) . name ( format ! ( "Processor #{}" , processor_id) ) . spawn ( move || {
166+ Processor :: set_tls ( & mut p) ;
167+
168+ let wrapper = move || {
169+ let ret = unsafe { :: try ( move || f ( ) ) } ;
150170
151171 // No matter whether it is panicked or not, the result will be sent to the channel
152172 let _ = tx. send ( ret) ; // Just ignore if it failed
153173 } ;
154174 p. spawn_opts ( Box :: new ( wrapper) , Options :: default ( ) ) ;
155175
156- if let Err ( err) = p. schedule ( ) {
176+ let err = p. schedule ( ) ;
177+ Processor :: unset_tls ( ) ;
178+
179+ if let Err ( err) = err {
157180 panic ! ( "Processor::schedule return Err: {:?}" , err) ;
158181 }
159182 } ) . unwrap ( ) ;
183+
160184 ( hdl, msg, st, rx)
161185 }
162186
163187 #[ inline]
164188 pub fn scheduler ( & self ) -> & Scheduler {
165- & * self . scheduler
189+ unsafe { & * self . scheduler }
166190 }
167191
168192 /// Get the thread local processor
169193 #[ inline]
170194 pub fn current ( ) -> Option < & ' static mut Processor > {
171- PROCESSOR . with ( |proc_opt| unsafe { ( * proc_opt. get ( ) ) . as_mut ( ) } )
195+ PROCESSOR . with ( |proc_opt| unsafe {
196+ let p: * mut Processor = * proc_opt. get ( ) ;
197+
198+ if p. is_null ( ) {
199+ None
200+ } else {
201+ Some ( & mut * p)
202+ }
203+ } )
172204 }
173205
174206 #[ inline]
0 commit comments