mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-25 09:02:00 +00:00
Attempt to solve signal safety of libunwind with solution from Fedor Korotkiy
This commit is contained in:
parent
56bb2956cd
commit
d95c6e1bc4
@ -20,6 +20,9 @@
|
||||
|
||||
#include <Common/StringUtils/StringUtils.h>
|
||||
|
||||
#include <common/phdr_cache.h>
|
||||
|
||||
|
||||
/// Universal executable for various clickhouse applications
|
||||
#if ENABLE_CLICKHOUSE_SERVER || !defined(ENABLE_CLICKHOUSE_SERVER)
|
||||
int mainEntryClickHouseServer(int argc, char ** argv);
|
||||
@ -144,6 +147,10 @@ int main(int argc_, char ** argv_)
|
||||
/// It is needed because LLVM library clobbers it.
|
||||
std::set_new_handler(nullptr);
|
||||
|
||||
/// PHDR cache is required for query profiler to work reliably
|
||||
/// It also speed up exception handling, but exceptions from dynamically loaded libraries (dlopen) won't work.
|
||||
enablePHDRCache();
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
if (argc_ >= 2 && 0 == strcmp(argv_[1], "-cc1"))
|
||||
return mainEntryClickHouseClang(argc_, argv_);
|
||||
|
@ -25,6 +25,7 @@ add_library (common
|
||||
src/argsToConfig.cpp
|
||||
src/StackTrace.cpp
|
||||
src/Pipe.cpp
|
||||
src/phdr_cache.cpp
|
||||
|
||||
include/common/SimpleCache.h
|
||||
include/common/StackTrace.h
|
||||
@ -51,6 +52,7 @@ add_library (common
|
||||
include/common/getThreadNumber.h
|
||||
include/common/sleep.h
|
||||
include/common/SimpleCache.h
|
||||
include/common/phdr_cache.h
|
||||
|
||||
include/ext/bit_cast.h
|
||||
include/ext/collection_cast.h
|
||||
|
10
libs/libcommon/include/common/phdr_cache.h
Normal file
10
libs/libcommon/include/common/phdr_cache.h
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
/// This code was developed by Fedor Korotkiy (prime@yandex-team.ru) for YT product in Yandex.
|
||||
|
||||
//! Collects all dl_phdr_info items and caches them in a static array.
|
||||
//! Also rewrites dl_iterate_phdr with a lockless version which consults the above cache
|
||||
//! thus eliminating scalability bottleneck in C++ exception unwinding.
|
||||
//! As a drawback, this only works if no dynamic object loading/unloading happens after this point.
|
||||
//! This function is not thread-safe; the caller must guarantee that no concurrent unwinding takes place.
|
||||
void enablePHDRCache();
|
70
libs/libcommon/src/phdr_cache.cpp
Normal file
70
libs/libcommon/src/phdr_cache.cpp
Normal file
@ -0,0 +1,70 @@
|
||||
/// This code was developed by Fedor Korotkiy (prime@yandex-team.ru) for YT product in Yandex.
|
||||
|
||||
#include <link.h>
|
||||
#include <dlfcn.h>
|
||||
#include <assert.h>
|
||||
#include <vector>
|
||||
#include <cstddef>
|
||||
#include <exception>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// This is adapted from
|
||||
// https://github.com/scylladb/seastar/blob/master/core/exception_hacks.hh
|
||||
// https://github.com/scylladb/seastar/blob/master/core/exception_hacks.cc
|
||||
|
||||
using DLIterateFunction = int (*) (int (*callback) (dl_phdr_info * info, size_t size, void * data), void * data);
|
||||
|
||||
DLIterateFunction getOriginalDLIteratePHDR()
|
||||
{
|
||||
void * func = dlsym(RTLD_NEXT, "dl_iterate_phdr");
|
||||
if (!func)
|
||||
throw std::runtime_error("Cannot find dl_iterate_phdr function with dlsym");
|
||||
return reinterpret_cast<DLIterateFunction>(func);
|
||||
}
|
||||
|
||||
// Never destroyed to avoid races with static destructors.
|
||||
using PHDRCache = std::vector<dl_phdr_info>;
|
||||
PHDRCache * phdr_cache;
|
||||
|
||||
}
|
||||
|
||||
|
||||
extern "C"
|
||||
#ifndef __clang__
|
||||
[[gnu::visibility("default")]]
|
||||
[[gnu::externally_visible]]
|
||||
#endif
|
||||
int dl_iterate_phdr(int (*callback) (dl_phdr_info * info, size_t size, void * data), void * data)
|
||||
{
|
||||
if (!phdr_cache)
|
||||
{
|
||||
// Cache is not yet populated, pass through to the original function.
|
||||
return getOriginalDLIteratePHDR()(callback, data);
|
||||
}
|
||||
|
||||
int result = 0;
|
||||
for (auto & info : *phdr_cache)
|
||||
{
|
||||
result = callback(&info, offsetof(dl_phdr_info, dlpi_adds), data);
|
||||
if (result != 0)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void enablePHDRCache()
|
||||
{
|
||||
#if defined(__linux__)
|
||||
// Fill out ELF header cache for access without locking.
|
||||
// This assumes no dynamic object loading/unloading after this point
|
||||
phdr_cache = new PHDRCache;
|
||||
getOriginalDLIteratePHDR()([] (dl_phdr_info * info, size_t /*size*/, void * /*data*/)
|
||||
{
|
||||
phdr_cache->push_back(*info);
|
||||
return 0;
|
||||
}, nullptr);
|
||||
#endif
|
||||
}
|
Loading…
Reference in New Issue
Block a user