File: tls.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (167 lines) | stat: -rw-r--r-- 5,351 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
// 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.

#include "base/allocator/dispatcher/tls.h"

#include <string_view>

#if USE_LOCAL_TLS_EMULATION()

#include <sys/mman.h>

#include "base/check.h"
#include "base/dcheck_is_on.h"
#include "base/debug/crash_logging.h"
#include "base/immediate_crash.h"
#include "build/build_config.h"

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX)
#include <sys/prctl.h>
#endif

namespace base::allocator::dispatcher::internal {
namespace {
base::debug::CrashKeySize GetCrashKeySize(const std::string& crash_key_name) {
  if (std::size(crash_key_name) <= 32ul) {
    return base::debug::CrashKeySize::Size32;
  }
  if (std::size(crash_key_name) <= 64ul) {
    return base::debug::CrashKeySize::Size64;
  }
  if (std::size(crash_key_name) <= 256ul) {
    return base::debug::CrashKeySize::Size256;
  }
  CHECK(std::size(crash_key_name) <= 1024ul);

  return base::debug::CrashKeySize::Size1024;
}

#if DCHECK_IS_ON()
void Swap(std::atomic_bool& lh_op, std::atomic_bool& rh_op) {
  auto lh_op_value = lh_op.load(std::memory_order_relaxed);
  auto rh_op_value = rh_op.load(std::memory_order_relaxed);

  CHECK(lh_op.compare_exchange_strong(lh_op_value, rh_op_value));
  CHECK(rh_op.compare_exchange_strong(rh_op_value, lh_op_value));
}
#endif
}  // namespace

void* MMapAllocator::AllocateMemory(size_t size_in_bytes) {
  void* const mmap_res = mmap(nullptr, size_in_bytes, PROT_READ | PROT_WRITE,
                              MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX)
#if defined(PR_SET_VMA) && defined(PR_SET_VMA_ANON_NAME)
  if (mmap_res != MAP_FAILED) {
    // Allow the anonymous memory region allocated by mmap(MAP_ANONYMOUS) to
    // be identified in /proc/$PID/smaps.  This helps improve visibility into
    // Chromium's memory usage on Android.
    prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, mmap_res, size_in_bytes,
          "tls-mmap-allocator");
  }
#endif
#endif

  return (mmap_res != MAP_FAILED) ? mmap_res : nullptr;
}

bool MMapAllocator::FreeMemoryForTesting(void* pointer_to_allocated,
                                         size_t size_in_bytes) {
  auto const munmap_res = munmap(pointer_to_allocated, size_in_bytes);
  return (munmap_res == 0);
}

PThreadTLSSystem::PThreadTLSSystem() = default;

PThreadTLSSystem::PThreadTLSSystem(PThreadTLSSystem&& other) {
  std::swap(crash_key_, other.crash_key_);
  std::swap(data_access_key_, other.data_access_key_);

#if DCHECK_IS_ON()
  Swap(initialized_, other.initialized_);
#endif
}

PThreadTLSSystem& PThreadTLSSystem::operator=(PThreadTLSSystem&& other) {
  std::swap(crash_key_, other.crash_key_);
  std::swap(data_access_key_, other.data_access_key_);

#if DCHECK_IS_ON()
  Swap(initialized_, other.initialized_);
#endif

  return *this;
}

bool PThreadTLSSystem::Setup(
    OnThreadTerminationFunction thread_termination_function,
    std::string_view instance_id) {
#if DCHECK_IS_ON()
  // Initialize must happen outside of the allocation path. Therefore, it is
  // secure to verify with DCHECK.
  DCHECK(!initialized_.exchange(true, std::memory_order_acq_rel));
#endif

  auto const key_create_res =
      pthread_key_create(&data_access_key_, thread_termination_function);

  // On some platforms creating a new pthread-key requires an allocation when a
  // given number of keys has been created. I.e. in glibc this limit is denoted
  // by PTHREAD_KEY_2NDLEVEL_SIZE. However, this value is neither present on all
  // systems nor accessible from here. Hence, we do not do any checks here.
  // However, we strongly recommend to setup the TLS system as early as possible
  // to avoid exceeding this limit.

  // Some crashes might be caused by the initialization being performed too late
  // and running into the problems mentioned above. Since there's no way to
  // handle this issue programmatically, we include the key into the crashpad
  // report to allow for later inspection.
  std::string crash_key_name = "tls_system-";
  crash_key_name += instance_id;

  crash_key_ = base::debug::AllocateCrashKeyString(
      crash_key_name.c_str(), GetCrashKeySize(crash_key_name));
  base::debug::SetCrashKeyString(crash_key_,
                                 base::NumberToString(data_access_key_));

  return (0 == key_create_res);
}

bool PThreadTLSSystem::TearDownForTesting() {
#if DCHECK_IS_ON()
  // TearDownForTesting must happen outside of the allocation path. Therefore,
  // it is secure to verify with DCHECK.
  DCHECK(initialized_.exchange(false, std::memory_order_acq_rel));
#endif

  base::debug::ClearCrashKeyString(crash_key_);
  crash_key_ = nullptr;

  auto const key_delete_res = pthread_key_delete(data_access_key_);
  return (0 == key_delete_res);
}

void* PThreadTLSSystem::GetThreadSpecificData() {
#if DCHECK_IS_ON()
  if (!initialized_.load(std::memory_order_acquire)) {
    return nullptr;
  }
#endif

  return pthread_getspecific(data_access_key_);
}

bool PThreadTLSSystem::SetThreadSpecificData(void* data) {
#if DCHECK_IS_ON()
  if (!initialized_.load(std::memory_order_acquire)) {
    return false;
  }
#endif

  return (0 == pthread_setspecific(data_access_key_, data));
}

}  // namespace base::allocator::dispatcher::internal

#endif  // USE_LOCAL_TLS_EMULATION()