@@ -4,12 +4,12 @@ use crate::zend::{
4
4
InternalFunctionHandler ,
5
5
} ;
6
6
use crate :: REQUEST_LOCALS ;
7
+ use ddcommon:: cstr;
7
8
use libc:: c_char;
8
9
use log:: { error, trace} ;
9
10
#[ cfg( php_zts) ]
10
11
use std:: cell:: Cell ;
11
12
use std:: cell:: RefCell ;
12
- use std:: ffi:: CStr ;
13
13
use std:: ptr;
14
14
use std:: time:: Instant ;
15
15
use std:: time:: SystemTime ;
@@ -24,12 +24,6 @@ static mut PREV_ZEND_COMPILE_STRING: Option<zend::VmZendCompileString> = None;
24
24
/// The engine's original (or neighbouring extensions) `zend_compile_file()` function
25
25
static mut PREV_ZEND_COMPILE_FILE : Option < zend:: VmZendCompileFile > = None ;
26
26
27
- static mut SLEEP_HANDLER : InternalFunctionHandler = None ;
28
- static mut USLEEP_HANDLER : InternalFunctionHandler = None ;
29
- static mut TIME_NANOSLEEP_HANDLER : InternalFunctionHandler = None ;
30
- static mut TIME_SLEEP_UNTIL_HANDLER : InternalFunctionHandler = None ;
31
- static mut FRANKENPHP_HANDLE_REQUEST_HANDLER : InternalFunctionHandler = None ;
32
-
33
27
thread_local ! {
34
28
static IDLE_SINCE : RefCell <Instant > = RefCell :: new( Instant :: now( ) ) ;
35
29
#[ cfg( php_zts) ]
@@ -39,6 +33,7 @@ thread_local! {
39
33
enum State {
40
34
Idle ,
41
35
Sleeping ,
36
+ Select ,
42
37
#[ cfg( php_zts) ]
43
38
ThreadStart ,
44
39
#[ cfg( php_zts) ]
@@ -50,6 +45,7 @@ impl State {
50
45
match self {
51
46
State :: Idle => "idle" ,
52
47
State :: Sleeping => "sleeping" ,
48
+ State :: Select => "select" ,
53
49
#[ cfg( php_zts) ]
54
50
State :: ThreadStart => "thread start" ,
55
51
#[ cfg( php_zts) ]
@@ -101,60 +97,40 @@ fn sleeping_fn(
101
97
}
102
98
}
103
99
104
- /// Wrapping the PHP `sleep()` function to take the time it is blocking the current thread
105
- #[ no_mangle]
106
- unsafe extern "C" fn ddog_php_prof_sleep (
107
- execute_data : * mut zend_execute_data ,
108
- return_value : * mut zval ,
109
- ) {
110
- if let Some ( func) = SLEEP_HANDLER {
111
- sleeping_fn ( func, execute_data, return_value, State :: Sleeping )
112
- }
113
- }
114
-
115
- /// Wrapping the PHP `usleep()` function to take the time it is blocking the current thread
116
- #[ no_mangle]
117
- unsafe extern "C" fn ddog_php_prof_usleep (
118
- execute_data : * mut zend_execute_data ,
119
- return_value : * mut zval ,
120
- ) {
121
- if let Some ( func) = USLEEP_HANDLER {
122
- sleeping_fn ( func, execute_data, return_value, State :: Sleeping )
123
- }
124
- }
125
-
126
- /// Wrapping the PHP `time_nanosleep()` function to take the time it is blocking the current thread
127
- #[ no_mangle]
128
- unsafe extern "C" fn ddog_php_prof_time_nanosleep (
129
- execute_data : * mut zend_execute_data ,
130
- return_value : * mut zval ,
131
- ) {
132
- if let Some ( func) = TIME_NANOSLEEP_HANDLER {
133
- sleeping_fn ( func, execute_data, return_value, State :: Sleeping )
134
- }
135
- }
136
-
137
- /// Wrapping the PHP `time_sleep_until()` function to take the time it is blocking the current thread
138
- #[ no_mangle]
139
- unsafe extern "C" fn ddog_php_prof_time_sleep_until (
140
- execute_data : * mut zend_execute_data ,
141
- return_value : * mut zval ,
142
- ) {
143
- if let Some ( func) = TIME_SLEEP_UNTIL_HANDLER {
144
- sleeping_fn ( func, execute_data, return_value, State :: Sleeping )
145
- }
100
+ macro_rules! create_sleeping_fn {
101
+ ( $fn_name: ident, $handler: ident, $state: expr) => {
102
+ static mut $handler: InternalFunctionHandler = None ;
103
+
104
+ #[ no_mangle]
105
+ unsafe extern "C" fn $fn_name(
106
+ execute_data: * mut zend_execute_data,
107
+ return_value: * mut zval,
108
+ ) {
109
+ if let Some ( func) = $handler {
110
+ sleeping_fn( func, execute_data, return_value, $state)
111
+ }
112
+ }
113
+ } ;
146
114
}
147
115
148
- /// Wrapping the FrankenPHP `frankenphp_handle_request()` function to take the time it is blocking the current thread
149
- #[ no_mangle]
150
- unsafe extern "C" fn ddog_php_prof_frankenphp_handle_request (
151
- execute_data : * mut zend_execute_data ,
152
- return_value : * mut zval ,
153
- ) {
154
- if let Some ( func) = FRANKENPHP_HANDLE_REQUEST_HANDLER {
155
- sleeping_fn ( func, execute_data, return_value, State :: Idle )
156
- }
157
- }
116
+ // Functions that are sleeping
117
+ create_sleeping_fn ! ( ddog_php_prof_sleep, SLEEP_HANDLER , State :: Sleeping ) ;
118
+ create_sleeping_fn ! ( ddog_php_prof_usleep, USLEEP_HANDLER , State :: Sleeping ) ;
119
+ create_sleeping_fn ! ( ddog_php_prof_time_nanosleep, TIME_NANOSLEEP_HANDLER , State :: Sleeping ) ;
120
+ create_sleeping_fn ! ( ddog_php_prof_time_sleep_until, TIME_SLEEP_UNTIL_HANDLER , State :: Sleeping ) ;
121
+
122
+ // Idle functions: these are functions which are like RSHUTDOWN -> RINIT
123
+ create_sleeping_fn ! ( ddog_php_prof_frankenphp_handle_request, FRANKENPHP_HANDLE_REQUEST_HANDLER , State :: Idle ) ;
124
+
125
+ // Functions that are blocking on I/O
126
+ create_sleeping_fn ! ( ddog_php_prof_stream_select, STREAM_SELECT_HANDLER , State :: Select ) ;
127
+ create_sleeping_fn ! ( ddog_php_prof_socket_select, SOCKET_SELECT_HANDLER , State :: Select ) ;
128
+ create_sleeping_fn ! ( ddog_php_prof_curl_multi_select, CURL_MULTI_SELECT_HANDLER , State :: Select ) ;
129
+ create_sleeping_fn ! ( ddog_php_prof_uv_run, UV_RUN_HANDLER , State :: Select ) ;
130
+ create_sleeping_fn ! ( ddog_php_prof_event_base_loop, EVENT_BASE_LOOP_HANDLER , State :: Select ) ;
131
+ create_sleeping_fn ! ( ddog_php_prof_eventbase_loop, EVENTBASE_LOOP_HANDLER , State :: Select ) ;
132
+ create_sleeping_fn ! ( ddog_php_prof_ev_loop_run, EV_LOOP_RUN_HANDLER , State :: Select ) ;
133
+ create_sleeping_fn ! ( ddog_php_prof_parallel_events_poll, PARALLEL_EVENTS_POLL_HANDLER , State :: Select ) ;
158
134
159
135
/// Will be called by the ZendEngine on all errors happening. This is a PHP 8 API
160
136
#[ cfg( zend_error_observer) ]
@@ -227,36 +203,92 @@ pub fn timeline_minit() {
227
203
pub unsafe fn timeline_startup ( ) {
228
204
let handlers = [
229
205
zend:: datadog_php_zif_handler:: new (
230
- CStr :: from_bytes_with_nul_unchecked ( b "sleep\0 ") ,
206
+ cstr ! ( "sleep" ) ,
231
207
ptr:: addr_of_mut!( SLEEP_HANDLER ) ,
232
208
Some ( ddog_php_prof_sleep) ,
233
209
) ,
234
210
zend:: datadog_php_zif_handler:: new (
235
- CStr :: from_bytes_with_nul_unchecked ( b "usleep\0 ") ,
211
+ cstr ! ( "usleep" ) ,
236
212
ptr:: addr_of_mut!( USLEEP_HANDLER ) ,
237
213
Some ( ddog_php_prof_usleep) ,
238
214
) ,
239
215
zend:: datadog_php_zif_handler:: new (
240
- CStr :: from_bytes_with_nul_unchecked ( b "time_nanosleep\0 ") ,
216
+ cstr ! ( "time_nanosleep" ) ,
241
217
ptr:: addr_of_mut!( TIME_NANOSLEEP_HANDLER ) ,
242
218
Some ( ddog_php_prof_time_nanosleep) ,
243
219
) ,
244
220
zend:: datadog_php_zif_handler:: new (
245
- CStr :: from_bytes_with_nul_unchecked ( b "time_sleep_until\0 ") ,
221
+ cstr ! ( "time_sleep_until" ) ,
246
222
ptr:: addr_of_mut!( TIME_SLEEP_UNTIL_HANDLER ) ,
247
223
Some ( ddog_php_prof_time_sleep_until) ,
248
224
) ,
249
225
zend:: datadog_php_zif_handler:: new (
250
- CStr :: from_bytes_with_nul_unchecked ( b "frankenphp_handle_request\0 ") ,
226
+ cstr ! ( "frankenphp_handle_request" ) ,
251
227
ptr:: addr_of_mut!( FRANKENPHP_HANDLE_REQUEST_HANDLER ) ,
252
228
Some ( ddog_php_prof_frankenphp_handle_request) ,
253
229
) ,
230
+ zend:: datadog_php_zif_handler:: new (
231
+ cstr ! ( "stream_select" ) ,
232
+ ptr:: addr_of_mut!( STREAM_SELECT_HANDLER ) ,
233
+ Some ( ddog_php_prof_stream_select) ,
234
+ ) ,
235
+ zend:: datadog_php_zif_handler:: new (
236
+ cstr ! ( "socket_select" ) ,
237
+ ptr:: addr_of_mut!( SOCKET_SELECT_HANDLER ) ,
238
+ Some ( ddog_php_prof_socket_select) ,
239
+ ) ,
240
+ zend:: datadog_php_zif_handler:: new (
241
+ cstr ! ( "curl_multi_select" ) ,
242
+ ptr:: addr_of_mut!( CURL_MULTI_SELECT_HANDLER ) ,
243
+ Some ( ddog_php_prof_curl_multi_select) ,
244
+ ) ,
245
+ // provided by `ext-uv` from https://pecl.php.net/package/uv
246
+ zend:: datadog_php_zif_handler:: new (
247
+ cstr ! ( "uv_run" ) ,
248
+ ptr:: addr_of_mut!( UV_RUN_HANDLER ) ,
249
+ Some ( ddog_php_prof_uv_run) ,
250
+ ) ,
251
+ // provided by `ext-libevent` from https://pecl.php.net/package/libevent
252
+ zend:: datadog_php_zif_handler:: new (
253
+ cstr ! ( "event_base_loop" ) ,
254
+ ptr:: addr_of_mut!( EVENT_BASE_LOOP_HANDLER ) ,
255
+ Some ( ddog_php_prof_event_base_loop) ,
256
+ ) ,
254
257
] ;
255
258
256
259
for handler in handlers. into_iter ( ) {
257
260
// Safety: we've set all the parameters correctly for this C call.
258
261
zend:: datadog_php_install_handler ( handler) ;
259
262
}
263
+
264
+ let handlers = [
265
+ // provided by `ext-ev` from https://pecl.php.net/package/ev
266
+ zend:: datadog_php_zim_handler:: new (
267
+ cstr ! ( "evloop" ) ,
268
+ cstr ! ( "run" ) ,
269
+ ptr:: addr_of_mut!( EV_LOOP_RUN_HANDLER ) ,
270
+ Some ( ddog_php_prof_ev_loop_run) ,
271
+ ) ,
272
+ // provided by `ext-event` from https://pecl.php.net/package/event
273
+ zend:: datadog_php_zim_handler:: new (
274
+ cstr ! ( "eventbase" ) ,
275
+ cstr ! ( "loop" ) ,
276
+ ptr:: addr_of_mut!( EVENTBASE_LOOP_HANDLER ) ,
277
+ Some ( ddog_php_prof_eventbase_loop) ,
278
+ ) ,
279
+ // provided by `ext-parallel` from https://pecl.php.net/package/parallel
280
+ zend:: datadog_php_zim_handler:: new (
281
+ cstr ! ( "parallel\\ events" ) ,
282
+ cstr ! ( "poll" ) ,
283
+ ptr:: addr_of_mut!( PARALLEL_EVENTS_POLL_HANDLER ) ,
284
+ Some ( ddog_php_prof_parallel_events_poll) ,
285
+ ) ,
286
+ ] ;
287
+
288
+ for handler in handlers. into_iter ( ) {
289
+ // Safety: we've set all the parameters correctly for this C call.
290
+ zend:: datadog_php_install_method_handler ( handler) ;
291
+ }
260
292
}
261
293
262
294
/// This function is run during the RINIT phase and reports any `IDLE_SINCE` duration as an idle
0 commit comments