mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2025-04-02 05:16:20 +03:00
75 lines
2.6 KiB
C++
75 lines
2.6 KiB
C++
// Copyright 2022 The Chromium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#ifndef BASE_ALLOCATOR_DISPATCHER_REENTRY_GUARD_H_
|
|
#define BASE_ALLOCATOR_DISPATCHER_REENTRY_GUARD_H_
|
|
|
|
#include "base/base_export.h"
|
|
#include "base/check.h"
|
|
#include "base/compiler_specific.h"
|
|
#include "build/build_config.h"
|
|
|
|
#if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_ANDROID)
|
|
#include <pthread.h>
|
|
#endif
|
|
|
|
namespace base::allocator::dispatcher {
|
|
|
|
#if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_ANDROID)
|
|
|
|
// The macOS implementation of libmalloc sometimes calls malloc recursively,
|
|
// delegating allocations between zones. That causes our hooks being called
|
|
// twice. The scoped guard allows us to detect that.
|
|
//
|
|
// Besides that the implementations of thread_local on macOS and Android
|
|
// seem to allocate memory lazily on the first access to thread_local variables
|
|
// (and on Android at least thread_local is implemented on top of pthread so is
|
|
// strictly worse for performance). Make use of pthread TLS instead of C++
|
|
// thread_local there.
|
|
struct BASE_EXPORT ReentryGuard {
|
|
ALWAYS_INLINE ReentryGuard() : allowed_(!pthread_getspecific(entered_key_)) {
|
|
pthread_setspecific(entered_key_, reinterpret_cast<void*>(true));
|
|
}
|
|
|
|
ALWAYS_INLINE ~ReentryGuard() {
|
|
if (LIKELY(allowed_))
|
|
pthread_setspecific(entered_key_, nullptr);
|
|
}
|
|
|
|
explicit operator bool() const noexcept { return allowed_; }
|
|
|
|
// This function must be called before installing any allocator hooks because
|
|
// some TLS implementations may allocate (eg. glibc will require a malloc call
|
|
// to allocate storage for a higher slot number (>= PTHREAD_KEY_2NDLEVEL_SIZE
|
|
// == 32). This touches the thread-local storage so that any malloc happens
|
|
// before installing the hooks.
|
|
static void InitTLSSlot();
|
|
|
|
// InitTLSSlot() is called before crash keys are available. At some point
|
|
// after SetCrashKeyImplementation() is called, this function should be
|
|
// called to record `entered_key_` to a crash key for debugging. This may
|
|
// allocate so it must not be called from inside an allocator hook.
|
|
static void RecordTLSSlotToCrashKey();
|
|
|
|
private:
|
|
static pthread_key_t entered_key_;
|
|
const bool allowed_;
|
|
};
|
|
|
|
#else
|
|
|
|
// Use [[maybe_unused]] as this lightweight stand-in for the more heavyweight
|
|
// ReentryGuard above will otherwise trigger the "unused code" warnings.
|
|
struct [[maybe_unused]] BASE_EXPORT ReentryGuard {
|
|
constexpr explicit operator bool() const noexcept { return true; }
|
|
|
|
static void InitTLSSlot();
|
|
static void RecordTLSSlotToCrashKey();
|
|
};
|
|
|
|
#endif
|
|
|
|
} // namespace base::allocator::dispatcher
|
|
|
|
#endif // BASE_ALLOCATOR_DISPATCHER_REENTRY_GUARD_H_
|