|
| 1 | +#[cfg(php_zts)] |
| 2 | +use crate::sapi::Sapi; |
| 3 | +use crate::SAPI; |
| 4 | +#[cfg(php_zts)] |
| 5 | +use libc::c_char; |
1 | 6 | use libc::sched_yield;
|
2 | 7 | use log::warn;
|
| 8 | +use once_cell::sync::OnceCell; |
3 | 9 | use std::mem::MaybeUninit;
|
4 | 10 | use std::thread::JoinHandle;
|
5 | 11 | use std::time::{Duration, Instant};
|
@@ -69,3 +75,70 @@ pub fn join_timeout(handle: JoinHandle<()>, timeout: Duration, impact: &str) {
|
69 | 75 | std::panic::resume_unwind(err)
|
70 | 76 | }
|
71 | 77 | }
|
| 78 | + |
| 79 | +thread_local! { |
| 80 | + /// This is a cache for the thread name. It will not change after the thread has been |
| 81 | + /// created, as SAPI's do not change thread names and ext-pthreads / ext-parallel do not |
| 82 | + /// provide an interface for renaming a thread. |
| 83 | + static THREAD_NAME: OnceCell<String> = const { OnceCell::new() }; |
| 84 | +} |
| 85 | + |
| 86 | +pub fn get_current_thread_name() -> String { |
| 87 | + THREAD_NAME.with(|name| { |
| 88 | + name.get_or_init(|| { |
| 89 | + #[cfg(php_zts)] |
| 90 | + let mut thread_name = SAPI.to_string(); |
| 91 | + #[cfg(not(php_zts))] |
| 92 | + let thread_name = SAPI.to_string(); |
| 93 | + |
| 94 | + #[cfg(php_zts)] |
| 95 | + { |
| 96 | + // So far, only FrankenPHP sets meaningful thread names |
| 97 | + if *SAPI == Sapi::FrankenPHP { |
| 98 | + let mut name = [0u8; 32]; |
| 99 | + |
| 100 | + let result = unsafe { |
| 101 | + libc::pthread_getname_np( |
| 102 | + libc::pthread_self(), |
| 103 | + name.as_mut_ptr() as *mut c_char, |
| 104 | + name.len(), |
| 105 | + ) |
| 106 | + }; |
| 107 | + |
| 108 | + if result == 0 { |
| 109 | + // If successful, convert the result to a Rust String |
| 110 | + let cstr = |
| 111 | + unsafe { std::ffi::CStr::from_ptr(name.as_ptr() as *const c_char) }; |
| 112 | + let str_slice: &str = cstr.to_str().unwrap_or_default(); |
| 113 | + if !str_slice.is_empty() { |
| 114 | + thread_name.push_str(": "); |
| 115 | + thread_name.push_str(str_slice); |
| 116 | + } |
| 117 | + } |
| 118 | + } |
| 119 | + } |
| 120 | + |
| 121 | + thread_name |
| 122 | + }).clone() |
| 123 | + }) |
| 124 | +} |
| 125 | + |
| 126 | +#[cfg(test)] |
| 127 | +mod tests { |
| 128 | + use super::*; |
| 129 | + use libc::c_char; |
| 130 | + |
| 131 | + #[test] |
| 132 | + fn test_get_current_thread_name() { |
| 133 | + unsafe { |
| 134 | + // When running `cargo test`, the thread name for this test will be set to |
| 135 | + // `profiling::thread_utils::tests:` which would interfer with this test |
| 136 | + libc::pthread_setname_np( |
| 137 | + #[cfg(target_os = "linux")] |
| 138 | + libc::pthread_self(), |
| 139 | + b"\0".as_ptr() as *const c_char, |
| 140 | + ); |
| 141 | + } |
| 142 | + assert_eq!(get_current_thread_name(), "unknown"); |
| 143 | + } |
| 144 | +} |
0 commit comments