11use super :: unsupported;
2+ use crate :: collections:: HashMap ;
23use crate :: error:: Error as StdError ;
34use crate :: ffi:: { OsStr , OsString } ;
45use crate :: marker:: PhantomData ;
56use crate :: os:: xous:: ffi:: Error as XousError ;
67use crate :: path:: { self , PathBuf } ;
7- use crate :: { fmt, io} ;
8+ use crate :: sync:: atomic:: { AtomicPtr , AtomicUsize , Ordering } ;
9+ use crate :: sync:: { Mutex , Once } ;
10+ use crate :: { fmt, io, vec} ;
11+
12+ pub ( crate ) mod params;
13+
14+ static PARAMS_ADDRESS : AtomicPtr < u8 > = AtomicPtr :: new ( core:: ptr:: null_mut ( ) ) ;
815
916#[ cfg( not( test) ) ]
1017#[ cfg( feature = "panic_unwind" ) ]
1118mod eh_unwinding {
12- pub ( crate ) struct EhFrameFinder ( usize /* eh_frame */ ) ;
13- pub ( crate ) static mut EH_FRAME_SETTINGS : EhFrameFinder = EhFrameFinder ( 0 ) ;
14- impl EhFrameFinder {
15- pub ( crate ) unsafe fn init ( & mut self , eh_frame : usize ) {
16- unsafe {
17- EH_FRAME_SETTINGS . 0 = eh_frame;
18- }
19- }
20- }
19+ pub ( crate ) struct EhFrameFinder ;
20+ pub ( crate ) static mut EH_FRAME_ADDRESS : usize = 0 ;
21+ pub ( crate ) static EH_FRAME_SETTINGS : EhFrameFinder = EhFrameFinder ;
22+
2123 unsafe impl unwind:: EhFrameFinder for EhFrameFinder {
2224 fn find ( & self , _pc : usize ) -> Option < unwind:: FrameInfo > {
23- Some ( unwind:: FrameInfo {
24- text_base : None ,
25- kind : unwind:: FrameInfoKind :: EhFrame ( self . 0 ) ,
26- } )
25+ if unsafe { EH_FRAME_ADDRESS == 0 } {
26+ None
27+ } else {
28+ Some ( unwind:: FrameInfo {
29+ text_base : None ,
30+ kind : unwind:: FrameInfoKind :: EhFrame ( unsafe { EH_FRAME_ADDRESS } ) ,
31+ } )
32+ }
2733 }
2834 }
2935}
@@ -41,12 +47,21 @@ mod c_compat {
4147 }
4248
4349 #[ no_mangle]
44- pub extern "C" fn _start ( eh_frame : usize ) {
50+ pub extern "C" fn _start ( eh_frame : usize , params_address : usize ) {
4551 #[ cfg( feature = "panic_unwind" ) ]
46- unsafe {
47- super :: eh_unwinding:: EH_FRAME_SETTINGS . init ( eh_frame) ;
52+ {
53+ unsafe { super :: eh_unwinding:: EH_FRAME_ADDRESS = eh_frame } ;
4854 unwind:: set_custom_eh_frame_finder ( & super :: eh_unwinding:: EH_FRAME_SETTINGS ) . ok ( ) ;
4955 }
56+
57+ if params_address != 0 {
58+ let params_address = crate :: ptr:: with_exposed_provenance_mut :: < u8 > ( params_address) ;
59+ if unsafe {
60+ super :: params:: ApplicationParameters :: new_from_ptr ( params_address) . is_some ( )
61+ } {
62+ super :: PARAMS_ADDRESS . store ( params_address, core:: sync:: atomic:: Ordering :: Relaxed ) ;
63+ }
64+ }
5065 exit ( unsafe { main ( ) } ) ;
5166 }
5267
@@ -116,44 +131,103 @@ pub fn current_exe() -> io::Result<PathBuf> {
116131 unsupported ( )
117132}
118133
119- pub struct Env ( !) ;
134+ pub ( crate ) fn get_application_parameters ( ) -> Option < params:: ApplicationParameters > {
135+ let params_address = PARAMS_ADDRESS . load ( Ordering :: Relaxed ) ;
136+ unsafe { params:: ApplicationParameters :: new_from_ptr ( params_address) }
137+ }
138+
139+ // ---------- Environment handling ---------- //
140+ static ENV : AtomicUsize = AtomicUsize :: new ( 0 ) ;
141+ static ENV_INIT : Once = Once :: new ( ) ;
142+ type EnvStore = Mutex < HashMap < OsString , OsString > > ;
143+
144+ fn get_env_store ( ) -> & ' static EnvStore {
145+ ENV_INIT . call_once ( || {
146+ let env_store = EnvStore :: default ( ) ;
147+ if let Some ( params) = get_application_parameters ( ) {
148+ for param in params {
149+ if let Ok ( envs) = params:: EnvironmentBlock :: try_from ( & param) {
150+ let mut env_store = env_store. lock ( ) . unwrap ( ) ;
151+ for env in envs {
152+ env_store. insert ( env. key . into ( ) , env. value . into ( ) ) ;
153+ }
154+ break ;
155+ }
156+ }
157+ }
158+ ENV . store ( Box :: into_raw ( Box :: new ( env_store) ) as _ , Ordering :: Relaxed )
159+ } ) ;
160+ unsafe { & * core:: ptr:: with_exposed_provenance :: < EnvStore > ( ENV . load ( Ordering :: Relaxed ) ) }
161+ }
162+
163+ pub struct Env {
164+ iter : vec:: IntoIter < ( OsString , OsString ) > ,
165+ }
166+
167+ // FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt.
168+ pub struct EnvStrDebug < ' a > {
169+ slice : & ' a [ ( OsString , OsString ) ] ,
170+ }
171+
172+ impl fmt:: Debug for EnvStrDebug < ' _ > {
173+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
174+ let Self { slice } = self ;
175+ f. debug_list ( )
176+ . entries ( slice. iter ( ) . map ( |( a, b) | ( a. to_str ( ) . unwrap ( ) , b. to_str ( ) . unwrap ( ) ) ) )
177+ . finish ( )
178+ }
179+ }
120180
121181impl Env {
122182 // FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt.
123183 pub fn str_debug ( & self ) -> impl fmt:: Debug + ' _ {
124- let Self ( inner ) = self ;
125- match * inner { }
184+ let Self { iter } = self ;
185+ EnvStrDebug { slice : iter . as_slice ( ) }
126186 }
127187}
128188
129189impl fmt:: Debug for Env {
130- fn fmt ( & self , _ : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
131- let Self ( inner ) = self ;
132- match * inner { }
190+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
191+ let Self { iter } = self ;
192+ f . debug_list ( ) . entries ( iter . as_slice ( ) ) . finish ( )
133193 }
134194}
135195
196+ impl !Send for Env { }
197+ impl !Sync for Env { }
198+
136199impl Iterator for Env {
137200 type Item = ( OsString , OsString ) ;
138201 fn next ( & mut self ) -> Option < ( OsString , OsString ) > {
139- self . 0
202+ self . iter . next ( )
203+ }
204+ fn size_hint ( & self ) -> ( usize , Option < usize > ) {
205+ self . iter . size_hint ( )
140206 }
141207}
142208
143209pub fn env ( ) -> Env {
144- panic ! ( "not supported on this platform" )
210+ let clone_to_vec = |map : & HashMap < OsString , OsString > | -> Vec < _ > {
211+ map. iter ( ) . map ( |( k, v) | ( k. clone ( ) , v. clone ( ) ) ) . collect ( )
212+ } ;
213+
214+ let iter = clone_to_vec ( & * get_env_store ( ) . lock ( ) . unwrap ( ) ) . into_iter ( ) ;
215+ Env { iter }
145216}
146217
147- pub fn getenv ( _ : & OsStr ) -> Option < OsString > {
148- None
218+ pub fn getenv ( k : & OsStr ) -> Option < OsString > {
219+ get_env_store ( ) . lock ( ) . unwrap ( ) . get ( k ) . cloned ( )
149220}
150221
151- pub unsafe fn setenv ( _: & OsStr , _: & OsStr ) -> io:: Result < ( ) > {
152- Err ( io:: const_io_error!( io:: ErrorKind :: Unsupported , "cannot set env vars on this platform" ) )
222+ pub unsafe fn setenv ( k : & OsStr , v : & OsStr ) -> io:: Result < ( ) > {
223+ let ( k, v) = ( k. to_owned ( ) , v. to_owned ( ) ) ;
224+ get_env_store ( ) . lock ( ) . unwrap ( ) . insert ( k, v) ;
225+ Ok ( ( ) )
153226}
154227
155- pub unsafe fn unsetenv ( _: & OsStr ) -> io:: Result < ( ) > {
156- Err ( io:: const_io_error!( io:: ErrorKind :: Unsupported , "cannot unset env vars on this platform" ) )
228+ pub unsafe fn unsetenv ( k : & OsStr ) -> io:: Result < ( ) > {
229+ get_env_store ( ) . lock ( ) . unwrap ( ) . remove ( k) ;
230+ Ok ( ( ) )
157231}
158232
159233pub fn temp_dir ( ) -> PathBuf {
0 commit comments