| OLD | NEW |
| 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/lockers.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 to automatically grab and release the |
| 21 // in_malloc_hook_flag_. | 21 // in_malloc_hook_flag_. |
| 22 class MallocHookScope { | 22 class MallocHookScope { |
| 23 public: | 23 public: |
| 24 static void InitMallocHookFlag() { | 24 static void InitMallocHookFlag() { |
| 25 MutexLocker ml(malloc_hook_scope_mutex_); |
| 25 ASSERT(in_malloc_hook_flag_ == kUnsetThreadLocalKey); | 26 ASSERT(in_malloc_hook_flag_ == kUnsetThreadLocalKey); |
| 26 in_malloc_hook_flag_ = OSThread::CreateThreadLocal(); | 27 in_malloc_hook_flag_ = OSThread::CreateThreadLocal(); |
| 27 OSThread::SetThreadLocal(in_malloc_hook_flag_, 0); | 28 OSThread::SetThreadLocal(in_malloc_hook_flag_, 0); |
| 28 } | 29 } |
| 29 | 30 |
| 30 static void DestroyMallocHookFlag() { | 31 static void DestroyMallocHookFlag() { |
| 32 MutexLocker ml(malloc_hook_scope_mutex_); |
| 31 ASSERT(in_malloc_hook_flag_ != kUnsetThreadLocalKey); | 33 ASSERT(in_malloc_hook_flag_ != kUnsetThreadLocalKey); |
| 32 OSThread::DeleteThreadLocal(in_malloc_hook_flag_); | 34 OSThread::DeleteThreadLocal(in_malloc_hook_flag_); |
| 33 in_malloc_hook_flag_ = kUnsetThreadLocalKey; | 35 in_malloc_hook_flag_ = kUnsetThreadLocalKey; |
| 34 } | 36 } |
| 35 | 37 |
| 36 MallocHookScope() { | 38 MallocHookScope() { |
| 39 MutexLocker ml(malloc_hook_scope_mutex_); |
| 37 ASSERT(in_malloc_hook_flag_ != kUnsetThreadLocalKey); | 40 ASSERT(in_malloc_hook_flag_ != kUnsetThreadLocalKey); |
| 38 OSThread::SetThreadLocal(in_malloc_hook_flag_, 1); | 41 OSThread::SetThreadLocal(in_malloc_hook_flag_, 1); |
| 39 } | 42 } |
| 40 | 43 |
| 41 ~MallocHookScope() { | 44 ~MallocHookScope() { |
| 45 MutexLocker ml(malloc_hook_scope_mutex_); |
| 42 ASSERT(in_malloc_hook_flag_ != kUnsetThreadLocalKey); | 46 ASSERT(in_malloc_hook_flag_ != kUnsetThreadLocalKey); |
| 43 OSThread::SetThreadLocal(in_malloc_hook_flag_, 0); | 47 OSThread::SetThreadLocal(in_malloc_hook_flag_, 0); |
| 44 } | 48 } |
| 45 | 49 |
| 46 static bool IsInHook() { | 50 static bool IsInHook() { |
| 47 ASSERT(in_malloc_hook_flag_ != kUnsetThreadLocalKey); | 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 } |
| 48 return OSThread::GetThreadLocal(in_malloc_hook_flag_); | 61 return OSThread::GetThreadLocal(in_malloc_hook_flag_); |
| 49 } | 62 } |
| 50 | 63 |
| 51 private: | 64 private: |
| 65 static Mutex* malloc_hook_scope_mutex_; |
| 52 static ThreadLocalKey in_malloc_hook_flag_; | 66 static ThreadLocalKey in_malloc_hook_flag_; |
| 53 | 67 |
| 54 DISALLOW_ALLOCATION(); | 68 DISALLOW_ALLOCATION(); |
| 55 DISALLOW_COPY_AND_ASSIGN(MallocHookScope); | 69 DISALLOW_COPY_AND_ASSIGN(MallocHookScope); |
| 56 }; | 70 }; |
| 57 | 71 |
| 58 | 72 |
| 59 // Custom key/value trait specifically for address/size pairs. Unlike | 73 // Custom key/value trait specifically for address/size pairs. Unlike |
| 60 // RawPointerKeyValueTrait, the default value is -1 as 0 can be a valid entry. | 74 // RawPointerKeyValueTrait, the default value is -1 as 0 can be a valid entry. |
| 61 class AddressKeyValueTrait { | 75 class AddressKeyValueTrait { |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 166 static intptr_t original_pid_; | 180 static intptr_t original_pid_; |
| 167 static Mutex* malloc_hook_mutex_; | 181 static Mutex* malloc_hook_mutex_; |
| 168 static intptr_t allocation_count_; | 182 static intptr_t allocation_count_; |
| 169 static intptr_t heap_allocated_memory_in_bytes_; | 183 static intptr_t heap_allocated_memory_in_bytes_; |
| 170 static AddressMap* address_map_; | 184 static AddressMap* address_map_; |
| 171 | 185 |
| 172 static const intptr_t kInvalidPid = -1; | 186 static const intptr_t kInvalidPid = -1; |
| 173 }; | 187 }; |
| 174 | 188 |
| 175 | 189 |
| 190 // MallocHookScope state. |
| 191 Mutex* MallocHookScope::malloc_hook_scope_mutex_ = new Mutex(); |
| 192 ThreadLocalKey MallocHookScope::in_malloc_hook_flag_ = kUnsetThreadLocalKey; |
| 193 |
| 176 // MallocHooks state / locks. | 194 // MallocHooks state / locks. |
| 177 ThreadLocalKey MallocHookScope::in_malloc_hook_flag_ = kUnsetThreadLocalKey; | |
| 178 bool MallocHooksState::active_ = false; | 195 bool MallocHooksState::active_ = false; |
| 179 intptr_t MallocHooksState::original_pid_ = MallocHooksState::kInvalidPid; | 196 intptr_t MallocHooksState::original_pid_ = MallocHooksState::kInvalidPid; |
| 180 Mutex* MallocHooksState::malloc_hook_mutex_ = new Mutex(); | 197 Mutex* MallocHooksState::malloc_hook_mutex_ = new Mutex(); |
| 181 | 198 |
| 182 // Memory allocation state information. | 199 // Memory allocation state information. |
| 183 intptr_t MallocHooksState::allocation_count_ = 0; | 200 intptr_t MallocHooksState::allocation_count_ = 0; |
| 184 intptr_t MallocHooksState::heap_allocated_memory_in_bytes_ = 0; | 201 intptr_t MallocHooksState::heap_allocated_memory_in_bytes_ = 0; |
| 185 AddressMap* MallocHooksState::address_map_ = NULL; | 202 AddressMap* MallocHooksState::address_map_ = NULL; |
| 186 | 203 |
| 187 | 204 |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 263 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); | 280 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); |
| 264 return MallocHooksState::heap_allocated_memory_in_bytes(); | 281 return MallocHooksState::heap_allocated_memory_in_bytes(); |
| 265 } | 282 } |
| 266 | 283 |
| 267 | 284 |
| 268 void MallocHooksState::RecordAllocHook(const void* ptr, size_t size) { | 285 void MallocHooksState::RecordAllocHook(const void* ptr, size_t size) { |
| 269 if (MallocHookScope::IsInHook() || !MallocHooksState::IsOriginalProcess()) { | 286 if (MallocHookScope::IsInHook() || !MallocHooksState::IsOriginalProcess()) { |
| 270 return; | 287 return; |
| 271 } | 288 } |
| 272 | 289 |
| 273 // Set the malloc hook flag before grabbing the mutex to avoid calling hooks | |
| 274 // again. | |
| 275 MallocHookScope mhs; | |
| 276 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); | 290 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); |
| 291 // Now that we hold the lock, check to make sure everything is still active. |
| 277 if ((ptr != NULL) && MallocHooksState::Active()) { | 292 if ((ptr != NULL) && MallocHooksState::Active()) { |
| 293 // Set the malloc hook flag to avoid calling hooks again if memory is |
| 294 // allocated/freed below. |
| 295 MallocHookScope mhs; |
| 278 MallocHooksState::IncrementHeapAllocatedMemoryInBytes(size); | 296 MallocHooksState::IncrementHeapAllocatedMemoryInBytes(size); |
| 279 MallocHooksState::address_map()->Insert(ptr, size); | 297 MallocHooksState::address_map()->Insert(ptr, size); |
| 280 } | 298 } |
| 281 } | 299 } |
| 282 | 300 |
| 283 | 301 |
| 284 void MallocHooksState::RecordFreeHook(const void* ptr) { | 302 void MallocHooksState::RecordFreeHook(const void* ptr) { |
| 285 if (MallocHookScope::IsInHook() || !MallocHooksState::IsOriginalProcess()) { | 303 if (MallocHookScope::IsInHook() || !MallocHooksState::IsOriginalProcess()) { |
| 286 return; | 304 return; |
| 287 } | 305 } |
| 288 | 306 |
| 289 // Set the malloc hook flag before grabbing the mutex to avoid calling hooks | |
| 290 // again. | |
| 291 MallocHookScope mhs; | |
| 292 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); | 307 MutexLocker ml(MallocHooksState::malloc_hook_mutex()); |
| 308 // Now that we hold the lock, check to make sure everything is still active. |
| 293 if ((ptr != NULL) && MallocHooksState::Active()) { | 309 if ((ptr != NULL) && MallocHooksState::Active()) { |
| 310 // Set the malloc hook flag to avoid calling hooks again if memory is |
| 311 // allocated/freed below. |
| 312 MallocHookScope mhs; |
| 294 intptr_t size = 0; | 313 intptr_t size = 0; |
| 295 if (MallocHooksState::address_map()->Lookup(ptr, &size)) { | 314 if (MallocHooksState::address_map()->Lookup(ptr, &size)) { |
| 296 MallocHooksState::DecrementHeapAllocatedMemoryInBytes(size); | 315 MallocHooksState::DecrementHeapAllocatedMemoryInBytes(size); |
| 297 MallocHooksState::address_map()->Remove(ptr); | 316 MallocHooksState::address_map()->Remove(ptr); |
| 298 } | 317 } |
| 299 } | 318 } |
| 300 } | 319 } |
| 301 | 320 |
| 302 } // namespace dart | 321 } // namespace dart |
| 303 | 322 |
| 304 #endif // defined(DART_USE_TCMALLOC) && !defined(PRODUCT) | 323 #endif // defined(DART_USE_TCMALLOC) && !defined(PRODUCT) |
| OLD | NEW |