Rename hasPHDRCache to hasAsyncSignalSafeUnwind; return true on macOS (backtrace-based unwinding)

This commit is contained in:
Raúl Marín
2026-07-08 16:48:14 +02:00
parent e2973f40f3
commit 51e29c630d
5 changed files with 31 additions and 16 deletions
+13 -6
View File
@@ -108,20 +108,27 @@ void updatePHDRCache()
}
bool hasPHDRCache()
namespace
{
return phdr_cache.load() != nullptr;
/// The lock-free dl_iterate_phdr override above is active once the cache is populated.
bool hasPHDRCache() { return phdr_cache.load() != nullptr; }
}
bool hasAsyncSignalSafeUnwind()
{
return hasPHDRCache();
}
#else
void updatePHDRCache() {}
#if defined(USE_MUSL)
/// With statically linked with musl, dl_iterate_phdr is immutable.
bool hasPHDRCache() { return true; }
#if defined(USE_MUSL) || defined(OS_DARWIN)
/// musl: dl_iterate_phdr is inherently lock-free.
/// macOS: unwinding uses frame-pointer backtrace() which never calls dl_iterate_phdr.
bool hasAsyncSignalSafeUnwind() { return true; }
#else
bool hasPHDRCache() { return false; }
bool hasAsyncSignalSafeUnwind() { return false; }
#endif
#endif
+10 -3
View File
@@ -14,7 +14,14 @@
*/
void updatePHDRCache();
/** Check if "dl_iterate_phdr" will be lock-free
* to determine if some features like Query Profiler can be used.
/** Whether capturing a stack trace from within an async signal handler is safe on this
* platform/build. This gates features that unwind in a signal handler (the Query Profiler)
* or that depend on such a source (the TraceCollector).
*
* - Linux: true once `updatePHDRCache` has installed the lock-free `dl_iterate_phdr` (libunwind
* calls `dl_iterate_phdr` while unwinding `.eh_frame`, and glibc's takes a loader lock).
* - musl: always true, its `dl_iterate_phdr` is inherently lock-free.
* - macOS: always true, unwinding uses frame-pointer `backtrace` which never calls
* `dl_iterate_phdr`, so no cache is needed.
*/
bool hasPHDRCache();
bool hasAsyncSignalSafeUnwind();
+5 -4
View File
@@ -1466,10 +1466,11 @@ try
bool has_trace_collector = config().has("trace_log");
LOG_INFO(log, "Query Profiler will use frame-pointer-based stack unwinding under sanitizers.");
#else
bool has_trace_collector = hasPHDRCache() && config().has("trace_log");
if (!hasPHDRCache())
LOG_INFO(log, "Query Profiler and TraceCollector are disabled because they require PHDR cache to be created"
" (otherwise the function 'dl_iterate_phdr' is not lock free and not async-signal safe).");
bool has_trace_collector = hasAsyncSignalSafeUnwind() && config().has("trace_log");
if (!hasAsyncSignalSafeUnwind())
LOG_INFO(log, "Query Profiler and TraceCollector are disabled because async-signal-safe stack unwinding"
" is not available in this build (on Linux this requires the lock-free PHDR cache, otherwise"
" 'dl_iterate_phdr' is not lock free and not async-signal safe).");
#endif
// Settings validation for page cache. Ensure that page_cache_max_size is > page_cache_min_size.
+2 -2
View File
@@ -249,8 +249,8 @@ QueryProfilerBase<ProfilerImpl>::QueryProfilerBase(
/// call dl_iterate_phdr in the signal handler, so the PHDR cache is not needed for
/// stack capture. Symbolization happens later in a normal thread context.
#if !defined(THREAD_SANITIZER)
if (!hasPHDRCache())
throw Exception(ErrorCodes::NOT_IMPLEMENTED, "QueryProfiler cannot be used without PHDR cache in this build");
if (!hasAsyncSignalSafeUnwind())
throw Exception(ErrorCodes::NOT_IMPLEMENTED, "QueryProfiler cannot be used without async-signal-safe stack unwinding in this build");
#endif
/// `sigaction` is `#define sigaction __sigaction` on some platforms, and
@@ -2262,7 +2262,7 @@ TEST(FunctionsStress, stress)
int num_threads = options.num_threads;
if (num_threads <= 0)
{
if (hasPHDRCache())
if (hasAsyncSignalSafeUnwind())
num_threads = std::thread::hardware_concurrency();
else
/// In TSAN build, with too many threads, this test gets >30s stalls on lock