@@ -13,7 +13,8 @@ use crate::exception::PhpResult;
1313#[ cfg( php82) ]
1414use crate :: ffi:: zend_atomic_bool_store;
1515use crate :: ffi:: {
16- _sapi_module_struct, _zend_executor_globals, ext_php_rs_executor_globals,
16+ _sapi_module_struct, _zend_executor_globals, _zend_compiler_globals,
17+ ext_php_rs_executor_globals, ext_php_rs_compiler_globals,
1718 ext_php_rs_file_globals, ext_php_rs_process_globals, ext_php_rs_sapi_globals,
1819 ext_php_rs_sapi_module, php_core_globals, php_file_globals, sapi_globals_struct,
1920 sapi_header_struct, sapi_headers_struct, sapi_request_info, zend_ini_entry,
@@ -35,9 +36,6 @@ use super::linked_list::ZendLinkedListIterator;
3536/// Stores global variables used in the PHP executor.
3637pub type ExecutorGlobals = _zend_executor_globals ;
3738
38- /// Stores the SAPI module used in the PHP executor.
39- pub type SapiModule = _sapi_module_struct ;
40-
4139impl ExecutorGlobals {
4240 /// Returns a reference to the PHP executor globals.
4341 ///
@@ -226,6 +224,69 @@ impl ExecutorGlobals {
226224 }
227225}
228226
227+ pub type CompilerGlobals = _zend_compiler_globals ;
228+
229+ impl CompilerGlobals {
230+ /// Returns a reference to the PHP compiler globals.
231+ ///
232+ /// The compiler globals are guarded by a [`RwLock`]. There can be multiple
233+ /// immutable references at one time but only ever one mutable reference.
234+ /// Attempting to retrieve the globals while already holding the global
235+ /// guard will lead to a deadlock. Dropping the globals guard will release
236+ /// the lock.
237+ ///
238+ /// # Panics
239+ ///
240+ /// * If static executor globals are not set
241+ pub fn get ( ) -> GlobalReadGuard < Self > {
242+ // SAFETY: PHP compiler globals are statically declared therefore should never
243+ // return an invalid pointer.
244+ let globals = unsafe { ext_php_rs_compiler_globals ( ) . as_ref ( ) }
245+ . expect ( "Static compiler globals were invalid" ) ;
246+
247+ cfg_if:: cfg_if! {
248+ if #[ cfg( php_zts) ] {
249+ let guard = lock:: GLOBALS_LOCK . with( |l| l. read_arc( ) ) ;
250+ } else {
251+ let guard = lock:: GLOBALS_LOCK . read_arc( ) ;
252+ }
253+ }
254+
255+ GlobalReadGuard { globals, guard }
256+ }
257+
258+ /// Returns a mutable reference to the PHP compiler globals.
259+ ///
260+ /// The compiler globals are guarded by a [`RwLock`]. There can be multiple
261+ /// immutable references at one time but only ever one mutable reference.
262+ /// Attempting to retrieve the globals while already holding the global
263+ /// guard will lead to a deadlock. Dropping the globals guard will release
264+ /// the lock.
265+ ///
266+ /// # Panics
267+ ///
268+ /// * If static compiler globals are not set
269+ pub fn get_mut ( ) -> GlobalWriteGuard < Self > {
270+ // SAFETY: PHP compiler globals are statically declared therefore should never
271+ // return an invalid pointer.
272+ let globals = unsafe { ext_php_rs_compiler_globals ( ) . as_mut ( ) }
273+ . expect ( "Static compiler globals were invalid" ) ;
274+
275+ cfg_if:: cfg_if! {
276+ if #[ cfg( php_zts) ] {
277+ let guard = lock:: GLOBALS_LOCK . with( |l| l. write_arc( ) ) ;
278+ } else {
279+ let guard = lock:: GLOBALS_LOCK . write_arc( ) ;
280+ }
281+ }
282+
283+ GlobalWriteGuard { globals, guard }
284+ }
285+ }
286+
287+ /// Stores the SAPI module used in the PHP executor.
288+ pub type SapiModule = _sapi_module_struct ;
289+
229290impl SapiModule {
230291 /// Returns a reference to the PHP SAPI module.
231292 ///
@@ -839,11 +900,10 @@ impl<T> DerefMut for GlobalWriteGuard<T> {
839900#[ cfg( feature = "embed" ) ]
840901#[ cfg( test) ]
841902mod embed_tests {
903+ use super :: * ;
842904 use crate :: embed:: Embed ;
843905 use std:: os:: raw:: c_char;
844906
845- use super :: SapiHeader ;
846-
847907 #[ test]
848908 fn test_sapi_header ( ) {
849909 Embed :: run ( || {
@@ -867,4 +927,22 @@ mod embed_tests {
867927 }
868928 } ) ;
869929 }
930+
931+ #[ test]
932+ fn test_executor_globals ( ) {
933+ let state = ExecutorGlobals :: get ( ) . active ;
934+ ExecutorGlobals :: get_mut ( ) . active = !state;
935+ let changed = ExecutorGlobals :: get ( ) . active ;
936+ ExecutorGlobals :: get_mut ( ) . active = state;
937+ assert_eq ! ( changed, !state) ;
938+ }
939+
940+ #[ test]
941+ fn test_compiler_globals ( ) {
942+ let state = CompilerGlobals :: get ( ) . in_compilation ;
943+ CompilerGlobals :: get_mut ( ) . in_compilation = !state;
944+ let changed = CompilerGlobals :: get ( ) . in_compilation ;
945+ CompilerGlobals :: get_mut ( ) . in_compilation = state;
946+ assert_eq ! ( changed, !state) ;
947+ }
870948}
0 commit comments