diff --git a/ext/ddtrace.c b/ext/ddtrace.c index 8214e38a944..b1ff4b450a4 100644 --- a/ext/ddtrace.c +++ b/ext/ddtrace.c @@ -1017,6 +1017,8 @@ static void dd_disable_if_incompatible_sapi_detected(void) { } } +static void dd_post_sapi_deactivate_minit(void); + static PHP_MINIT_FUNCTION(ddtrace) { UNUSED(type); @@ -1109,6 +1111,7 @@ static PHP_MINIT_FUNCTION(ddtrace) { ddtrace_dogstatsd_client_minit(); #endif ddshared_minit(); + dd_post_sapi_deactivate_minit(); dd_register_span_data_ce(); dd_register_fatal_error_ce(); @@ -1401,6 +1404,10 @@ static PHP_RSHUTDOWN_FUNCTION(ddtrace) { DDTRACE_G(active_stack) = NULL; } + return SUCCESS; +} + +static void dd_post_sapi_deactivate_do(void) { dd_finalize_telemetry(); if (DDTRACE_G(last_flushed_root_service_name)) { zend_string_release(DDTRACE_G(last_flushed_root_service_name)); @@ -1411,23 +1418,71 @@ static PHP_RSHUTDOWN_FUNCTION(ddtrace) { DDTRACE_G(last_flushed_root_env_name) = NULL; } - return SUCCESS; -} - -#if PHP_VERSION_ID < 80000 -int ddtrace_post_deactivate(void) { -#else -zend_result ddtrace_post_deactivate(void) { -#endif zai_interceptor_deactivate(); - // we can only actually free our hooks hashtables in post_deactivate, as within RSHUTDOWN some user code may still run + // we can only actually free our hooks hashtables in post_deactivate or later, as within RSHUTDOWN some user code may still run zai_hook_rshutdown(); zai_uhook_rshutdown(); // zai config may be accessed indirectly via other modules RSHUTDOWN, so delay this until the last possible time zai_config_rshutdown(); - return SUCCESS; +} + +static int (*dd_prev_sapi_deactivate)(void); + +// Start of request_rec from httpd.h, this has been unchanged forever, so we can just use this. +struct apache_request_rec { + void *pool; + void *connection; + void *server; + void *next; + void *prev; + void *main; +}; +static void (*dd_ap_finalize_request_protocol)(struct apache_request_rec *r); + +static int dd_post_apache_deactivate(void) { + int result = dd_prev_sapi_deactivate(); + + struct apache_request_rec *r = ((struct { + int state; + struct apache_request_rec *r; + } *) SG(server_context))->r; + // Check whether this is not an apache sub-request, otherwise we may not alter the state of the connection, i.e. here we don't gain any latency benefit + if (!r->main) { + dd_ap_finalize_request_protocol(r); + } + + dd_post_sapi_deactivate_do(); + + return result; +} + +static int dd_post_sapi_deactivate(void) { + int result = dd_prev_sapi_deactivate(); + dd_post_sapi_deactivate_do(); + return result; +} + +static void dd_post_sapi_deactivate_minit(void) { + dd_prev_sapi_deactivate = sapi_module.deactivate; + + if (ddtrace_active_sapi == DATADOG_PHP_SAPI_APACHE2HANDLER) { +#ifndef _WIN32 + void *handle = dlopen(NULL, RTLD_LAZY); +#else + void *handle = GetModuleHandle(NULL); // not refcounted, must not be closed +#endif + dd_ap_finalize_request_protocol = DL_FETCH_SYMBOL(handle, "ap_finalize_request_protocol"); +#ifndef _WIN32 + dlclose(handle); +#endif + if (dd_ap_finalize_request_protocol) { + sapi_module.deactivate = dd_post_apache_deactivate; + return; + } + } + sapi_module.deactivate = dd_post_sapi_deactivate; } void ddtrace_disable_tracing_in_current_request(void) { @@ -2874,7 +2929,7 @@ zend_module_entry ddtrace_module_entry = {STANDARD_MODULE_HEADER_EX, NULL, PHP_RSHUTDOWN(ddtrace), PHP_MINFO(ddtrace), PHP_DDTRACE_VERSION, PHP_MODULE_GLOBALS(ddtrace), PHP_GINIT(ddtrace), PHP_GSHUTDOWN(ddtrace), - ddtrace_post_deactivate, STANDARD_MODULE_PROPERTIES_EX}; + NULL, STANDARD_MODULE_PROPERTIES_EX}; // the following operations are performed in order to put the tracer in a state when a new trace can be started: // - set a new trace (group) id