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

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

Issue 2647283004: Reintroducing MallocHooks changes with fix for hooks being called when in execvpe after a fork whil… (Closed)
Patch Set: Reintroducing MallocHooks changes with fix for hooks being called when in execvpe after a fork whil… 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 | « runtime/vm/malloc_hooks.h ('k') | runtime/vm/malloc_hooks_test.cc » ('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 #if defined(DART_USE_TCMALLOC) 5 #include "platform/globals.h"
6
7 #if defined(DART_USE_TCMALLOC) && !defined(PRODUCT)
6 8
7 #include "vm/malloc_hooks.h" 9 #include "vm/malloc_hooks.h"
8 10
11 #include "gperftools/malloc_hook.h"
12
13 #include "platform/assert.h"
14 #include "vm/hash_map.h"
15 #include "vm/lockers.h"
16
9 namespace dart { 17 namespace dart {
10 18
11 void MallocHooks::Init() { 19 // A locker-type class to automatically grab and release the
12 // TODO(bkonyi): Implement 20 // in_malloc_hook_flag_.
21 class MallocHookScope {
22 public:
23 static void InitMallocHookFlag() {
24 ASSERT(in_malloc_hook_flag_ == kUnsetThreadLocalKey);
25 in_malloc_hook_flag_ = OSThread::CreateThreadLocal();
26 OSThread::SetThreadLocal(in_malloc_hook_flag_, 0);
27 }
28
29 static void DestroyMallocHookFlag() {
30 ASSERT(in_malloc_hook_flag_ != kUnsetThreadLocalKey);
31 OSThread::DeleteThreadLocal(in_malloc_hook_flag_);
32 in_malloc_hook_flag_ = kUnsetThreadLocalKey;
33 }
34
35 MallocHookScope() {
36 ASSERT(in_malloc_hook_flag_ != kUnsetThreadLocalKey);
37 OSThread::SetThreadLocal(in_malloc_hook_flag_, 1);
38 }
39
40 ~MallocHookScope() {
41 ASSERT(in_malloc_hook_flag_ != kUnsetThreadLocalKey);
42 OSThread::SetThreadLocal(in_malloc_hook_flag_, 0);
43 }
44
45 static bool IsInHook() {
46 ASSERT(in_malloc_hook_flag_ != kUnsetThreadLocalKey);
47 return OSThread::GetThreadLocal(in_malloc_hook_flag_);
48 }
49
50 private:
51 static ThreadLocalKey in_malloc_hook_flag_;
52
53 DISALLOW_ALLOCATION();
54 DISALLOW_COPY_AND_ASSIGN(MallocHookScope);
55 };
56
57
58 // Custom key/value trait specifically for address/size pairs. Unlike
59 // RawPointerKeyValueTrait, the default value is -1 as 0 can be a valid entry.
60 class AddressKeyValueTrait {
61 public:
62 typedef const void* Key;
63 typedef intptr_t Value;
64
65 struct Pair {
66 Key key;
67 Value value;
68 Pair() : key(NULL), value(-1) {}
69 Pair(const Key key, const Value& value) : key(key), value(value) {}
70 Pair(const Pair& other) : key(other.key), value(other.value) {}
71 };
72
73 static Key KeyOf(Pair kv) { return kv.key; }
74 static Value ValueOf(Pair kv) { return kv.value; }
75 static intptr_t Hashcode(Key key) { return reinterpret_cast<intptr_t>(key); }
76 static bool IsKeyEqual(Pair kv, Key key) { return kv.key == key; }
77 };
78
79
80 // Map class that will be used to store mappings between ptr -> allocation size.
81 class AddressMap : public MallocDirectChainedHashMap<AddressKeyValueTrait> {
82 public:
83 typedef AddressKeyValueTrait::Key Key;
84 typedef AddressKeyValueTrait::Value Value;
85 typedef AddressKeyValueTrait::Pair Pair;
86
87 inline void Insert(const Key& key, const Value& value) {
88 Pair pair(key, value);
89 MallocDirectChainedHashMap<AddressKeyValueTrait>::Insert(pair);
90 }
91
92 inline bool Lookup(const Key& key, Value* value) {
93 ASSERT(value != NULL);
94 Pair* pair = MallocDirectChainedHashMap<AddressKeyValueTrait>::Lookup(key);
95 if (pair == NULL) {
96 return false;
97 } else {
98 *value = pair->value;
99 return true;
100 }
101 }
102 };
103
104
105 class MallocHooksState {
106 public:
107 static void RecordAllocHook(const void* ptr, size_t size);
108 static void RecordFreeHook(const void* ptr);
109
110 static bool initialized() { return initialized_; }
111 static void Init() {
112 address_map_ = new AddressMap();
113 initialized_ = true;
114 original_pid_ = OS::ProcessId();
115 }
116
117 static bool IsOriginalProcess() {
118 ASSERT(original_pid_ != kInvalidPid);
119 return original_pid_ == OS::ProcessId();
120 }
121
122 static Mutex* malloc_hook_mutex() { return malloc_hook_mutex_; }
123
124 static intptr_t allocation_count() { return allocation_count_; }
125
126 static intptr_t heap_allocated_memory_in_bytes() {
127 return heap_allocated_memory_in_bytes_;
128 }
129
130 static void IncrementHeapAllocatedMemoryInBytes(intptr_t size) {
131 ASSERT(size >= 0);
132 heap_allocated_memory_in_bytes_ += size;
133 ++allocation_count_;
134 }
135
136 static void DecrementHeapAllocatedMemoryInBytes(intptr_t size) {
137 ASSERT(size >= 0);
138 ASSERT(heap_allocated_memory_in_bytes_ >= size);
139 heap_allocated_memory_in_bytes_ -= size;
140 --allocation_count_;
141 ASSERT(allocation_count_ >= 0);
142 }
143
144 static AddressMap* address_map() { return address_map_; }
145
146 static void ResetStats() {
147 allocation_count_ = 0;
148 heap_allocated_memory_in_bytes_ = 0;
149 address_map_->Clear();
150 }
151
152 static void TearDown() {
153 initialized_ = false;
154 original_pid_ = kInvalidPid;
155 ResetStats();
156 delete address_map_;
157 }
158
159 private:
160 static bool initialized_;
161 static intptr_t original_pid_;
162 static Mutex* malloc_hook_mutex_;
163 static intptr_t allocation_count_;
164 static intptr_t heap_allocated_memory_in_bytes_;
165 static AddressMap* address_map_;
166
167 static const intptr_t kInvalidPid = -1;
168
169 DISALLOW_ALLOCATION();
170 DISALLOW_COPY_AND_ASSIGN(MallocHooksState);
171 };
172
173
174 // MallocHooks state / locks.
175 ThreadLocalKey MallocHookScope::in_malloc_hook_flag_ = kUnsetThreadLocalKey;
176 bool MallocHooksState::initialized_ = false;
177 intptr_t MallocHooksState::original_pid_ = MallocHooksState::kInvalidPid;
178 Mutex* MallocHooksState::malloc_hook_mutex_ = new Mutex();
179
180 // Memory allocation state information.
181 intptr_t MallocHooksState::allocation_count_ = 0;
182 intptr_t MallocHooksState::heap_allocated_memory_in_bytes_ = 0;
183 AddressMap* MallocHooksState::address_map_ = NULL;
184
185
186 void MallocHooks::InitOnce() {
187 MutexLocker ml(MallocHooksState::malloc_hook_mutex());
188 ASSERT(!MallocHooksState::initialized());
189
190 MallocHookScope::InitMallocHookFlag();
191 MallocHooksState::Init();
192
193 // Register malloc hooks.
194 bool success = false;
195 success = MallocHook::AddNewHook(&MallocHooksState::RecordAllocHook);
196 ASSERT(success);
197 success = MallocHook::AddDeleteHook(&MallocHooksState::RecordFreeHook);
198 ASSERT(success);
199 }
200
201
202 void MallocHooks::TearDown() {
203 MutexLocker ml(MallocHooksState::malloc_hook_mutex());
204 ASSERT(MallocHooksState::initialized());
205
206 // Remove malloc hooks.
207 bool success = false;
208 success = MallocHook::RemoveNewHook(&MallocHooksState::RecordAllocHook);
209 ASSERT(success);
210 success = MallocHook::RemoveDeleteHook(&MallocHooksState::RecordFreeHook);
211 ASSERT(success);
212
213 MallocHooksState::TearDown();
214 MallocHookScope::DestroyMallocHookFlag();
215 }
216
217
218 void MallocHooks::ResetStats() {
219 MutexLocker ml(MallocHooksState::malloc_hook_mutex());
220 ASSERT(MallocHooksState::initialized());
221
222 MallocHooksState::ResetStats();
223 }
224
225
226 intptr_t MallocHooks::allocation_count() {
227 MutexLocker ml(MallocHooksState::malloc_hook_mutex());
228 return MallocHooksState::allocation_count();
229 }
230
231
232 intptr_t MallocHooks::heap_allocated_memory_in_bytes() {
233 MutexLocker ml(MallocHooksState::malloc_hook_mutex());
234 return MallocHooksState::heap_allocated_memory_in_bytes();
235 }
236
237
238 void MallocHooksState::RecordAllocHook(const void* ptr, size_t size) {
239 if (MallocHookScope::IsInHook() || !MallocHooksState::IsOriginalProcess()) {
240 return;
241 }
242
243 // Set the malloc hook flag before grabbing the mutex to avoid calling hooks
244 // again.
245 MallocHookScope mhs;
246 MutexLocker ml(MallocHooksState::malloc_hook_mutex());
247 ASSERT(MallocHooksState::initialized());
248
249 if (ptr != NULL) {
250 MallocHooksState::IncrementHeapAllocatedMemoryInBytes(size);
251 MallocHooksState::address_map()->Insert(ptr, size);
252 }
253 }
254
255
256 void MallocHooksState::RecordFreeHook(const void* ptr) {
257 if (MallocHookScope::IsInHook() || !MallocHooksState::IsOriginalProcess()) {
258 return;
259 }
260
261 // Set the malloc hook flag before grabbing the mutex to avoid calling hooks
262 // again.
263 MallocHookScope mhs;
264 MutexLocker ml(MallocHooksState::malloc_hook_mutex());
265 ASSERT(MallocHooksState::initialized());
266
267 if (ptr != NULL) {
268 intptr_t size = 0;
269 if (MallocHooksState::address_map()->Lookup(ptr, &size)) {
270 MallocHooksState::DecrementHeapAllocatedMemoryInBytes(size);
271 MallocHooksState::address_map()->Remove(ptr);
272 }
273 }
13 } 274 }
14 275
15 } // namespace dart 276 } // namespace dart
16 277
17 #endif // defined(DART_USE_TCMALLOC) 278 #endif // defined(DART_USE_TCMALLOC) && !defined(PRODUCT)
OLDNEW
« no previous file with comments | « runtime/vm/malloc_hooks.h ('k') | runtime/vm/malloc_hooks_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698