| Index: runtime/vm/malloc_hooks.cc
|
| diff --git a/runtime/vm/malloc_hooks.cc b/runtime/vm/malloc_hooks.cc
|
| index 4f7de9e20d70b8b4c0326e5d47d996f0496ea5dc..a85d22e85f306300ee3b7f499290bd4a7f3f7846 100644
|
| --- a/runtime/vm/malloc_hooks.cc
|
| +++ b/runtime/vm/malloc_hooks.cc
|
| @@ -13,60 +13,33 @@
|
| #include "platform/assert.h"
|
| #include "vm/hash_map.h"
|
| #include "vm/json_stream.h"
|
| -#include "vm/lockers.h"
|
| +#include "vm/os_thread.h"
|
|
|
| namespace dart {
|
|
|
| -// A locker-type class to automatically grab and release the
|
| -// in_malloc_hook_flag_.
|
| -class MallocHookScope {
|
| +// A locker-type class similar to MutexLocker which tracks which thread
|
| +// currently holds the lock. We use this instead of MutexLocker and
|
| +// mutex->IsOwnedByCurrentThread() since IsOwnedByCurrentThread() is only
|
| +// enabled for debug mode.
|
| +class MallocLocker : public ValueObject {
|
| public:
|
| - static void InitMallocHookFlag() {
|
| - MutexLocker ml(malloc_hook_scope_mutex_);
|
| - ASSERT(in_malloc_hook_flag_ == kUnsetThreadLocalKey);
|
| - in_malloc_hook_flag_ = OSThread::CreateThreadLocal();
|
| - OSThread::SetThreadLocal(in_malloc_hook_flag_, 0);
|
| + explicit MallocLocker(Mutex* mutex, ThreadId* owner)
|
| + : mutex_(mutex), owner_(owner) {
|
| + ASSERT(owner != NULL);
|
| + mutex_->Lock();
|
| + ASSERT(*owner_ == OSThread::kInvalidThreadId);
|
| + *owner_ = OSThread::GetCurrentThreadId();
|
| }
|
|
|
| - static void DestroyMallocHookFlag() {
|
| - MutexLocker ml(malloc_hook_scope_mutex_);
|
| - ASSERT(in_malloc_hook_flag_ != kUnsetThreadLocalKey);
|
| - OSThread::DeleteThreadLocal(in_malloc_hook_flag_);
|
| - in_malloc_hook_flag_ = kUnsetThreadLocalKey;
|
| - }
|
| -
|
| - MallocHookScope() {
|
| - MutexLocker ml(malloc_hook_scope_mutex_);
|
| - ASSERT(in_malloc_hook_flag_ != kUnsetThreadLocalKey);
|
| - OSThread::SetThreadLocal(in_malloc_hook_flag_, 1);
|
| - }
|
| -
|
| - ~MallocHookScope() {
|
| - MutexLocker ml(malloc_hook_scope_mutex_);
|
| - ASSERT(in_malloc_hook_flag_ != kUnsetThreadLocalKey);
|
| - OSThread::SetThreadLocal(in_malloc_hook_flag_, 0);
|
| - }
|
| -
|
| - static bool IsInHook() {
|
| - MutexLocker ml(malloc_hook_scope_mutex_);
|
| - if (in_malloc_hook_flag_ == kUnsetThreadLocalKey) {
|
| - // Bail out if the malloc hook flag is invalid. This means that
|
| - // MallocHookState::TearDown() has been called and MallocHookScope is no
|
| - // longer intitialized. Don't worry if MallocHookState::TearDown() is
|
| - // called before the hooks grab the mutex, since
|
| - // MallocHooksState::Active() is checked after the lock is taken before
|
| - // proceeding to act on the allocation/free.
|
| - return false;
|
| - }
|
| - return OSThread::GetThreadLocal(in_malloc_hook_flag_);
|
| + virtual ~MallocLocker() {
|
| + ASSERT(*owner_ == OSThread::GetCurrentThreadId());
|
| + *owner_ = OSThread::kInvalidThreadId;
|
| + mutex_->Unlock();
|
| }
|
|
|
| private:
|
| - static Mutex* malloc_hook_scope_mutex_;
|
| - static ThreadLocalKey in_malloc_hook_flag_;
|
| -
|
| - DISALLOW_ALLOCATION();
|
| - DISALLOW_COPY_AND_ASSIGN(MallocHookScope);
|
| + Mutex* mutex_;
|
| + ThreadId* owner_;
|
| };
|
|
|
|
|
| @@ -135,6 +108,12 @@ class MallocHooksState : public AllStatic {
|
| }
|
|
|
| static Mutex* malloc_hook_mutex() { return malloc_hook_mutex_; }
|
| + static ThreadId* malloc_hook_mutex_owner() {
|
| + return &malloc_hook_mutex_owner_;
|
| + }
|
| + static bool IsLockHeldByCurrentThread() {
|
| + return (malloc_hook_mutex_owner_ == OSThread::GetCurrentThreadId());
|
| + }
|
|
|
| static intptr_t allocation_count() { return allocation_count_; }
|
|
|
| @@ -179,6 +158,7 @@ class MallocHooksState : public AllStatic {
|
| static bool active_;
|
| static intptr_t original_pid_;
|
| static Mutex* malloc_hook_mutex_;
|
| + static ThreadId malloc_hook_mutex_owner_;
|
| static intptr_t allocation_count_;
|
| static intptr_t heap_allocated_memory_in_bytes_;
|
| static AddressMap* address_map_;
|
| @@ -187,14 +167,12 @@ class MallocHooksState : public AllStatic {
|
| };
|
|
|
|
|
| -// MallocHookScope state.
|
| -Mutex* MallocHookScope::malloc_hook_scope_mutex_ = new Mutex();
|
| -ThreadLocalKey MallocHookScope::in_malloc_hook_flag_ = kUnsetThreadLocalKey;
|
| -
|
| // MallocHooks state / locks.
|
| bool MallocHooksState::active_ = false;
|
| intptr_t MallocHooksState::original_pid_ = MallocHooksState::kInvalidPid;
|
| Mutex* MallocHooksState::malloc_hook_mutex_ = new Mutex();
|
| +ThreadId MallocHooksState::malloc_hook_mutex_owner_ =
|
| + OSThread::kInvalidThreadId;
|
|
|
| // Memory allocation state information.
|
| intptr_t MallocHooksState::allocation_count_ = 0;
|
| @@ -206,10 +184,10 @@ void MallocHooks::InitOnce() {
|
| if (!FLAG_enable_malloc_hooks) {
|
| return;
|
| }
|
| - MutexLocker ml(MallocHooksState::malloc_hook_mutex());
|
| + MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
|
| + MallocHooksState::malloc_hook_mutex_owner());
|
| ASSERT(!MallocHooksState::Active());
|
|
|
| - MallocHookScope::InitMallocHookFlag();
|
| MallocHooksState::Init();
|
|
|
| // Register malloc hooks.
|
| @@ -225,7 +203,8 @@ void MallocHooks::TearDown() {
|
| if (!FLAG_enable_malloc_hooks) {
|
| return;
|
| }
|
| - MutexLocker ml(MallocHooksState::malloc_hook_mutex());
|
| + MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
|
| + MallocHooksState::malloc_hook_mutex_owner());
|
| ASSERT(MallocHooksState::Active());
|
|
|
| // Remove malloc hooks.
|
| @@ -236,7 +215,6 @@ void MallocHooks::TearDown() {
|
| ASSERT(success);
|
|
|
| MallocHooksState::TearDown();
|
| - MallocHookScope::DestroyMallocHookFlag();
|
| }
|
|
|
|
|
| @@ -244,7 +222,8 @@ void MallocHooks::ResetStats() {
|
| if (!FLAG_enable_malloc_hooks) {
|
| return;
|
| }
|
| - MutexLocker ml(MallocHooksState::malloc_hook_mutex());
|
| + MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
|
| + MallocHooksState::malloc_hook_mutex_owner());
|
| if (MallocHooksState::Active()) {
|
| MallocHooksState::ResetStats();
|
| }
|
| @@ -271,7 +250,8 @@ void MallocHooks::PrintToJSONObject(JSONObject* jsobj) {
|
| // to acquire the lock recursively so we extract the values first
|
| // and then add the JSON properties.
|
| {
|
| - MutexLocker ml(MallocHooksState::malloc_hook_mutex());
|
| + MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
|
| + MallocHooksState::malloc_hook_mutex_owner());
|
| if (Active()) {
|
| allocated_memory = MallocHooksState::heap_allocated_memory_in_bytes();
|
| allocation_count = MallocHooksState::allocation_count();
|
| @@ -289,7 +269,8 @@ intptr_t MallocHooks::allocation_count() {
|
| if (!FLAG_enable_malloc_hooks) {
|
| return 0;
|
| }
|
| - MutexLocker ml(MallocHooksState::malloc_hook_mutex());
|
| + MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
|
| + MallocHooksState::malloc_hook_mutex_owner());
|
| return MallocHooksState::allocation_count();
|
| }
|
|
|
| @@ -298,22 +279,22 @@ intptr_t MallocHooks::heap_allocated_memory_in_bytes() {
|
| if (!FLAG_enable_malloc_hooks) {
|
| return 0;
|
| }
|
| - MutexLocker ml(MallocHooksState::malloc_hook_mutex());
|
| + MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
|
| + MallocHooksState::malloc_hook_mutex_owner());
|
| return MallocHooksState::heap_allocated_memory_in_bytes();
|
| }
|
|
|
|
|
| void MallocHooksState::RecordAllocHook(const void* ptr, size_t size) {
|
| - if (MallocHookScope::IsInHook() || !MallocHooksState::IsOriginalProcess()) {
|
| + if (MallocHooksState::IsLockHeldByCurrentThread() ||
|
| + !MallocHooksState::IsOriginalProcess()) {
|
| return;
|
| }
|
|
|
| - MutexLocker ml(MallocHooksState::malloc_hook_mutex());
|
| + MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
|
| + MallocHooksState::malloc_hook_mutex_owner());
|
| // Now that we hold the lock, check to make sure everything is still active.
|
| if ((ptr != NULL) && MallocHooksState::Active()) {
|
| - // Set the malloc hook flag to avoid calling hooks again if memory is
|
| - // allocated/freed below.
|
| - MallocHookScope mhs;
|
| MallocHooksState::IncrementHeapAllocatedMemoryInBytes(size);
|
| MallocHooksState::address_map()->Insert(ptr, size);
|
| }
|
| @@ -321,16 +302,15 @@ void MallocHooksState::RecordAllocHook(const void* ptr, size_t size) {
|
|
|
|
|
| void MallocHooksState::RecordFreeHook(const void* ptr) {
|
| - if (MallocHookScope::IsInHook() || !MallocHooksState::IsOriginalProcess()) {
|
| + if (MallocHooksState::IsLockHeldByCurrentThread() ||
|
| + !MallocHooksState::IsOriginalProcess()) {
|
| return;
|
| }
|
|
|
| - MutexLocker ml(MallocHooksState::malloc_hook_mutex());
|
| + MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
|
| + MallocHooksState::malloc_hook_mutex_owner());
|
| // Now that we hold the lock, check to make sure everything is still active.
|
| if ((ptr != NULL) && MallocHooksState::Active()) {
|
| - // Set the malloc hook flag to avoid calling hooks again if memory is
|
| - // allocated/freed below.
|
| - MallocHookScope mhs;
|
| intptr_t size = 0;
|
| if (MallocHooksState::address_map()->Lookup(ptr, &size)) {
|
| MallocHooksState::DecrementHeapAllocatedMemoryInBytes(size);
|
|
|