Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion profiling/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ lazy_static = { version = "1.4" }
libc = "0.2"
# TRACE set to max to support runtime configuration.
log = { version = "0.4", features = ["max_level_trace", "release_max_level_trace"]}
once_cell = { version = "1.12" }
serde_json = {version = "1.0"}
rand = { version = "0.8.5" }
rand_distr = { version = "0.4.3" }
Expand Down
17 changes: 9 additions & 8 deletions profiling/src/bindings/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,13 +246,16 @@ pub struct ZendExtension {

pub use ZendExtension as zend_extension;

impl Default for ModuleEntry {
fn default() -> Self {
impl ModuleEntry {
/// Creates a new ModuleEntry with default values for const-compatible fields.
/// Non-const fields (functions, build_id) are set to null and should be initialized separately.
#[allow(clippy::new_without_default)]
pub const fn new() -> Self {
Self {
size: std::mem::size_of::<Self>() as c_ushort,
size: core::mem::size_of::<Self>() as c_ushort,
zend_api: ZEND_MODULE_API_NO,
zend_debug: ZEND_DEBUG as u8,
zts: USING_ZTS as u8,
zend_debug: ZEND_DEBUG as c_uchar,
zts: USING_ZTS as c_uchar,
ini_entry: ptr::null(),
deps: ptr::null(),
name: c"".as_ptr(),
Expand All @@ -264,20 +267,18 @@ impl Default for ModuleEntry {
info_func: None,
version: ptr::null(),
globals_size: 0,

#[cfg(php_zts)]
globals_id_ptr: ptr::null_mut(),
#[cfg(not(php_zts))]
globals_ptr: ptr::null_mut(),

globals_ctor: None,
globals_dtor: None,
post_deactivate_func: None,
module_started: 0,
type_: MODULE_PERSISTENT as c_uchar,
handle: ptr::null_mut(),
module_number: -1,
build_id: unsafe { datadog_module_build_id() },
build_id: ptr::null(),
}
}
}
Expand Down
106 changes: 56 additions & 50 deletions profiling/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,13 @@ use core::ptr;
use lazy_static::lazy_static;
use libdd_common::{cstr, tag, tag::Tag};
use log::{debug, error, info, trace, warn};
use once_cell::sync::{Lazy, OnceCell};
use profiling::{LocalRootSpanResourceMessage, Profiler, VmInterrupt};
use sapi::Sapi;
use std::borrow::Cow;
use std::cell::{BorrowError, BorrowMutError, RefCell};
use std::ops::{Deref, DerefMut};
use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
use std::sync::{Arc, Once};
use std::sync::{Arc, Once, OnceLock};
use std::thread::{AccessError, LocalKey};
use std::time::{Duration, Instant};
use uuid::Uuid;
Expand Down Expand Up @@ -146,7 +145,7 @@ lazy_static! {
/// Additionally, the tracer is going to ask for this in its ACTIVATE handler,
/// so whatever it is replaced with needs to also follow the
/// initialize-on-first-use pattern.
static RUNTIME_ID: OnceCell<Uuid> = OnceCell::new();
static RUNTIME_ID: OnceLock<Uuid> = OnceLock::new();
// If ddtrace is loaded, we fetch the uuid from there instead
extern "C" {
pub static ddtrace_runtime_id: *const Uuid;
Expand All @@ -159,55 +158,62 @@ extern "C" {
#[cfg(php_zts)]
static mut GLOBALS_ID_PTR: i32 = 0;

/// The function `get_module` is what makes this a PHP module. Please do not
/// call this directly; only let it be called by the engine. Generally it is
/// only called once, but if someone accidentally loads the module twice then
/// it might get called more than once, though it will warn and not use the
/// consecutive return value.
/// Module dependencies for the profiler extension.
static MODULE_DEPS: [zend::ModuleDep; 8] = [
zend::ModuleDep::required(cstr!("standard")),
zend::ModuleDep::required(cstr!("json")),
zend::ModuleDep::optional(cstr!("ddtrace")),
// Optionally, be dependent on these event extensions so that the functions they provide
// are registered in the function table and we can hook into them.
zend::ModuleDep::optional(cstr!("ev")),
zend::ModuleDep::optional(cstr!("event")),
zend::ModuleDep::optional(cstr!("libevent")),
zend::ModuleDep::optional(cstr!("uv")),
zend::ModuleDep::end(),
];

/// The module entry for the profiler extension. Fields that aren't
/// const-compatible are set in get_module().
static mut MODULE: zend::ModuleEntry = zend::ModuleEntry {
deps: MODULE_DEPS.as_ptr(),
name: PROFILER_NAME.as_ptr(),
functions: ptr::null(), // Will be set in get_module()
module_startup_func: Some(minit),
module_shutdown_func: Some(mshutdown),
request_startup_func: Some(rinit),
request_shutdown_func: Some(rshutdown),
info_func: Some(minfo),
version: PROFILER_VERSION.as_ptr(),
globals_size: 1,
#[cfg(php_zts)]
globals_id_ptr: ptr::addr_of_mut!(GLOBALS_ID_PTR),
#[cfg(not(php_zts))]
globals_ptr: ptr::null_mut(),
globals_ctor: Some(ginit),
globals_dtor: Some(gshutdown),
post_deactivate_func: Some(prshutdown),
build_id: ptr::null(), // Will be set in get_module()
..zend::ModuleEntry::new()
};

/// The function `get_module` is what makes this a PHP module.
///
/// # Safety
///
/// Do not call this function manually; it will be called by the engine.
/// Generally it is only called once, but if someone accidentally loads the
/// module twice then it might get called more than once, though it will warn
/// and not use the consecutive return value.
#[no_mangle]
pub extern "C" fn get_module() -> &'static mut zend::ModuleEntry {
static DEPS: [zend::ModuleDep; 8] = [
zend::ModuleDep::required(cstr!("standard")),
zend::ModuleDep::required(cstr!("json")),
zend::ModuleDep::optional(cstr!("ddtrace")),
// Optionally, be dependent on these event extensions so that the functions they provide
// are registered in the function table and we can hook into them.
zend::ModuleDep::optional(cstr!("ev")),
zend::ModuleDep::optional(cstr!("event")),
zend::ModuleDep::optional(cstr!("libevent")),
zend::ModuleDep::optional(cstr!("uv")),
zend::ModuleDep::end(),
];

// In PHP modules written in C, this just returns the address of a global,
// mutable variable. In Rust, you cannot initialize such a complicated
// global variable because of initialization order issues that have been
// found through decades of C++ experience.
// There are a variety of ways to deal with this; this is just one way.
static mut MODULE: Lazy<zend::ModuleEntry> = Lazy::new(|| zend::ModuleEntry {
name: PROFILER_NAME.as_ptr(),
// SAFETY: php_ffi.c defines this correctly
functions: unsafe { bindings::ddog_php_prof_functions },
module_startup_func: Some(minit),
module_shutdown_func: Some(mshutdown),
request_startup_func: Some(rinit),
request_shutdown_func: Some(rshutdown),
info_func: Some(minfo),
version: PROFILER_VERSION.as_ptr(),
post_deactivate_func: Some(prshutdown),
deps: DEPS.as_ptr(),
globals_ctor: Some(ginit),
globals_dtor: Some(gshutdown),
globals_size: 1,
#[cfg(php_zts)]
globals_id_ptr: ptr::addr_of_mut!(GLOBALS_ID_PTR),
#[cfg(not(php_zts))]
globals_ptr: ptr::null_mut(),
..Default::default()
});
pub unsafe extern "C" fn get_module() -> *mut zend::ModuleEntry {
let module = ptr::addr_of_mut!(MODULE);

// SAFETY: well, it's at least as safe as what every single C extension does.
unsafe { &mut *ptr::addr_of_mut!(MODULE) }
// Set fields that aren't const-compatible.
unsafe {
ptr::addr_of_mut!((*module).functions).write(bindings::ddog_php_prof_functions);
ptr::addr_of_mut!((*module).build_id).write(bindings::datadog_module_build_id());
}
module
}

unsafe extern "C" fn ginit(_globals_ptr: *mut c_void) {
Expand Down
2 changes: 1 addition & 1 deletion profiling/src/profiling/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ use libdd_profiling::api::{
use libdd_profiling::exporter::Tag;
use libdd_profiling::internal::Profile as InternalProfile;
use log::{debug, info, trace, warn};
use once_cell::sync::OnceCell;
use std::borrow::Cow;
use std::cell::OnceCell;
use std::collections::HashMap;
use std::hash::Hash;
use std::num::NonZeroI64;
Expand Down
2 changes: 1 addition & 1 deletion profiling/src/profiling/thread_utils.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::SAPI;
use libc::sched_yield;
use once_cell::sync::OnceCell;
use std::cell::OnceCell;
use std::mem::MaybeUninit;
use std::thread::JoinHandle;
use std::time::{Duration, Instant};
Expand Down
4 changes: 2 additions & 2 deletions profiling/src/sapi.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use crate::zend::sapi_request_info;
use log::warn;
use once_cell::sync::OnceCell;
use std::borrow::Cow;
use std::collections::HashMap;
use std::ffi::{CStr, OsStr};
use std::fmt::{Display, Formatter};
use std::os::unix::ffi::OsStrExt;
use std::path::Path;
use std::sync::OnceLock;

// todo: unify with ../component/sapi
#[derive(Copy, Clone, Eq, PartialEq)]
Expand All @@ -27,7 +27,7 @@ pub enum Sapi {

impl Sapi {
pub fn from_name(name: &str) -> Sapi {
static SAPIS: OnceCell<HashMap<&str, Sapi>> = OnceCell::new();
static SAPIS: OnceLock<HashMap<&str, Sapi>> = OnceLock::new();
let sapis = SAPIS.get_or_init(|| {
HashMap::from_iter([
("apache2handler", Sapi::Apache2Handler),
Expand Down
Loading