]>
Commit | Line | Data |
---|---|---|
970d7e83 LB |
1 | #define JEMALLOC_BASE_C_ |
2 | #include "jemalloc/internal/jemalloc_internal.h" | |
3 | ||
4 | /******************************************************************************/ | |
5 | /* Data. */ | |
6 | ||
7 | static malloc_mutex_t base_mtx; | |
3b2f2976 XL |
8 | static size_t base_extent_sn_next; |
9 | static extent_tree_t base_avail_szsnad; | |
970d7e83 | 10 | static extent_node_t *base_nodes; |
54a0048b SL |
11 | static size_t base_allocated; |
12 | static size_t base_resident; | |
13 | static size_t base_mapped; | |
970d7e83 | 14 | |
970d7e83 LB |
15 | /******************************************************************************/ |
16 | ||
54a0048b | 17 | static extent_node_t * |
3b2f2976 | 18 | base_node_try_alloc(tsdn_t *tsdn) |
970d7e83 | 19 | { |
54a0048b | 20 | extent_node_t *node; |
970d7e83 | 21 | |
3b2f2976 XL |
22 | malloc_mutex_assert_owner(tsdn, &base_mtx); |
23 | ||
54a0048b SL |
24 | if (base_nodes == NULL) |
25 | return (NULL); | |
26 | node = base_nodes; | |
27 | base_nodes = *(extent_node_t **)node; | |
28 | JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(node, sizeof(extent_node_t)); | |
29 | return (node); | |
970d7e83 LB |
30 | } |
31 | ||
54a0048b | 32 | static void |
3b2f2976 | 33 | base_node_dalloc(tsdn_t *tsdn, extent_node_t *node) |
970d7e83 | 34 | { |
970d7e83 | 35 | |
3b2f2976 XL |
36 | malloc_mutex_assert_owner(tsdn, &base_mtx); |
37 | ||
54a0048b SL |
38 | JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(node, sizeof(extent_node_t)); |
39 | *(extent_node_t **)node = base_nodes; | |
40 | base_nodes = node; | |
970d7e83 LB |
41 | } |
42 | ||
3b2f2976 XL |
43 | static void |
44 | base_extent_node_init(extent_node_t *node, void *addr, size_t size) | |
45 | { | |
46 | size_t sn = atomic_add_z(&base_extent_sn_next, 1) - 1; | |
47 | ||
48 | extent_node_init(node, NULL, addr, size, sn, true, true); | |
49 | } | |
50 | ||
54a0048b | 51 | static extent_node_t * |
3b2f2976 | 52 | base_chunk_alloc(tsdn_t *tsdn, size_t minsize) |
970d7e83 | 53 | { |
54a0048b SL |
54 | extent_node_t *node; |
55 | size_t csize, nsize; | |
56 | void *addr; | |
7453a54e | 57 | |
3b2f2976 | 58 | malloc_mutex_assert_owner(tsdn, &base_mtx); |
54a0048b | 59 | assert(minsize != 0); |
3b2f2976 | 60 | node = base_node_try_alloc(tsdn); |
54a0048b SL |
61 | /* Allocate enough space to also carve a node out if necessary. */ |
62 | nsize = (node == NULL) ? CACHELINE_CEILING(sizeof(extent_node_t)) : 0; | |
63 | csize = CHUNK_CEILING(minsize + nsize); | |
64 | addr = chunk_alloc_base(csize); | |
65 | if (addr == NULL) { | |
66 | if (node != NULL) | |
3b2f2976 | 67 | base_node_dalloc(tsdn, node); |
54a0048b SL |
68 | return (NULL); |
69 | } | |
70 | base_mapped += csize; | |
71 | if (node == NULL) { | |
72 | node = (extent_node_t *)addr; | |
73 | addr = (void *)((uintptr_t)addr + nsize); | |
74 | csize -= nsize; | |
75 | if (config_stats) { | |
76 | base_allocated += nsize; | |
77 | base_resident += PAGE_CEILING(nsize); | |
78 | } | |
79 | } | |
3b2f2976 | 80 | base_extent_node_init(node, addr, csize); |
54a0048b | 81 | return (node); |
7453a54e SL |
82 | } |
83 | ||
54a0048b SL |
84 | /* |
85 | * base_alloc() guarantees demand-zeroed memory, in order to make multi-page | |
86 | * sparse data structures such as radix tree nodes efficient with respect to | |
87 | * physical memory usage. | |
88 | */ | |
89 | void * | |
3b2f2976 | 90 | base_alloc(tsdn_t *tsdn, size_t size) |
7453a54e | 91 | { |
54a0048b SL |
92 | void *ret; |
93 | size_t csize, usize; | |
94 | extent_node_t *node; | |
95 | extent_node_t key; | |
96 | ||
97 | /* | |
98 | * Round size up to nearest multiple of the cacheline size, so that | |
99 | * there is no chance of false cache line sharing. | |
100 | */ | |
101 | csize = CACHELINE_CEILING(size); | |
970d7e83 | 102 | |
54a0048b | 103 | usize = s2u(csize); |
3b2f2976 XL |
104 | extent_node_init(&key, NULL, NULL, usize, 0, false, false); |
105 | malloc_mutex_lock(tsdn, &base_mtx); | |
106 | node = extent_tree_szsnad_nsearch(&base_avail_szsnad, &key); | |
54a0048b SL |
107 | if (node != NULL) { |
108 | /* Use existing space. */ | |
3b2f2976 | 109 | extent_tree_szsnad_remove(&base_avail_szsnad, node); |
970d7e83 | 110 | } else { |
54a0048b | 111 | /* Try to allocate more space. */ |
3b2f2976 | 112 | node = base_chunk_alloc(tsdn, csize); |
54a0048b SL |
113 | } |
114 | if (node == NULL) { | |
115 | ret = NULL; | |
116 | goto label_return; | |
970d7e83 LB |
117 | } |
118 | ||
54a0048b SL |
119 | ret = extent_node_addr_get(node); |
120 | if (extent_node_size_get(node) > csize) { | |
121 | extent_node_addr_set(node, (void *)((uintptr_t)ret + csize)); | |
122 | extent_node_size_set(node, extent_node_size_get(node) - csize); | |
3b2f2976 | 123 | extent_tree_szsnad_insert(&base_avail_szsnad, node); |
54a0048b | 124 | } else |
3b2f2976 | 125 | base_node_dalloc(tsdn, node); |
54a0048b SL |
126 | if (config_stats) { |
127 | base_allocated += csize; | |
128 | /* | |
129 | * Add one PAGE to base_resident for every page boundary that is | |
130 | * crossed by the new allocation. | |
131 | */ | |
132 | base_resident += PAGE_CEILING((uintptr_t)ret + csize) - | |
133 | PAGE_CEILING((uintptr_t)ret); | |
134 | } | |
135 | JEMALLOC_VALGRIND_MAKE_MEM_DEFINED(ret, csize); | |
136 | label_return: | |
3b2f2976 | 137 | malloc_mutex_unlock(tsdn, &base_mtx); |
970d7e83 LB |
138 | return (ret); |
139 | } | |
140 | ||
141 | void | |
3b2f2976 XL |
142 | base_stats_get(tsdn_t *tsdn, size_t *allocated, size_t *resident, |
143 | size_t *mapped) | |
970d7e83 LB |
144 | { |
145 | ||
3b2f2976 | 146 | malloc_mutex_lock(tsdn, &base_mtx); |
54a0048b SL |
147 | assert(base_allocated <= base_resident); |
148 | assert(base_resident <= base_mapped); | |
149 | *allocated = base_allocated; | |
150 | *resident = base_resident; | |
151 | *mapped = base_mapped; | |
3b2f2976 | 152 | malloc_mutex_unlock(tsdn, &base_mtx); |
970d7e83 LB |
153 | } |
154 | ||
155 | bool | |
156 | base_boot(void) | |
157 | { | |
158 | ||
3b2f2976 | 159 | if (malloc_mutex_init(&base_mtx, "base", WITNESS_RANK_BASE)) |
970d7e83 | 160 | return (true); |
3b2f2976 XL |
161 | base_extent_sn_next = 0; |
162 | extent_tree_szsnad_new(&base_avail_szsnad); | |
54a0048b | 163 | base_nodes = NULL; |
970d7e83 LB |
164 | |
165 | return (false); | |
166 | } | |
167 | ||
168 | void | |
3b2f2976 | 169 | base_prefork(tsdn_t *tsdn) |
970d7e83 LB |
170 | { |
171 | ||
3b2f2976 | 172 | malloc_mutex_prefork(tsdn, &base_mtx); |
970d7e83 LB |
173 | } |
174 | ||
175 | void | |
3b2f2976 | 176 | base_postfork_parent(tsdn_t *tsdn) |
970d7e83 LB |
177 | { |
178 | ||
3b2f2976 | 179 | malloc_mutex_postfork_parent(tsdn, &base_mtx); |
970d7e83 LB |
180 | } |
181 | ||
182 | void | |
3b2f2976 | 183 | base_postfork_child(tsdn_t *tsdn) |
970d7e83 LB |
184 | { |
185 | ||
3b2f2976 | 186 | malloc_mutex_postfork_child(tsdn, &base_mtx); |
970d7e83 | 187 | } |