1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 static pthread_mutex_t malloc_disabled_lock = PTHREAD_MUTEX_INITIALIZER;
18 static bool malloc_disabled_tcache;
19
je_malloc_iterate(uintptr_t base,size_t size,void (* callback)(uintptr_t ptr,size_t size,void * arg),void * arg)20 int je_malloc_iterate(uintptr_t base, size_t size,
21 void (*callback)(uintptr_t ptr, size_t size, void* arg), void* arg) {
22 size_t pagesize = getpagesize();
23 tsd_t* tsd = tsd_fetch_min();
24 rtree_ctx_t *rtree_ctx = tsd_rtree_ctx(tsd);
25
26 // Make sure the pointer is aligned to at least 8 bytes.
27 uintptr_t ptr = (base + 7) & ~7;
28 uintptr_t end_ptr = ptr + size;
29 while (ptr < end_ptr) {
30 extent_t* extent = iealloc(tsd_tsdn(tsd), (void*)ptr);
31 if (extent == NULL) {
32 // Skip to the next page, guaranteed no other pointers on this page.
33 ptr += pagesize;
34 continue;
35 }
36
37 if (extent_szind_get_maybe_invalid(extent) >= NSIZES) {
38 // Ignore this unused extent.
39 ptr = (uintptr_t)extent_past_get(extent);
40 continue;
41 }
42
43 szind_t szind;
44 bool slab;
45 rtree_szind_slab_read(tsd_tsdn(tsd), &extents_rtree, rtree_ctx, ptr, true, &szind, &slab);
46 if (slab) {
47 // Small allocation.
48 szind_t binind = extent_szind_get(extent);
49 const bin_info_t* bin_info = &bin_infos[binind];
50 arena_slab_data_t* slab_data = extent_slab_data_get(extent);
51
52 uintptr_t first_ptr = (uintptr_t)extent_addr_get(extent);
53 size_t bin_size = bin_info->reg_size;
54 // Align the pointer to the bin size.
55 ptr = (ptr + bin_size - 1) & ~(bin_size - 1);
56 for (size_t bit = (ptr - first_ptr) / bin_size; bit < bin_info->bitmap_info.nbits; bit++) {
57 if (bitmap_get(slab_data->bitmap, &bin_info->bitmap_info, bit)) {
58 uintptr_t allocated_ptr = first_ptr + bin_size * bit;
59 if (allocated_ptr >= end_ptr) {
60 break;
61 }
62 callback(allocated_ptr, bin_size, arg);
63 }
64 }
65 } else if (extent_state_get(extent) == extent_state_active) {
66 // Large allocation.
67 uintptr_t base_ptr = (uintptr_t)extent_addr_get(extent);
68 if (ptr <= base_ptr) {
69 // This extent is actually allocated and within the range to check.
70 callback(base_ptr, extent_usize_get(extent), arg);
71 }
72 }
73 ptr = (uintptr_t)extent_past_get(extent);
74 }
75 return 0;
76 }
77
je_malloc_disable_prefork()78 static void je_malloc_disable_prefork() {
79 pthread_mutex_lock(&malloc_disabled_lock);
80 }
81
je_malloc_disable_postfork_parent()82 static void je_malloc_disable_postfork_parent() {
83 pthread_mutex_unlock(&malloc_disabled_lock);
84 }
85
je_malloc_disable_postfork_child()86 static void je_malloc_disable_postfork_child() {
87 pthread_mutex_init(&malloc_disabled_lock, NULL);
88 }
89
je_malloc_disable_init()90 void je_malloc_disable_init() {
91 if (pthread_atfork(je_malloc_disable_prefork,
92 je_malloc_disable_postfork_parent, je_malloc_disable_postfork_child) != 0) {
93 malloc_write("<jemalloc>: Error in pthread_atfork()\n");
94 if (opt_abort)
95 abort();
96 }
97 }
98
je_malloc_disable()99 void je_malloc_disable() {
100 static pthread_once_t once_control = PTHREAD_ONCE_INIT;
101 pthread_once(&once_control, je_malloc_disable_init);
102
103 pthread_mutex_lock(&malloc_disabled_lock);
104 bool new_tcache = false;
105 size_t old_len = sizeof(malloc_disabled_tcache);
106
107 // Disable the tcache (if not already disabled) so that we don't
108 // have to search the tcache for pointers.
109 je_mallctl("thread.tcache.enabled",
110 &malloc_disabled_tcache, &old_len,
111 &new_tcache, sizeof(new_tcache));
112 jemalloc_prefork();
113 }
114
je_malloc_enable()115 void je_malloc_enable() {
116 jemalloc_postfork_parent();
117 if (malloc_disabled_tcache) {
118 // Re-enable the tcache if it was enabled before the disabled call.
119 je_mallctl("thread.tcache.enabled", NULL, NULL,
120 &malloc_disabled_tcache, sizeof(malloc_disabled_tcache));
121 }
122 pthread_mutex_unlock(&malloc_disabled_lock);
123 }
124