@@ -10,6 +10,7 @@ use crate::boxed::ZBox;
1010use crate :: ffi:: zend_atomic_bool_store;
1111use crate :: ffi:: {
1212 _sapi_globals_struct, _zend_executor_globals, ext_php_rs_executor_globals,
13+ _sapi_module_struct, ext_php_rs_sapi_module,
1314 ext_php_rs_sapi_globals, zend_ini_entry,
1415} ;
1516use crate :: types:: { ZendHashTable , ZendObject } ;
@@ -20,6 +21,9 @@ pub type ExecutorGlobals = _zend_executor_globals;
2021/// Stores global SAPI variables used in the PHP executor.
2122pub type SapiGlobals = _sapi_globals_struct ;
2223
24+ /// Stores the SAPI module used in the PHP executor.
25+ pub type SapiModule = _sapi_module_struct ;
26+
2327impl ExecutorGlobals {
2428 /// Returns a reference to the PHP executor globals.
2529 ///
@@ -167,6 +171,40 @@ impl SapiGlobals {
167171 }
168172}
169173
174+ impl SapiModule {
175+ /// Returns a reference to the PHP SAPI module.
176+ ///
177+ /// The executor globals are guarded by a RwLock. There can be multiple
178+ /// immutable references at one time but only ever one mutable reference.
179+ /// Attempting to retrieve the globals while already holding the global
180+ /// guard will lead to a deadlock. Dropping the globals guard will release
181+ /// the lock.
182+ pub fn get ( ) -> GlobalReadGuard < Self > {
183+ // SAFETY: PHP executor globals are statically declared therefore should never
184+ // return an invalid pointer.
185+ let globals = unsafe { ext_php_rs_sapi_module ( ) . as_ref ( ) }
186+ . expect ( "Static executor globals were invalid" ) ;
187+ let guard = SAPI_MODULE_LOCK . read ( ) ;
188+ GlobalReadGuard { globals, guard }
189+ }
190+
191+ /// Returns a mutable reference to the PHP executor globals.
192+ ///
193+ /// The executor globals are guarded by a RwLock. There can be multiple
194+ /// immutable references at one time but only ever one mutable reference.
195+ /// Attempting to retrieve the globals while already holding the global
196+ /// guard will lead to a deadlock. Dropping the globals guard will release
197+ /// the lock.
198+ pub fn get_mut ( ) -> GlobalWriteGuard < Self > {
199+ // SAFETY: PHP executor globals are statically declared therefore should never
200+ // return an invalid pointer.
201+ let globals = unsafe { ext_php_rs_sapi_module ( ) . as_mut ( ) }
202+ . expect ( "Static executor globals were invalid" ) ;
203+ let guard = SAPI_MODULE_LOCK . write ( ) ;
204+ GlobalWriteGuard { globals, guard }
205+ }
206+ }
207+
170208/// Executor globals rwlock.
171209///
172210/// PHP provides no indication if the executor globals are being accessed so
@@ -179,6 +217,12 @@ static GLOBALS_LOCK: RwLock<()> = const_rwlock(());
179217/// this is only effective on the Rust side.
180218static SAPI_LOCK : RwLock < ( ) > = const_rwlock ( ( ) ) ;
181219
220+ /// SAPI globals rwlock.
221+ ///
222+ /// PHP provides no indication if the executor globals are being accessed so
223+ /// this is only effective on the Rust side.
224+ static SAPI_MODULE_LOCK : RwLock < ( ) > = const_rwlock ( ( ) ) ;
225+
182226/// Wrapper guard that contains a reference to a given type `T`. Dropping a
183227/// guard releases the lock on the relevant rwlock.
184228pub struct GlobalReadGuard < T : ' static > {
0 commit comments