blob: 9a4149603089839fa0a10f2230795d6934edab34 [file] [log] [blame]
erikchen7a54483e2017-02-24 10:04:431// Copyright 2017 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/allocator/malloc_zone_functions_mac.h"
6
7#include "base/atomicops.h"
8#include "base/synchronization/lock.h"
9
10namespace base {
11namespace allocator {
12
erikchen2f9bf052017-03-28 01:11:2613MallocZoneFunctions g_malloc_zones[kMaxZoneCount];
14static_assert(std::is_pod<MallocZoneFunctions>::value,
15 "MallocZoneFunctions must be POD");
erikchen7a54483e2017-02-24 10:04:4316
17void StoreZoneFunctions(const ChromeMallocZone* zone,
18 MallocZoneFunctions* functions) {
erikchen2f9bf052017-03-28 01:11:2619 memset(functions, 0, sizeof(MallocZoneFunctions));
erikchen7a54483e2017-02-24 10:04:4320 functions->malloc = zone->malloc;
21 functions->calloc = zone->calloc;
22 functions->valloc = zone->valloc;
23 functions->free = zone->free;
24 functions->realloc = zone->realloc;
25 functions->size = zone->size;
26 CHECK(functions->malloc && functions->calloc && functions->valloc &&
27 functions->free && functions->realloc && functions->size);
28
29 // These functions might be nullptr.
30 functions->batch_malloc = zone->batch_malloc;
31 functions->batch_free = zone->batch_free;
32
33 if (zone->version >= 5) {
34 // Not all custom malloc zones have a memalign.
35 functions->memalign = zone->memalign;
36 }
37 if (zone->version >= 6) {
38 // This may be nullptr.
39 functions->free_definite_size = zone->free_definite_size;
40 }
41
42 functions->context = zone;
43}
44
45namespace {
46
47// All modifications to g_malloc_zones are gated behind this lock.
48// Dispatch to a malloc zone does not need to acquire this lock.
49base::Lock& GetLock() {
50 static base::Lock* g_lock = new base::Lock;
51 return *g_lock;
52}
53
54void EnsureMallocZonesInitializedLocked() {
55 GetLock().AssertAcquired();
erikchen7a54483e2017-02-24 10:04:4356}
57
58int g_zone_count = 0;
59
60bool IsMallocZoneAlreadyStoredLocked(ChromeMallocZone* zone) {
61 EnsureMallocZonesInitializedLocked();
62 GetLock().AssertAcquired();
63 for (int i = 0; i < g_zone_count; ++i) {
64 if (g_malloc_zones[i].context == reinterpret_cast<void*>(zone))
65 return true;
66 }
67 return false;
68}
69
70} // namespace
71
erikchen2f9bf052017-03-28 01:11:2672bool StoreMallocZone(ChromeMallocZone* zone) {
erikchen7a54483e2017-02-24 10:04:4373 base::AutoLock l(GetLock());
74 EnsureMallocZonesInitializedLocked();
75 if (IsMallocZoneAlreadyStoredLocked(zone))
erikchen2f9bf052017-03-28 01:11:2676 return false;
erikchen7a54483e2017-02-24 10:04:4377
78 if (g_zone_count == kMaxZoneCount)
erikchen2f9bf052017-03-28 01:11:2679 return false;
erikchen7a54483e2017-02-24 10:04:4380
81 StoreZoneFunctions(zone, &g_malloc_zones[g_zone_count]);
82 ++g_zone_count;
83
84 // No other thread can possibly see these stores at this point. The code that
85 // reads these values is triggered after this function returns. so we want to
86 // guarantee that they are committed at this stage"
87 base::subtle::MemoryBarrier();
erikchen2f9bf052017-03-28 01:11:2688 return true;
erikchen7a54483e2017-02-24 10:04:4389}
90
91bool IsMallocZoneAlreadyStored(ChromeMallocZone* zone) {
92 base::AutoLock l(GetLock());
93 return IsMallocZoneAlreadyStoredLocked(zone);
94}
95
erikchen2f9bf052017-03-28 01:11:2696bool DoesMallocZoneNeedReplacing(ChromeMallocZone* zone,
97 const MallocZoneFunctions* functions) {
98 return IsMallocZoneAlreadyStored(zone) && zone->malloc != functions->malloc;
99}
100
erikchen7a54483e2017-02-24 10:04:43101int GetMallocZoneCountForTesting() {
102 base::AutoLock l(GetLock());
103 return g_zone_count;
104}
105
106void ClearAllMallocZonesForTesting() {
107 base::AutoLock l(GetLock());
108 EnsureMallocZonesInitializedLocked();
109 memset(g_malloc_zones, 0, kMaxZoneCount * sizeof(MallocZoneFunctions));
110 g_zone_count = 0;
111}
112
113} // namespace allocator
114} // namespace base