Skip to content

Commit d954ded

Browse files
realFlowControlbwoebimorrisonlevi
authored
Add FrankenPHP to the list of recognised/supported SAPIs (#2523)
Signed-off-by: Bob Weinand <[email protected]> Co-authored-by: Bob Weinand <[email protected]> Co-authored-by: Levi Morrison <[email protected]>
1 parent 254782a commit d954ded

File tree

6 files changed

+63
-15
lines changed

6 files changed

+63
-15
lines changed

Diff for: components/sapi/sapi.c

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ sapi_t datadog_php_sapi_from_name(string_view_t module) {
2020
{SV("cli-server"), DATADOG_PHP_SAPI_CLI_SERVER},
2121
{SV("embed"), DATADOG_PHP_SAPI_EMBED},
2222
{SV("fpm-fcgi"), DATADOG_PHP_SAPI_FPM_FCGI},
23+
{SV("frankenphp"), DATADOG_PHP_SAPI_FRANKENPHP},
2324
{SV("litespeed"), DATADOG_PHP_SAPI_LITESPEED},
2425
{SV("phpdbg"), DATADOG_PHP_SAPI_PHPDBG},
2526
{SV("tea"), DATADOG_PHP_SAPI_TEA},

Diff for: components/sapi/sapi.h

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ typedef enum {
1212
DATADOG_PHP_SAPI_EMBED,
1313
DATADOG_PHP_SAPI_LITESPEED,
1414
DATADOG_PHP_SAPI_FPM_FCGI,
15+
DATADOG_PHP_SAPI_FRANKENPHP,
1516
DATADOG_PHP_SAPI_PHPDBG,
1617
DATADOG_PHP_SAPI_TEA,
1718
} datadog_php_sapi;

Diff for: components/sapi/tests/sapi.cc

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ TEST_CASE("recognize real sapis", "[sapi]") {
1616
{"cli-server", DATADOG_PHP_SAPI_CLI_SERVER},
1717
{"embed", DATADOG_PHP_SAPI_EMBED},
1818
{"fpm-fcgi", DATADOG_PHP_SAPI_FPM_FCGI},
19+
{"frankenphp", DATADOG_PHP_SAPI_FRANKENPHP},
1920
{"litespeed", DATADOG_PHP_SAPI_LITESPEED},
2021
{"phpdbg", DATADOG_PHP_SAPI_PHPDBG},
2122
{"tea", DATADOG_PHP_SAPI_TEA},

Diff for: ext/ddtrace.c

+16-8
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ static bool dd_has_other_observers;
118118
static int dd_observer_extension_backup = -1;
119119
#endif
120120

121+
static datadog_php_sapi ddtrace_active_sapi = DATADOG_PHP_SAPI_UNKNOWN;
122+
121123
_Atomic(int64_t) ddtrace_warn_legacy_api;
122124

123125
ZEND_DECLARE_MODULE_GLOBALS(ddtrace)
@@ -579,7 +581,8 @@ static PHP_GSHUTDOWN_FUNCTION(ddtrace) {
579581
zai_hook_gshutdown();
580582

581583
#ifdef CXA_THREAD_ATEXIT_WRAPPER
582-
if (!dd_is_main_thread) {
584+
// FrankenPHP calls `ts_free_thread()` in rshutdown
585+
if (!dd_is_main_thread && ddtrace_active_sapi != DATADOG_PHP_SAPI_FRANKENPHP) {
583586
dd_run_rust_thread_destructors(NULL);
584587
}
585588
#endif
@@ -991,13 +994,14 @@ static void dd_register_fatal_error_ce(void) {
991994
ddtrace_ce_fatal_error = zend_register_internal_class_ex(&ce, zend_ce_exception);
992995
}
993996

994-
static bool dd_is_compatible_sapi(datadog_php_string_view module_name) {
995-
switch (datadog_php_sapi_from_name(module_name)) {
997+
static bool dd_is_compatible_sapi() {
998+
switch (ddtrace_active_sapi) {
996999
case DATADOG_PHP_SAPI_APACHE2HANDLER:
9971000
case DATADOG_PHP_SAPI_CGI_FCGI:
9981001
case DATADOG_PHP_SAPI_CLI:
9991002
case DATADOG_PHP_SAPI_CLI_SERVER:
10001003
case DATADOG_PHP_SAPI_FPM_FCGI:
1004+
case DATADOG_PHP_SAPI_FRANKENPHP:
10011005
case DATADOG_PHP_SAPI_TEA:
10021006
return true;
10031007

@@ -1007,8 +1011,7 @@ static bool dd_is_compatible_sapi(datadog_php_string_view module_name) {
10071011
}
10081012

10091013
static void dd_disable_if_incompatible_sapi_detected(void) {
1010-
datadog_php_string_view module_name = datadog_php_string_view_from_cstr(sapi_module.name);
1011-
if (UNEXPECTED(!dd_is_compatible_sapi(module_name))) {
1014+
if (UNEXPECTED(!dd_is_compatible_sapi())) {
10121015
LOG(WARN, "Incompatible SAPI detected '%s'; disabling ddtrace", sapi_module.name);
10131016
ddtrace_disable = 1;
10141017
}
@@ -1017,10 +1020,15 @@ static void dd_disable_if_incompatible_sapi_detected(void) {
10171020
static PHP_MINIT_FUNCTION(ddtrace) {
10181021
UNUSED(type);
10191022

1023+
ddtrace_active_sapi = datadog_php_sapi_from_name(datadog_php_string_view_from_cstr(sapi_module.name));
1024+
10201025
#ifdef CXA_THREAD_ATEXIT_WRAPPER
1021-
dd_is_main_thread = true;
1022-
glibc__cxa_thread_atexit_impl = CXA_THREAD_ATEXIT_PHP;
1023-
atexit(dd_clean_main_thread_locals);
1026+
// FrankenPHP calls `ts_free_thread()` in rshutdown
1027+
if (ddtrace_active_sapi != DATADOG_PHP_SAPI_FRANKENPHP) {
1028+
dd_is_main_thread = true;
1029+
glibc__cxa_thread_atexit_impl = CXA_THREAD_ATEXIT_PHP;
1030+
atexit(dd_clean_main_thread_locals);
1031+
}
10241032
#endif
10251033

10261034
// Reset on every minit for `apachectl graceful`.

Diff for: profiling/src/sapi.rs

+4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ pub enum Sapi {
1818
Cli,
1919
CliServer,
2020
Embed,
21+
FrankenPHP,
2122
FpmFcgi,
2223
Litespeed,
2324
PhpDbg,
@@ -34,6 +35,7 @@ impl Sapi {
3435
("cli", Sapi::Cli),
3536
("cli-server", Sapi::CliServer),
3637
("embed", Sapi::Embed),
38+
("frankenphp", Sapi::FrankenPHP),
3739
("fpm-fcgi", Sapi::FpmFcgi),
3840
("litespeed", Sapi::Litespeed),
3941
("phpdbg", Sapi::PhpDbg),
@@ -99,6 +101,7 @@ impl AsRef<str> for Sapi {
99101
Sapi::Cli => "cli",
100102
Sapi::CliServer => "cli-server",
101103
Sapi::Embed => "embed",
104+
Sapi::FrankenPHP => "frankenphp",
102105
Sapi::FpmFcgi => "fpm-fcgi",
103106
Sapi::Litespeed => "litespeed",
104107
Sapi::PhpDbg => "phpdbg",
@@ -125,6 +128,7 @@ mod tests {
125128
("cli", Sapi::Cli),
126129
("cli-server", Sapi::CliServer),
127130
("embed", Sapi::Embed),
131+
("frankenphp", Sapi::FrankenPHP),
128132
("fpm-fcgi", Sapi::FpmFcgi),
129133
("litespeed", Sapi::Litespeed),
130134
("phpdbg", Sapi::PhpDbg),

Diff for: profiling/src/timeline.rs

+40-7
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,32 @@ static mut SLEEP_HANDLER: InternalFunctionHandler = None;
2626
static mut USLEEP_HANDLER: InternalFunctionHandler = None;
2727
static mut TIME_NANOSLEEP_HANDLER: InternalFunctionHandler = None;
2828
static mut TIME_SLEEP_UNTIL_HANDLER: InternalFunctionHandler = None;
29+
static mut FRANKENPHP_HANDLE_REQUEST_HANDLER: InternalFunctionHandler = None;
2930

3031
thread_local! {
3132
static IDLE_SINCE: RefCell<Instant> = RefCell::new(Instant::now());
3233
}
3334

35+
enum State {
36+
Idle,
37+
Sleeping,
38+
}
39+
40+
impl State {
41+
fn as_str(&self) -> &'static str {
42+
match self {
43+
State::Idle => "idle",
44+
State::Sleeping => "sleeping",
45+
}
46+
}
47+
}
48+
3449
#[inline]
3550
fn try_sleeping_fn(
3651
func: unsafe extern "C" fn(execute_data: *mut zend_execute_data, return_value: *mut zval),
3752
execute_data: *mut zend_execute_data,
3853
return_value: *mut zval,
54+
state: State,
3955
) -> anyhow::Result<()> {
4056
let timeline_enabled = REQUEST_LOCALS.with(|cell| {
4157
cell.try_borrow()
@@ -71,7 +87,7 @@ fn try_sleeping_fn(
7187
if let Some(profiler) = guard.as_ref() {
7288
let now = now.as_nanos() as i64;
7389
let duration = duration.as_nanos() as i64;
74-
profiler.collect_idle(now, duration, "sleeping")
90+
profiler.collect_idle(now, duration, state.as_str())
7591
}
7692
}
7793
Err(err) => anyhow::bail!("profiler mutex: {err:#}"),
@@ -83,8 +99,9 @@ fn sleeping_fn(
8399
func: unsafe extern "C" fn(execute_data: *mut zend_execute_data, return_value: *mut zval),
84100
execute_data: *mut zend_execute_data,
85101
return_value: *mut zval,
102+
state: State,
86103
) {
87-
if let Err(err) = try_sleeping_fn(func, execute_data, return_value) {
104+
if let Err(err) = try_sleeping_fn(func, execute_data, return_value, state) {
88105
warn!("error creating profiling timeline sample for an internal function: {err:#}");
89106
}
90107
}
@@ -96,7 +113,7 @@ unsafe extern "C" fn ddog_php_prof_sleep(
96113
return_value: *mut zval,
97114
) {
98115
if let Some(func) = SLEEP_HANDLER {
99-
sleeping_fn(func, execute_data, return_value)
116+
sleeping_fn(func, execute_data, return_value, State::Sleeping)
100117
}
101118
}
102119

@@ -107,7 +124,7 @@ unsafe extern "C" fn ddog_php_prof_usleep(
107124
return_value: *mut zval,
108125
) {
109126
if let Some(func) = USLEEP_HANDLER {
110-
sleeping_fn(func, execute_data, return_value)
127+
sleeping_fn(func, execute_data, return_value, State::Sleeping)
111128
}
112129
}
113130

@@ -118,7 +135,7 @@ unsafe extern "C" fn ddog_php_prof_time_nanosleep(
118135
return_value: *mut zval,
119136
) {
120137
if let Some(func) = TIME_NANOSLEEP_HANDLER {
121-
sleeping_fn(func, execute_data, return_value)
138+
sleeping_fn(func, execute_data, return_value, State::Sleeping)
122139
}
123140
}
124141

@@ -129,7 +146,18 @@ unsafe extern "C" fn ddog_php_prof_time_sleep_until(
129146
return_value: *mut zval,
130147
) {
131148
if let Some(func) = TIME_SLEEP_UNTIL_HANDLER {
132-
sleeping_fn(func, execute_data, return_value)
149+
sleeping_fn(func, execute_data, return_value, State::Sleeping)
150+
}
151+
}
152+
153+
/// Wrapping the FrankenPHP `frankenphp_handle_request()` function to take the time it is blocking the current thread
154+
#[no_mangle]
155+
unsafe extern "C" fn ddog_php_prof_frankenphp_handle_request(
156+
execute_data: *mut zend_execute_data,
157+
return_value: *mut zval,
158+
) {
159+
if let Some(func) = FRANKENPHP_HANDLE_REQUEST_HANDLER {
160+
sleeping_fn(func, execute_data, return_value, State::Idle)
133161
}
134162
}
135163

@@ -174,6 +202,11 @@ pub unsafe fn timeline_startup() {
174202
&mut TIME_SLEEP_UNTIL_HANDLER,
175203
Some(ddog_php_prof_time_sleep_until),
176204
),
205+
zend::datadog_php_zif_handler::new(
206+
CStr::from_bytes_with_nul_unchecked(b"frankenphp_handle_request\0"),
207+
&mut FRANKENPHP_HANDLE_REQUEST_HANDLER,
208+
Some(ddog_php_prof_frankenphp_handle_request),
209+
),
177210
];
178211

179212
for handler in handlers.into_iter() {
@@ -210,7 +243,7 @@ pub unsafe fn timeline_rinit() {
210243
.unwrap()
211244
.as_nanos() as i64,
212245
idle_since.elapsed().as_nanos() as i64,
213-
"idle",
246+
State::Idle.as_str(),
214247
);
215248
}
216249
});

0 commit comments

Comments
 (0)