Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(419)

Side by Side Diff: runtime/vm/malloc_hooks.cc

Issue 2715493005: Removed MallocHookScope and replaced it with MallocLocker, which behaves like MutexLocker but also … (Closed)
Patch Set: Pulled static member out of MallocLocker and into MallocHooksState. Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | runtime/vm/os_thread.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "platform/globals.h" 5 #include "platform/globals.h"
6 6
7 #if defined(DART_USE_TCMALLOC) && !defined(PRODUCT) 7 #if defined(DART_USE_TCMALLOC) && !defined(PRODUCT)
8 8
9 #include "vm/malloc_hooks.h" 9 #include "vm/malloc_hooks.h"
10 10
11 #include "gperftools/malloc_hook.h" 11 #include "gperftools/malloc_hook.h"
12 12
13 #include "platform/assert.h" 13 #include "platform/assert.h"
14 #include "vm/hash_map.h" 14 #include "vm/hash_map.h"
15 #include "vm/json_stream.h" 15 #include "vm/json_stream.h"
16 #include "vm/lockers.h" 16 #include "vm/os_thread.h"
17 17
18 namespace dart { 18 namespace dart {
19 19
20 // A locker-type class to automatically grab and release the 20 // A locker-type class similar to MutexLocker which tracks which thread
21 // in_malloc_hook_flag_. 21 // currently holds the lock. We use this instead of MutexLocker and
22 class MallocHookScope { 22 // mutex->IsOwnedByCurrentThread() since IsOwnedByCurrentThread() is only
23 // enabled for debug mode.
24 class MallocLocker : public ValueObject {
23 public: 25 public:
24 static void InitMallocHookFlag() { 26 explicit MallocLocker(Mutex* mutex, ThreadId* owner)
25 MutexLocker ml(malloc_hook_scope_mutex_); 27 : mutex_(mutex), owner_(owner) {
26 ASSERT(in_malloc_hook_flag_ == kUnsetThreadLocalKey); 28 ASSERT(owner != NULL);
27 in_malloc_hook_flag_ = OSThread::CreateThreadLocal(); 29 mutex_->Lock();
28 OSThread::SetThreadLocal(in_malloc_hook_flag_, 0); 30 ASSERT(*owner_ == OSThread::kInvalidThreadId);
31 *owner_ = OSThread::GetCurrentThreadId();
29 } 32 }
30 33
31 static void DestroyMallocHookFlag() { 34 virtual ~MallocLocker() {
32 MutexLocker ml(malloc_hook_scope_mutex_); 35 ASSERT(*owner_ == OSThread::GetCurrentThreadId());
33 ASSERT(in_malloc_hook_flag_ != kUnsetThreadLocalKey); 36 *owner_ = OSThread::kInvalidThreadId;
34 OSThread::DeleteThreadLocal(in_malloc_hook_flag_); 37 mutex_->Unlock();
35 in_malloc_hook_flag_ = kUnsetThreadLocalKey;
36 }
37
38 MallocHookScope() {
39 MutexLocker ml(malloc_hook_scope_mutex_);
40 ASSERT(in_malloc_hook_flag_ != kUnsetThreadLocalKey);
41 OSThread::SetThreadLocal(in_malloc_hook_flag_, 1);
42 }
43
44 ~MallocHookScope() {
45 MutexLocker ml(malloc_hook_scope_mutex_);
46 ASSERT(in_malloc_hook_flag_ != kUnsetThreadLocalKey);
47 OSThread::SetThreadLocal(in_malloc_hook_flag_, 0);
48 }
49
50 static bool IsInHook() {
51 MutexLocker ml(malloc_hook_scope_mutex_);
52 if (in_malloc_hook_flag_ == kUnsetThreadLocalKey) {
53 // Bail out if the malloc hook flag is invalid. This means that
54 // MallocHookState::TearDown() has been called and MallocHookScope is no
55 // longer intitialized. Don't worry if MallocHookState::TearDown() is
56 // called before the hooks grab the mutex, since
57 // MallocHooksState::Active() is checked after the lock is taken before
58 // proceeding to act on the allocation/free.
59 return false;
60 }
61 return OSThread::GetThreadLocal(in_malloc_hook_flag_);
62 } 38 }
63 39
64 private: 40 private:
65 static Mutex* malloc_hook_scope_mutex_; 41 Mutex* mutex_;
66 static ThreadLocalKey in_malloc_hook_flag_; 42 ThreadId* owner_;
67
68 DISALLOW_ALLOCATION();
69 DISALLOW_COPY_AND_ASSIGN(MallocHookScope);
70 }; 43 };
71 44
72 45
73 // Custom key/value trait specifically for address/size pairs. Unlike 46 // Custom key/value trait specifically for address/size pairs. Unlike
74 // RawPointerKeyValueTrait, the default value is -1 as 0 can be a valid entry. 47 // RawPointerKeyValueTrait, the default value is -1 as 0 can be a valid entry.
75 class AddressKeyValueTrait { 48 class AddressKeyValueTrait {
76 public: 49 public:
77 typedef const void* Key; 50 typedef const void* Key;
78 typedef intptr_t Value; 51 typedef intptr_t Value;
79 52
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
128 active_ = true; 101 active_ = true;
129 original_pid_ = OS::ProcessId(); 102 original_pid_ = OS::ProcessId();
130 } 103 }
131 104
132 static bool IsOriginalProcess() { 105 static bool IsOriginalProcess() {
133 ASSERT(original_pid_ != kInvalidPid); 106 ASSERT(original_pid_ != kInvalidPid);
134 return original_pid_ == OS::ProcessId(); 107 return original_pid_ == OS::ProcessId();
135 } 108 }
136 109
137 static Mutex* malloc_hook_mutex() { return malloc_hook_mutex_; } 110 static Mutex* malloc_hook_mutex() { return malloc_hook_mutex_; }
111 static ThreadId* malloc_hook_mutex_owner() {
112 return &malloc_hook_mutex_owner_;
113 }
114 static bool IsLockHeldByCurrentThread() {
115 return (malloc_hook_mutex_owner_ == OSThread::GetCurrentThreadId());
116 }
138 117
139 static intptr_t allocation_count() { return allocation_count_; } 118 static intptr_t allocation_count() { return allocation_count_; }
140 119
141 static intptr_t heap_allocated_memory_in_bytes() { 120 static intptr_t heap_allocated_memory_in_bytes() {
142 return heap_allocated_memory_in_bytes_; 121 return heap_allocated_memory_in_bytes_;
143 } 122 }
144 123
145 static void IncrementHeapAllocatedMemoryInBytes(intptr_t size) { 124 static void IncrementHeapAllocatedMemoryInBytes(intptr_t size) {
146 ASSERT(malloc_hook_mutex()->IsOwnedByCurrentThread()); 125 ASSERT(malloc_hook_mutex()->IsOwnedByCurrentThread());
147 ASSERT(size >= 0); 126 ASSERT(size >= 0);
(...skipping 24 matching lines...) Expand all
172 active_ = false; 151 active_ = false;
173 original_pid_ = kInvalidPid; 152 original_pid_ = kInvalidPid;
174 ResetStats(); 153 ResetStats();
175 delete address_map_; 154 delete address_map_;
176 } 155 }
177 156
178 private: 157 private:
179 static bool active_; 158 static bool active_;
180 static intptr_t original_pid_; 159 static intptr_t original_pid_;
181 static Mutex* malloc_hook_mutex_; 160 static Mutex* malloc_hook_mutex_;
161 static ThreadId malloc_hook_mutex_owner_;
182 static intptr_t allocation_count_; 162 static intptr_t allocation_count_;
183 static intptr_t heap_allocated_memory_in_bytes_; 163 static intptr_t heap_allocated_memory_in_bytes_;
184 static AddressMap* address_map_; 164 static AddressMap* address_map_;
185 165
186 static const intptr_t kInvalidPid = -1; 166 static const intptr_t kInvalidPid = -1;
187 }; 167 };
188 168
189 169
190 // MallocHookScope state.
191 Mutex* MallocHookScope::malloc_hook_scope_mutex_ = new Mutex();
192 ThreadLocalKey MallocHookScope::in_malloc_hook_flag_ = kUnsetThreadLocalKey;
193
194 // MallocHooks state / locks. 170 // MallocHooks state / locks.
195 bool MallocHooksState::active_ = false; 171 bool MallocHooksState::active_ = false;
196 intptr_t MallocHooksState::original_pid_ = MallocHooksState::kInvalidPid; 172 intptr_t MallocHooksState::original_pid_ = MallocHooksState::kInvalidPid;
197 Mutex* MallocHooksState::malloc_hook_mutex_ = new Mutex(); 173 Mutex* MallocHooksState::malloc_hook_mutex_ = new Mutex();
174 ThreadId MallocHooksState::malloc_hook_mutex_owner_ =
175 OSThread::kInvalidThreadId;
198 176
199 // Memory allocation state information. 177 // Memory allocation state information.
200 intptr_t MallocHooksState::allocation_count_ = 0; 178 intptr_t MallocHooksState::allocation_count_ = 0;
201 intptr_t MallocHooksState::heap_allocated_memory_in_bytes_ = 0; 179 intptr_t MallocHooksState::heap_allocated_memory_in_bytes_ = 0;
202 AddressMap* MallocHooksState::address_map_ = NULL; 180 AddressMap* MallocHooksState::address_map_ = NULL;
203 181
204 182
205 void MallocHooks::InitOnce() { 183 void MallocHooks::InitOnce() {
206 if (!FLAG_enable_malloc_hooks) { 184 if (!FLAG_enable_malloc_hooks) {
207 return; 185 return;
208 } 186 }
209 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); 187 MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
188 MallocHooksState::malloc_hook_mutex_owner());
210 ASSERT(!MallocHooksState::Active()); 189 ASSERT(!MallocHooksState::Active());
211 190
212 MallocHookScope::InitMallocHookFlag();
213 MallocHooksState::Init(); 191 MallocHooksState::Init();
214 192
215 // Register malloc hooks. 193 // Register malloc hooks.
216 bool success = false; 194 bool success = false;
217 success = MallocHook::AddNewHook(&MallocHooksState::RecordAllocHook); 195 success = MallocHook::AddNewHook(&MallocHooksState::RecordAllocHook);
218 ASSERT(success); 196 ASSERT(success);
219 success = MallocHook::AddDeleteHook(&MallocHooksState::RecordFreeHook); 197 success = MallocHook::AddDeleteHook(&MallocHooksState::RecordFreeHook);
220 ASSERT(success); 198 ASSERT(success);
221 } 199 }
222 200
223 201
224 void MallocHooks::TearDown() { 202 void MallocHooks::TearDown() {
225 if (!FLAG_enable_malloc_hooks) { 203 if (!FLAG_enable_malloc_hooks) {
226 return; 204 return;
227 } 205 }
228 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); 206 MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
207 MallocHooksState::malloc_hook_mutex_owner());
229 ASSERT(MallocHooksState::Active()); 208 ASSERT(MallocHooksState::Active());
230 209
231 // Remove malloc hooks. 210 // Remove malloc hooks.
232 bool success = false; 211 bool success = false;
233 success = MallocHook::RemoveNewHook(&MallocHooksState::RecordAllocHook); 212 success = MallocHook::RemoveNewHook(&MallocHooksState::RecordAllocHook);
234 ASSERT(success); 213 ASSERT(success);
235 success = MallocHook::RemoveDeleteHook(&MallocHooksState::RecordFreeHook); 214 success = MallocHook::RemoveDeleteHook(&MallocHooksState::RecordFreeHook);
236 ASSERT(success); 215 ASSERT(success);
237 216
238 MallocHooksState::TearDown(); 217 MallocHooksState::TearDown();
239 MallocHookScope::DestroyMallocHookFlag();
240 } 218 }
241 219
242 220
243 void MallocHooks::ResetStats() { 221 void MallocHooks::ResetStats() {
244 if (!FLAG_enable_malloc_hooks) { 222 if (!FLAG_enable_malloc_hooks) {
245 return; 223 return;
246 } 224 }
247 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); 225 MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
226 MallocHooksState::malloc_hook_mutex_owner());
248 if (MallocHooksState::Active()) { 227 if (MallocHooksState::Active()) {
249 MallocHooksState::ResetStats(); 228 MallocHooksState::ResetStats();
250 } 229 }
251 } 230 }
252 231
253 232
254 bool MallocHooks::Active() { 233 bool MallocHooks::Active() {
255 if (!FLAG_enable_malloc_hooks) { 234 if (!FLAG_enable_malloc_hooks) {
256 return false; 235 return false;
257 } 236 }
258 ASSERT(MallocHooksState::malloc_hook_mutex()->IsOwnedByCurrentThread()); 237 ASSERT(MallocHooksState::malloc_hook_mutex()->IsOwnedByCurrentThread());
259 return MallocHooksState::Active(); 238 return MallocHooksState::Active();
260 } 239 }
261 240
262 241
263 void MallocHooks::PrintToJSONObject(JSONObject* jsobj) { 242 void MallocHooks::PrintToJSONObject(JSONObject* jsobj) {
264 if (!FLAG_enable_malloc_hooks) { 243 if (!FLAG_enable_malloc_hooks) {
265 return; 244 return;
266 } 245 }
267 intptr_t allocated_memory = 0; 246 intptr_t allocated_memory = 0;
268 intptr_t allocation_count = 0; 247 intptr_t allocation_count = 0;
269 bool add_usage = false; 248 bool add_usage = false;
270 // AddProperty may call malloc which would result in an attempt 249 // AddProperty may call malloc which would result in an attempt
271 // to acquire the lock recursively so we extract the values first 250 // to acquire the lock recursively so we extract the values first
272 // and then add the JSON properties. 251 // and then add the JSON properties.
273 { 252 {
274 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); 253 MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
254 MallocHooksState::malloc_hook_mutex_owner());
275 if (Active()) { 255 if (Active()) {
276 allocated_memory = MallocHooksState::heap_allocated_memory_in_bytes(); 256 allocated_memory = MallocHooksState::heap_allocated_memory_in_bytes();
277 allocation_count = MallocHooksState::allocation_count(); 257 allocation_count = MallocHooksState::allocation_count();
278 add_usage = true; 258 add_usage = true;
279 } 259 }
280 } 260 }
281 if (add_usage) { 261 if (add_usage) {
282 jsobj->AddProperty("_heapAllocatedMemoryUsage", allocated_memory); 262 jsobj->AddProperty("_heapAllocatedMemoryUsage", allocated_memory);
283 jsobj->AddProperty("_heapAllocationCount", allocation_count); 263 jsobj->AddProperty("_heapAllocationCount", allocation_count);
284 } 264 }
285 } 265 }
286 266
287 267
288 intptr_t MallocHooks::allocation_count() { 268 intptr_t MallocHooks::allocation_count() {
289 if (!FLAG_enable_malloc_hooks) { 269 if (!FLAG_enable_malloc_hooks) {
290 return 0; 270 return 0;
291 } 271 }
292 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); 272 MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
273 MallocHooksState::malloc_hook_mutex_owner());
293 return MallocHooksState::allocation_count(); 274 return MallocHooksState::allocation_count();
294 } 275 }
295 276
296 277
297 intptr_t MallocHooks::heap_allocated_memory_in_bytes() { 278 intptr_t MallocHooks::heap_allocated_memory_in_bytes() {
298 if (!FLAG_enable_malloc_hooks) { 279 if (!FLAG_enable_malloc_hooks) {
299 return 0; 280 return 0;
300 } 281 }
301 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); 282 MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
283 MallocHooksState::malloc_hook_mutex_owner());
302 return MallocHooksState::heap_allocated_memory_in_bytes(); 284 return MallocHooksState::heap_allocated_memory_in_bytes();
303 } 285 }
304 286
305 287
306 void MallocHooksState::RecordAllocHook(const void* ptr, size_t size) { 288 void MallocHooksState::RecordAllocHook(const void* ptr, size_t size) {
307 if (MallocHookScope::IsInHook() || !MallocHooksState::IsOriginalProcess()) { 289 if (MallocHooksState::IsLockHeldByCurrentThread() ||
290 !MallocHooksState::IsOriginalProcess()) {
308 return; 291 return;
309 } 292 }
310 293
311 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); 294 MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
295 MallocHooksState::malloc_hook_mutex_owner());
312 // Now that we hold the lock, check to make sure everything is still active. 296 // Now that we hold the lock, check to make sure everything is still active.
313 if ((ptr != NULL) && MallocHooksState::Active()) { 297 if ((ptr != NULL) && MallocHooksState::Active()) {
314 // Set the malloc hook flag to avoid calling hooks again if memory is
315 // allocated/freed below.
316 MallocHookScope mhs;
317 MallocHooksState::IncrementHeapAllocatedMemoryInBytes(size); 298 MallocHooksState::IncrementHeapAllocatedMemoryInBytes(size);
318 MallocHooksState::address_map()->Insert(ptr, size); 299 MallocHooksState::address_map()->Insert(ptr, size);
319 } 300 }
320 } 301 }
321 302
322 303
323 void MallocHooksState::RecordFreeHook(const void* ptr) { 304 void MallocHooksState::RecordFreeHook(const void* ptr) {
324 if (MallocHookScope::IsInHook() || !MallocHooksState::IsOriginalProcess()) { 305 if (MallocHooksState::IsLockHeldByCurrentThread() ||
306 !MallocHooksState::IsOriginalProcess()) {
325 return; 307 return;
326 } 308 }
327 309
328 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); 310 MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
311 MallocHooksState::malloc_hook_mutex_owner());
329 // Now that we hold the lock, check to make sure everything is still active. 312 // Now that we hold the lock, check to make sure everything is still active.
330 if ((ptr != NULL) && MallocHooksState::Active()) { 313 if ((ptr != NULL) && MallocHooksState::Active()) {
331 // Set the malloc hook flag to avoid calling hooks again if memory is
332 // allocated/freed below.
333 MallocHookScope mhs;
334 intptr_t size = 0; 314 intptr_t size = 0;
335 if (MallocHooksState::address_map()->Lookup(ptr, &size)) { 315 if (MallocHooksState::address_map()->Lookup(ptr, &size)) {
336 MallocHooksState::DecrementHeapAllocatedMemoryInBytes(size); 316 MallocHooksState::DecrementHeapAllocatedMemoryInBytes(size);
337 MallocHooksState::address_map()->Remove(ptr); 317 MallocHooksState::address_map()->Remove(ptr);
338 } 318 }
339 } 319 }
340 } 320 }
341 321
342 } // namespace dart 322 } // namespace dart
343 323
344 #endif // defined(DART_USE_TCMALLOC) && !defined(PRODUCT) 324 #endif // defined(DART_USE_TCMALLOC) && !defined(PRODUCT)
OLDNEW
« no previous file with comments | « no previous file | runtime/vm/os_thread.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698