@@ -2,6 +2,7 @@ use crate::allocation;
22use core:: cell:: Cell ;
33use core:: ffi:: c_void;
44use core:: ptr;
5+ use core:: sync:: atomic:: AtomicU32 ;
56
67#[ cfg( php_zend_mm_set_custom_handlers_ex) ]
78use crate :: allocation:: allocation_ge84:: ZendMMState ;
@@ -13,6 +14,12 @@ pub struct ProfilerGlobals {
1314 /// Wrapped in `Cell` to prevent torn reads/writes when allocation hooks
1415 /// are called re-entrantly during `rinit()`/`rshutdown()`.
1516 pub zend_mm_state : Cell < ZendMMState > ,
17+ /// Number of profiler time interrupts pending for this PHP thread.
18+ ///
19+ /// The profiler timer thread updates this through a pointer registered by
20+ /// the PHP thread, so the value must remain atomic despite living in
21+ /// thread-local PHP module globals.
22+ pub interrupt_count : AtomicU32 ,
1623}
1724
1825/// We need TSRM to call into GINIT and GSHUTDOWN to observe spawning and
@@ -29,6 +36,7 @@ pub static mut GLOBALS_ID: i32 = 0;
2936#[ cfg( not( php_zts) ) ]
3037pub static mut GLOBALS : ProfilerGlobals = ProfilerGlobals {
3138 zend_mm_state : Cell :: new ( ZendMMState :: new ( ) ) ,
39+ interrupt_count : AtomicU32 :: new ( 0 ) ,
3240} ;
3341
3442#[ cfg( php_zts) ]
@@ -40,9 +48,13 @@ mod zts {
4048 }
4149
4250 #[ inline]
43- pub unsafe fn tsrmg_bulk ( id : i32 ) -> * mut c_void {
44- let tls = tsrm_get_ls_cache ( ) as * mut * mut * mut c_void ;
45- let storage = * tls; // void** storage
51+ pub unsafe fn get_ls_cache ( ) -> * mut c_void {
52+ tsrm_get_ls_cache ( )
53+ }
54+
55+ #[ inline]
56+ pub unsafe fn tsrmg_bulk ( ls_cache : * mut c_void , id : i32 ) -> * mut c_void {
57+ let storage = * ( ls_cache as * mut * mut * mut c_void ) ; // void** storage
4658
4759 // TSRM_UNSHUFFLE_RSRC_ID(id) is just `id - 1`.
4860 let idx = ( id - 1 ) as usize ;
@@ -51,6 +63,27 @@ mod zts {
5163 }
5264}
5365
66+ #[ cfg( php_zts) ]
67+ #[ inline]
68+ pub unsafe fn get_tsrm_ls_cache ( ) -> * mut c_void {
69+ zts:: get_ls_cache ( )
70+ }
71+
72+ #[ cfg( php_zts) ]
73+ #[ inline]
74+ pub unsafe fn get_tsrm_resource_from_cache ( ls_cache : * mut c_void , id : i32 ) -> * mut c_void {
75+ zts:: tsrmg_bulk ( ls_cache, id)
76+ }
77+
78+ #[ cfg( php_zts) ]
79+ #[ inline]
80+ pub unsafe fn get_profiler_globals_from_cache ( ls_cache : * mut c_void ) -> * mut ProfilerGlobals {
81+ // SAFETY: As long as this is called during the times documented by
82+ // get_profiler_globals(), GLOBALS_ID will be set by PHP.
83+ let id = ptr:: addr_of!( GLOBALS_ID ) . read ( ) ;
84+ get_tsrm_resource_from_cache ( ls_cache, id) . cast ( )
85+ }
86+
5487/// Returns a pointer to the profiler globals for the current thread.
5588///
5689/// # Safety
@@ -64,10 +97,7 @@ mod zts {
6497pub unsafe fn get_profiler_globals ( ) -> * mut ProfilerGlobals {
6598 #[ cfg( php_zts) ]
6699 {
67- // SAFETY: As long as this is called during the times documented by
68- // our own safety requirements, GLOBALS_ID will be set by PHP.
69- let id = ptr:: addr_of!( GLOBALS_ID ) . read ( ) ;
70- zts:: tsrmg_bulk ( id) . cast ( )
100+ get_profiler_globals_from_cache ( get_tsrm_ls_cache ( ) )
71101 }
72102
73103 #[ cfg( not( php_zts) ) ]
@@ -85,12 +115,13 @@ pub unsafe extern "C" fn ginit(_globals_ptr: *mut c_void) {
85115 #[ cfg( php_zts) ]
86116 crate :: timeline:: timeline_ginit ( ) ;
87117
88- // Initialize ZendMMState in PHP globals for ZTS builds. For NTS builds,
89- // this was already done in its const initializer.
118+ // Initialize PHP globals for ZTS builds. For NTS builds, this was already
119+ // done in its const initializer.
90120 #[ cfg( php_zts) ]
91121 {
92122 let globals = _globals_ptr. cast :: < ProfilerGlobals > ( ) ;
93123 ( * globals) . zend_mm_state = Cell :: new ( ZendMMState :: new ( ) ) ;
124+ ( * globals) . interrupt_count = AtomicU32 :: new ( 0 ) ;
94125 }
95126
96127 // SAFETY: this is called in thread ginit as expected, and no other places.
@@ -113,3 +144,19 @@ pub unsafe extern "C" fn gshutdown(_globals_ptr: *mut c_void) {
113144 // SAFETY: this is called in thread gshutdown as expected, no other places.
114145 allocation:: gshutdown ( ) ;
115146}
147+
148+ // Unit tests are not loaded by PHP, so provide the PHP globals and TSRM symbol
149+ // needed to link code retained in the test executable.
150+ #[ cfg( test) ]
151+ mod test_symbols {
152+ #[ cfg( not( php_zts) ) ]
153+ #[ export_name = "compiler_globals" ]
154+ static mut TEST_COMPILER_GLOBALS : core:: mem:: MaybeUninit < crate :: zend:: zend_compiler_globals > =
155+ core:: mem:: MaybeUninit :: zeroed ( ) ;
156+
157+ #[ cfg( php_zts) ]
158+ #[ no_mangle]
159+ unsafe extern "C" fn tsrm_get_ls_cache ( ) -> * mut core:: ffi:: c_void {
160+ core:: ptr:: null_mut ( )
161+ }
162+ }
0 commit comments