blob: da18b698f0d18b76a66ed80f721fb10cc304084e [file]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
// This file is copied from
// https://github.com/ClickHouse/ClickHouse/blob/master/src/base/phdr_cache.h
// and modified by Doris
#pragma once
#if defined(__linux__) && !defined(THREAD_SANITIZER) && !defined(USE_MUSL)
#include <link.h>
#include <cstddef>
#include <cstdint>
#endif
/// This code was based on the code by Fedor Korotkiy https://www.linkedin.com/in/fedor-korotkiy-659a1838/
/** Collects loaded-object PHDR metadata into a lock-free snapshot.
* Doris uses this snapshot in two narrow places where entering glibc's loader lock can deadlock:
* the BE stack-trace signal handler and Doris-patched GNU libunwind's FDE lookup. Both paths may
* run while another thread is inside dlopen/dlclose or jemalloc profiling.
*
* Normal code paths must keep using the original glibc dl_iterate_phdr. Process-wide use of a
* snapshot can hide libraries loaded after the last refresh from sanitizers, JVM/Jindo native
* code, and C++ exception handling. Use ScopedPHDRCacheRead only around the minimal
* signal-handler unwind section; GNU libunwind reaches this cache through
* doris_unwind_iterate_phdr without changing ordinary dl_iterate_phdr callers.
*
* Old cache snapshots are intentionally leaked and remain readable by concurrent signal-handler
* unwinders.
*
* NOTE: It is disabled with Thread Sanitizer because TSan can only use original "dl_iterate_phdr" function.
*/
void updatePHDRCache();
/** Configure GNU libunwind to use the PHDR snapshot without its global register-state cache. */
void configureLibunwindPHDRCache();
/** Check if a PHDR snapshot is available for ScopedPHDRCacheRead. */
bool hasPHDRCache();
#if defined(__linux__) && !defined(THREAD_SANITIZER) && !defined(USE_MUSL)
/**
* GNU libunwind calls this weak hook from Doris-patched thirdparty libunwind instead of calling
* glibc dl_iterate_phdr directly. The hook is intentionally narrower than the process-wide
* dl_iterate_phdr interposer: ordinary loader users still see glibc's live loader list, while
* libunwind reads Doris' lock-free PHDR snapshot to avoid loader-lock inversions during profiling
* and signal-context stack capture.
*/
extern "C" int doris_unwind_iterate_phdr(int (*callback)(dl_phdr_info* info, size_t size,
void* data),
void* data, uintptr_t ip);
#endif
class ScopedPHDRCacheRead {
public:
ScopedPHDRCacheRead();
~ScopedPHDRCacheRead();
ScopedPHDRCacheRead(const ScopedPHDRCacheRead&) = delete;
ScopedPHDRCacheRead& operator=(const ScopedPHDRCacheRead&) = delete;
private:
bool _previous = false;
};