@@ -21,10 +21,11 @@ mod exception;
21
21
#[ cfg( feature = "timeline" ) ]
22
22
mod timeline;
23
23
24
+ use crate :: bindings:: ddog_php_prof_executor_global_addrs;
24
25
use crate :: config:: { SystemSettings , INITIAL_SYSTEM_SETTINGS } ;
25
26
use bindings:: {
26
- self as zend, ddog_php_prof_php_version, ddog_php_prof_php_version_id, ZendExtension ,
27
- ZendResult ,
27
+ self as zend, ddog_php_prof_php_version, ddog_php_prof_php_version_id, zend_execute_data , zval ,
28
+ ZendExtension , ZendResult ,
28
29
} ;
29
30
use clocks:: * ;
30
31
use core:: ptr;
@@ -33,14 +34,14 @@ use lazy_static::lazy_static;
33
34
use libc:: c_char;
34
35
use log:: { debug, error, info, trace, warn} ;
35
36
use once_cell:: sync:: { Lazy , OnceCell } ;
36
- use profiling:: { LocalRootSpanResourceMessage , Profiler , VmInterrupt } ;
37
+ use profiling:: { LocalRootSpanResourceMessage , Profiler } ;
37
38
use sapi:: Sapi ;
38
39
use std:: borrow:: Cow ;
39
40
use std:: cell:: RefCell ;
40
41
use std:: ffi:: CStr ;
41
42
use std:: ops:: Deref ;
42
43
use std:: os:: raw:: c_int;
43
- use std:: sync:: atomic:: { AtomicBool , AtomicU32 , Ordering } ;
44
+ use std:: sync:: atomic:: { AtomicBool , AtomicPtr , AtomicU32 , Ordering } ;
44
45
use std:: sync:: { Arc , Mutex , Once } ;
45
46
use std:: time:: { Duration , Instant } ;
46
47
use uuid:: Uuid ;
@@ -333,6 +334,23 @@ extern "C" fn prshutdown() -> ZendResult {
333
334
ZendResult :: Success
334
335
}
335
336
337
+ // Keep in-sync with php_ffi.c.
338
+ #[ repr( C ) ]
339
+ #[ derive( Clone , Copy , Debug , Eq , PartialEq , Hash ) ]
340
+ pub struct ExecutorGlobalAddrs {
341
+ pub vm_stack_top : ptr:: NonNull < * mut zval > ,
342
+ pub current_execute_data : ptr:: NonNull < * mut zend_execute_data > ,
343
+ pub vm_interrupt : ptr:: NonNull < AtomicBool > ,
344
+ }
345
+
346
+ impl ExecutorGlobalAddrs {
347
+ /// # Safety
348
+ /// Must be called on a PHP thread during a request.
349
+ unsafe fn new ( ) -> ExecutorGlobalAddrs {
350
+ ddog_php_prof_executor_global_addrs ( )
351
+ }
352
+ }
353
+
336
354
pub struct RequestLocals {
337
355
pub env : Option < String > ,
338
356
pub service : Option < String > ,
@@ -347,29 +365,33 @@ pub struct RequestLocals {
347
365
pub system_settings : ptr:: NonNull < SystemSettings > ,
348
366
349
367
pub interrupt_count : AtomicU32 ,
350
- pub vm_interrupt_addr : * const AtomicBool ,
368
+ pub current_execute_data_cache : AtomicPtr < zend_execute_data > ,
369
+ pub executor_global_addrs : ExecutorGlobalAddrs ,
351
370
}
352
371
353
372
impl RequestLocals {
354
- #[ track_caller]
355
- pub fn system_settings ( & self ) -> & SystemSettings {
356
- // SAFETY: it should always be valid, either set to the
357
- // INITIAL_SYSTEM_SETTINGS or to the SYSTEM_SETTINGS.
358
- unsafe { self . system_settings . as_ref ( ) }
359
- }
360
- }
361
-
362
- impl Default for RequestLocals {
363
- fn default ( ) -> RequestLocals {
373
+ /// # Safety
374
+ /// Must be called from a PHP Thread.
375
+ unsafe fn new ( ) -> RequestLocals {
364
376
RequestLocals {
365
377
env : None ,
366
378
service : None ,
367
379
version : None ,
368
380
system_settings : ptr:: NonNull :: from ( INITIAL_SYSTEM_SETTINGS . deref ( ) ) ,
369
381
interrupt_count : AtomicU32 :: new ( 0 ) ,
370
- vm_interrupt_addr : ptr:: null_mut ( ) ,
382
+ current_execute_data_cache : AtomicPtr :: new ( ptr:: null_mut ( ) ) ,
383
+
384
+ // SAFETY: required by this function's safety conditions.
385
+ executor_global_addrs : ExecutorGlobalAddrs :: new ( ) ,
371
386
}
372
387
}
388
+
389
+ #[ track_caller]
390
+ pub fn system_settings ( & self ) -> & SystemSettings {
391
+ // SAFETY: it should always be valid, either set to the
392
+ // INITIAL_SYSTEM_SETTINGS or to the SYSTEM_SETTINGS.
393
+ unsafe { self . system_settings . as_ref ( ) }
394
+ }
373
395
}
374
396
375
397
thread_local ! {
@@ -378,7 +400,8 @@ thread_local! {
378
400
wall_time: Instant :: now( ) ,
379
401
} ) ;
380
402
381
- static REQUEST_LOCALS : RefCell <RequestLocals > = RefCell :: new( RequestLocals :: default ( ) ) ;
403
+ // These are only meant to be used on a PHP thread.
404
+ static REQUEST_LOCALS : RefCell <RequestLocals > = RefCell :: new( unsafe { RequestLocals :: new( ) } ) ;
382
405
383
406
/// The tags for this thread/request. These get sent to other threads,
384
407
/// which is why they are Arc. However, they are wrapped in a RefCell
@@ -426,9 +449,9 @@ extern "C" fn rinit(_type: c_int, _module_number: c_int) -> ZendResult {
426
449
// initialize the thread local storage and cache some items
427
450
REQUEST_LOCALS . with ( |cell| {
428
451
let mut locals = cell. borrow_mut ( ) ;
429
- // Safety: we are in rinit on a PHP thread.
430
- locals. vm_interrupt_addr = unsafe { zend:: datadog_php_profiling_vm_interrupt_addr ( ) } ;
431
452
locals. interrupt_count . store ( 0 , Ordering :: SeqCst ) ;
453
+ // Safety: we are in rinit on a PHP thread.
454
+ locals. executor_global_addrs = unsafe { ddog_php_prof_executor_global_addrs ( ) } ;
432
455
433
456
// Safety: We are after first rinit and before mshutdown.
434
457
unsafe {
@@ -555,11 +578,17 @@ extern "C" fn rinit(_type: c_int, _module_number: c_int) -> ZendResult {
555
578
}
556
579
557
580
if let Some ( profiler) = PROFILER . lock ( ) . unwrap ( ) . as_ref ( ) {
558
- let interrupt = VmInterrupt {
559
- interrupt_count_ptr : & locals. interrupt_count as * const AtomicU32 ,
560
- engine_ptr : locals. vm_interrupt_addr ,
581
+ let id = profiling:: interrupts:: Id {
582
+ vm_interrupt_addr : locals. executor_global_addrs . vm_interrupt ,
583
+ current_execute_data_addr : locals. executor_global_addrs . current_execute_data ,
584
+ } ;
585
+ let state = profiling:: interrupts:: State {
586
+ interrupt_count_addr : ptr:: NonNull :: from ( & locals. interrupt_count ) ,
587
+ current_execute_data_addr : ptr:: NonNull :: from (
588
+ & locals. current_execute_data_cache ,
589
+ ) ,
561
590
} ;
562
- profiler. add_interrupt ( interrupt ) ;
591
+ profiler. add_interrupt ( id , state ) ;
563
592
}
564
593
} ) ;
565
594
} else {
@@ -611,11 +640,11 @@ extern "C" fn rshutdown(_type: c_int, _module_number: c_int) -> ZendResult {
611
640
// and we don't need to optimize for that.
612
641
if system_settings. profiling_enabled {
613
642
if let Some ( profiler) = PROFILER . lock ( ) . unwrap ( ) . as_ref ( ) {
614
- let interrupt = VmInterrupt {
615
- interrupt_count_ptr : & locals. interrupt_count ,
616
- engine_ptr : locals. vm_interrupt_addr ,
643
+ let id = profiling :: interrupts :: Id {
644
+ current_execute_data_addr : locals. executor_global_addrs . current_execute_data ,
645
+ vm_interrupt_addr : locals. executor_global_addrs . vm_interrupt ,
617
646
} ;
618
- profiler. remove_interrupt ( interrupt ) ;
647
+ profiler. remove_interrupt ( id ) ;
619
648
}
620
649
}
621
650
} ) ;
0 commit comments