reentry_guard.h 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. // Copyright (c) 2022 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef BASE_ALLOCATOR_DISPATCHER_REENTRY_GUARD_H_
  5. #define BASE_ALLOCATOR_DISPATCHER_REENTRY_GUARD_H_
  6. #include "base/base_export.h"
  7. #include "base/check.h"
  8. #include "base/compiler_specific.h"
  9. #include "build/build_config.h"
  10. #if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_ANDROID)
  11. #include <pthread.h>
  12. #endif
  13. namespace base::allocator::dispatcher {
  14. #if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_ANDROID)
  15. // The macOS implementation of libmalloc sometimes calls malloc recursively,
  16. // delegating allocations between zones. That causes our hooks being called
  17. // twice. The scoped guard allows us to detect that.
  18. //
  19. // Besides that the implementations of thread_local on macOS and Android
  20. // seem to allocate memory lazily on the first access to thread_local variables.
  21. // Make use of pthread TLS instead of C++ thread_local there.
  22. struct BASE_EXPORT ReentryGuard {
  23. ReentryGuard() : allowed_(!pthread_getspecific(entered_key_)) {
  24. pthread_setspecific(entered_key_, reinterpret_cast<void*>(true));
  25. }
  26. ~ReentryGuard() {
  27. if (LIKELY(allowed_))
  28. pthread_setspecific(entered_key_, nullptr);
  29. }
  30. explicit operator bool() const noexcept { return allowed_; }
  31. // This function must be called in very early of the process start-up in
  32. // order to acquire a low TLS slot number because glibc TLS implementation
  33. // will require a malloc call to allocate storage for a higher slot number
  34. // (>= PTHREAD_KEY_2NDLEVEL_SIZE == 32). c.f. heap_profiling::InitTLSSlot.
  35. static void InitTLSSlot();
  36. private:
  37. static pthread_key_t entered_key_;
  38. const bool allowed_;
  39. };
  40. #else
  41. // Use [[maybe_unused]] as this lightweight stand-in for the more heavyweight
  42. // ReentryGuard above will otherwise trigger the "unused code" warnings.
  43. struct [[maybe_unused]] BASE_EXPORT ReentryGuard {
  44. constexpr explicit operator bool() const noexcept { return true; }
  45. static void InitTLSSlot();
  46. };
  47. #endif
  48. } // namespace base::allocator::dispatcher
  49. #endif // BASE_ALLOCATOR_DISPATCHER_REENTRY_GUARD_H_