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