@@ -8,19 +8,36 @@ use crate::bindings::{
88} ;
99use crate :: zend:: zai_str_from_zstr;
1010use core:: fmt:: { Display , Formatter } ;
11- use core:: mem:: { swap , transmute, MaybeUninit } ;
11+ use core:: mem:: transmute;
1212use core:: ptr;
1313use core:: str:: FromStr ;
1414use libc:: { c_char, c_int} ;
1515use libdd_common:: tag:: { parse_tags, Tag } ;
1616pub use libdd_profiling:: exporter:: Uri ;
17- use log:: { warn, LevelFilter } ;
17+ use log:: { debug , warn, LevelFilter } ;
1818use std:: borrow:: Cow ;
1919use std:: ffi:: CString ;
2020use std:: path:: { Path , PathBuf } ;
2121
22+ #[ derive( Copy , Clone , Debug , Default ) ]
23+ pub enum SystemSettingsState {
24+ /// Indicates the system settings are not aware of the configuration at
25+ /// the moment.
26+ #[ default]
27+ ConfigUnaware ,
28+
29+ /// Indicates the system settings _are_ aware of configuration at the
30+ /// moment.
31+ ConfigAware ,
32+
33+ /// Expressly disabled, such as a child process post-fork (forks are not
34+ /// currently profiled, except certain forks made by SAPIs).
35+ Disabled ,
36+ }
37+
2238#[ derive( Clone , Debug ) ]
2339pub struct SystemSettings {
40+ pub state : SystemSettingsState ,
2441 pub profiling_enabled : bool ,
2542 pub profiling_experimental_features_enabled : bool ,
2643 pub profiling_endpoint_collection_enabled : bool ,
@@ -41,16 +58,26 @@ pub struct SystemSettings {
4158}
4259
4360impl SystemSettings {
44- pub fn disable_all ( & mut self ) {
45- self . profiling_enabled = false ;
46- self . profiling_experimental_features_enabled = false ;
47- self . profiling_endpoint_collection_enabled = false ;
48- self . profiling_experimental_cpu_time_enabled = false ;
49- self . profiling_allocation_enabled = false ;
50- self . profiling_timeline_enabled = false ;
51- self . profiling_exception_enabled = false ;
52- self . profiling_exception_message_enabled = false ;
53- self . profiling_io_enabled = false ;
61+ /// Provides "initial" settings, which are all "off"-like values.
62+ pub const fn initial ( ) -> SystemSettings {
63+ SystemSettings {
64+ state : SystemSettingsState :: ConfigUnaware ,
65+ profiling_enabled : false ,
66+ profiling_experimental_features_enabled : false ,
67+ profiling_endpoint_collection_enabled : false ,
68+ profiling_experimental_cpu_time_enabled : false ,
69+ profiling_allocation_enabled : false ,
70+ profiling_allocation_sampling_distance : u32:: MAX ,
71+ profiling_timeline_enabled : false ,
72+ profiling_exception_enabled : false ,
73+ profiling_exception_message_enabled : false ,
74+ profiling_wall_time_enabled : false ,
75+ profiling_io_enabled : false ,
76+ output_pprof : None ,
77+ profiling_exception_sampling_distance : u32:: MAX ,
78+ profiling_log_level : LevelFilter :: Off ,
79+ uri : AgentEndpoint :: Socket ( Cow :: Borrowed ( AgentEndpoint :: DEFAULT_UNIX_SOCKET_PATH ) ) ,
80+ }
5481 }
5582
5683 /// # Safety
@@ -64,6 +91,7 @@ impl SystemSettings {
6491 let trace_agent_url = trace_agent_url ( ) ;
6592 let uri = detect_uri_from_config ( trace_agent_url, agent_host, trace_agent_port) ;
6693 Self {
94+ state : SystemSettingsState :: ConfigAware ,
6795 profiling_enabled : profiling_enabled ( ) ,
6896 profiling_experimental_features_enabled : profiling_experimental_features_enabled ( ) ,
6997 profiling_endpoint_collection_enabled : profiling_endpoint_collection_enabled ( ) ,
@@ -83,15 +111,16 @@ impl SystemSettings {
83111 }
84112}
85113
86- static mut SYSTEM_SETTINGS : MaybeUninit < SystemSettings > = MaybeUninit :: uninit ( ) ;
114+ static mut SYSTEM_SETTINGS : SystemSettings = SystemSettings :: initial ( ) ;
87115
88116impl SystemSettings {
89- /// # Safety
90- /// Must be called after [first_rinit] and before [shutdown].
91- pub unsafe fn get ( ) -> ptr:: NonNull < SystemSettings > {
92- // SAFETY: required by this function's own safety requirements.
93- let addr = unsafe { ( * ptr:: addr_of_mut!( SYSTEM_SETTINGS ) ) . assume_init_mut ( ) } ;
94- ptr:: NonNull :: from ( addr)
117+ /// Returns the "current" system settings, which are always memory-safe
118+ /// but may point to "initial" values rather than the configured ones,
119+ /// depending on what point in the lifecycle we're at.
120+ pub const fn get ( ) -> ptr:: NonNull < SystemSettings > {
121+ let addr = ptr:: addr_of_mut!( SYSTEM_SETTINGS ) ;
122+ // SAFETY: it's derived from a static variable, it's not null.
123+ unsafe { ptr:: NonNull :: new_unchecked ( addr) }
95124 }
96125
97126 /// # Safety
@@ -110,10 +139,6 @@ impl SystemSettings {
110139 }
111140 }
112141
113- // Initialize the lazy lock holding the env var for new origin
114- // detection in a safe place.
115- _ = std:: sync:: LazyLock :: force ( & libdd_common:: entity_id:: DD_EXTERNAL_ENV ) ;
116-
117142 // Work around version-specific issues.
118143 #[ cfg( not( php_zend_mm_set_custom_handlers_ex) ) ]
119144 if allocation:: allocation_le83:: first_rinit_should_disable_due_to_jit ( ) {
@@ -123,54 +148,48 @@ impl SystemSettings {
123148 if allocation:: allocation_ge84:: first_rinit_should_disable_due_to_jit ( ) {
124149 system_settings. profiling_allocation_enabled = false ;
125150 }
126- swap (
127- & mut system_settings,
128- ( * ptr:: addr_of_mut!( SYSTEM_SETTINGS ) ) . assume_init_mut ( ) ,
151+
152+ SystemSettings :: log_state (
153+ ( * ptr:: addr_of!( SYSTEM_SETTINGS ) ) . state ,
154+ system_settings. state ,
155+ "the first request was received" ,
129156 ) ;
157+ ptr:: addr_of_mut!( SYSTEM_SETTINGS ) . swap ( & mut system_settings) ;
130158 }
131159
132- /// # Safety
133- /// Must be called exactly once each startup in either minit or startup,
134- /// whether profiling is enabled or not.
135- unsafe fn on_startup ( ) {
136- ( * ptr:: addr_of_mut!( SYSTEM_SETTINGS ) ) . write ( INITIAL_SYSTEM_SETTINGS . clone ( ) ) ;
160+ fn log_state ( from : SystemSettingsState , to : SystemSettingsState , reason : & str ) {
161+ debug ! ( "SystemSettings state transitioned from {from:?} to {to:?} because {reason}." ) ;
137162 }
138163
139164 /// # Safety
140165 /// Must be called exactly once per shutdown in either mshutdown or
141166 /// shutdown, before zai config is shutdown.
142167 unsafe fn on_shutdown ( ) {
143- let system_settings = ( * ptr:: addr_of_mut!( SYSTEM_SETTINGS ) ) . assume_init_mut ( ) ;
168+ let system_settings = & mut * ptr:: addr_of_mut!( SYSTEM_SETTINGS ) ;
169+ let state = SystemSettingsState :: ConfigUnaware ;
170+ SystemSettings :: log_state (
171+ system_settings. state ,
172+ state,
173+ "a shutdown command was received" ,
174+ ) ;
144175 * system_settings = SystemSettings {
145- profiling_enabled : false ,
146- profiling_experimental_features_enabled : false ,
147- profiling_endpoint_collection_enabled : false ,
148- profiling_experimental_cpu_time_enabled : false ,
149- profiling_allocation_enabled : false ,
150- profiling_allocation_sampling_distance : 0 ,
151- profiling_timeline_enabled : false ,
152- profiling_exception_enabled : false ,
153- profiling_exception_message_enabled : false ,
154- profiling_wall_time_enabled : false ,
155- profiling_io_enabled : false ,
156- output_pprof : None ,
157- profiling_exception_sampling_distance : 0 ,
158- profiling_log_level : LevelFilter :: Off ,
159- uri : Default :: default ( ) ,
176+ state,
177+ ..SystemSettings :: initial ( )
160178 } ;
161179 }
162180
163181 unsafe fn on_fork_in_child ( ) {
164- let system_settings = ( * ptr:: addr_of_mut!( SYSTEM_SETTINGS ) ) . assume_init_mut ( ) ;
165- system_settings. profiling_enabled = false ;
166- system_settings. profiling_experimental_features_enabled = false ;
167- system_settings. profiling_endpoint_collection_enabled = false ;
168- system_settings. profiling_experimental_cpu_time_enabled = false ;
169- system_settings. profiling_allocation_enabled = false ;
170- system_settings. profiling_timeline_enabled = false ;
171- system_settings. profiling_exception_enabled = false ;
172- system_settings. profiling_exception_message_enabled = false ;
173- system_settings. profiling_io_enabled = false ;
182+ let system_settings = & mut * ptr:: addr_of_mut!( SYSTEM_SETTINGS ) ;
183+ let state = SystemSettingsState :: Disabled ;
184+ SystemSettings :: log_state (
185+ system_settings. state ,
186+ state,
187+ "the processed forked, and child processes are not profiled" ,
188+ ) ;
189+ * system_settings = SystemSettings {
190+ state,
191+ ..SystemSettings :: initial ( )
192+ } ;
174193 }
175194}
176195
@@ -448,55 +467,25 @@ impl ConfigId {
448467 }
449468}
450469
451- lazy_static:: lazy_static! {
452- /// In some SAPIs, full configuration is not known until the first request
453- /// is served. This is ripe for edge cases. Consider this order of events:
454- /// 1. Worker is created.
455- /// 2. No requests are served.
456- /// 3. As the worker shuts down, the timeline profiler will attempt to
457- /// add idle time to timeline.
458- /// What state should the configuration be in?
459- ///
460- /// Since the real configuration was never learned, assume everything is
461- /// disabled, which should cause fewer issues for customers than assuming
462- /// defaults.
463- pub static ref INITIAL_SYSTEM_SETTINGS : SystemSettings = SystemSettings {
464- profiling_enabled: false ,
465- profiling_experimental_features_enabled: false ,
466- profiling_endpoint_collection_enabled: false ,
467- profiling_experimental_cpu_time_enabled: false ,
468- profiling_allocation_enabled: false ,
469- profiling_allocation_sampling_distance: u32 :: MAX ,
470- profiling_timeline_enabled: false ,
471- profiling_exception_enabled: false ,
472- profiling_exception_message_enabled: false ,
473- profiling_wall_time_enabled: false ,
474- profiling_io_enabled: false ,
475- output_pprof: None ,
476- profiling_exception_sampling_distance: u32 :: MAX ,
477- profiling_log_level: LevelFilter :: Off ,
478- uri: Default :: default ( ) ,
479- } ;
480-
481- /// Keep these in sync with the INI defaults.
482- static ref DEFAULT_SYSTEM_SETTINGS : SystemSettings = SystemSettings {
483- profiling_enabled: true ,
484- profiling_experimental_features_enabled: false ,
485- profiling_endpoint_collection_enabled: true ,
486- profiling_experimental_cpu_time_enabled: true ,
487- profiling_allocation_enabled: true ,
488- profiling_allocation_sampling_distance: 1024 * 4096 ,
489- profiling_timeline_enabled: true ,
490- profiling_exception_enabled: true ,
491- profiling_exception_message_enabled: false ,
492- profiling_wall_time_enabled: true ,
493- profiling_io_enabled: false ,
494- output_pprof: None ,
495- profiling_exception_sampling_distance: 100 ,
496- profiling_log_level: LevelFilter :: Off ,
497- uri: Default :: default ( ) ,
498- } ;
499- }
470+ /// Keep these in sync with the INI defaults.
471+ static DEFAULT_SYSTEM_SETTINGS : SystemSettings = SystemSettings {
472+ state : SystemSettingsState :: ConfigUnaware ,
473+ profiling_enabled : true ,
474+ profiling_experimental_features_enabled : false ,
475+ profiling_endpoint_collection_enabled : true ,
476+ profiling_experimental_cpu_time_enabled : true ,
477+ profiling_allocation_enabled : true ,
478+ profiling_allocation_sampling_distance : 1024 * 4096 ,
479+ profiling_timeline_enabled : true ,
480+ profiling_exception_enabled : true ,
481+ profiling_exception_message_enabled : false ,
482+ profiling_wall_time_enabled : true ,
483+ profiling_io_enabled : false ,
484+ output_pprof : None ,
485+ profiling_exception_sampling_distance : 100 ,
486+ profiling_log_level : LevelFilter :: Off ,
487+ uri : AgentEndpoint :: Socket ( Cow :: Borrowed ( AgentEndpoint :: DEFAULT_UNIX_SOCKET_PATH ) ) ,
488+ } ;
500489
501490/// # Safety
502491/// This function must only be called after config has been initialized in
@@ -1244,7 +1233,8 @@ pub(crate) fn minit(module_number: libc::c_int) {
12441233 ) ;
12451234 assert ! ( tmp) ; // It's literally return true in the source.
12461235
1247- SystemSettings :: on_startup ( ) ;
1236+ let system_settings = & mut * ptr:: addr_of_mut!( SYSTEM_SETTINGS ) ;
1237+ * system_settings = SystemSettings :: initial ( ) ;
12481238 }
12491239}
12501240
@@ -1268,6 +1258,7 @@ pub(crate) unsafe fn on_fork_in_child() {
12681258#[ cfg( test) ]
12691259mod tests {
12701260 use super :: * ;
1261+ use core:: mem:: MaybeUninit ;
12711262 use libc:: memcmp;
12721263
12731264 #[ test]
0 commit comments