blob: 4d2ae8d5910b95e2c7e6e3a27fb57780ba4f4655 [file] [log] [blame]
Austin Schuh745610d2015-09-06 18:19:50 -07001// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
2/* Copyright (c) 2006, Google Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32// A low-level allocator that can be used by other low-level
33// modules without introducing dependency cycles.
34// This allocator is slow and wasteful of memory;
35// it should not be used when performance is key.
36
37#include "base/low_level_alloc.h"
38#include "base/dynamic_annotations.h"
39#include "base/spinlock.h"
40#include "base/logging.h"
41#include "malloc_hook-inl.h"
42#include <gperftools/malloc_hook.h>
43#include <errno.h>
44#ifdef HAVE_UNISTD_H
45#include <unistd.h>
46#endif
47#ifdef HAVE_MMAP
48#include <sys/mman.h>
49#endif
50#include <new> // for placement-new
51
52// On systems (like freebsd) that don't define MAP_ANONYMOUS, use the old
53// form of the name instead.
54#ifndef MAP_ANONYMOUS
55# define MAP_ANONYMOUS MAP_ANON
56#endif
57
58// A first-fit allocator with amortized logarithmic free() time.
59
60// ---------------------------------------------------------------------------
61static const int kMaxLevel = 30;
62
63// We put this class-only struct in a namespace to avoid polluting the
64// global namespace with this struct name (thus risking an ODR violation).
65namespace low_level_alloc_internal {
66 // This struct describes one allocated block, or one free block.
67 struct AllocList {
68 struct Header {
69 intptr_t size; // size of entire region, including this field. Must be
70 // first. Valid in both allocated and unallocated blocks
71 intptr_t magic; // kMagicAllocated or kMagicUnallocated xor this
72 LowLevelAlloc::Arena *arena; // pointer to parent arena
73 void *dummy_for_alignment; // aligns regions to 0 mod 2*sizeof(void*)
74 } header;
75
76 // Next two fields: in unallocated blocks: freelist skiplist data
77 // in allocated blocks: overlaps with client data
78 int levels; // levels in skiplist used
79 AllocList *next[kMaxLevel]; // actually has levels elements.
80 // The AllocList node may not have room for
81 // all kMaxLevel entries. See max_fit in
82 // LLA_SkiplistLevels()
83 };
84}
85using low_level_alloc_internal::AllocList;
86
87
88// ---------------------------------------------------------------------------
89// A trivial skiplist implementation. This is used to keep the freelist
90// in address order while taking only logarithmic time per insert and delete.
91
92// An integer approximation of log2(size/base)
93// Requires size >= base.
94static int IntLog2(size_t size, size_t base) {
95 int result = 0;
96 for (size_t i = size; i > base; i >>= 1) { // i == floor(size/2**result)
97 result++;
98 }
99 // floor(size / 2**result) <= base < floor(size / 2**(result-1))
100 // => log2(size/(base+1)) <= result < 1+log2(size/base)
101 // => result ~= log2(size/base)
102 return result;
103}
104
105// Return a random integer n: p(n)=1/(2**n) if 1 <= n; p(n)=0 if n < 1.
106static int Random() {
107 static int32 r = 1; // no locking---it's not critical
108 ANNOTATE_BENIGN_RACE(&r, "benign race, not critical.");
109 int result = 1;
110 while ((((r = r*1103515245 + 12345) >> 30) & 1) == 0) {
111 result++;
112 }
113 return result;
114}
115
116// Return a number of skiplist levels for a node of size bytes, where
117// base is the minimum node size. Compute level=log2(size / base)+n
118// where n is 1 if random is false and otherwise a random number generated with
119// the standard distribution for a skiplist: See Random() above.
120// Bigger nodes tend to have more skiplist levels due to the log2(size / base)
121// term, so first-fit searches touch fewer nodes. "level" is clipped so
122// level<kMaxLevel and next[level-1] will fit in the node.
123// 0 < LLA_SkiplistLevels(x,y,false) <= LLA_SkiplistLevels(x,y,true) < kMaxLevel
124static int LLA_SkiplistLevels(size_t size, size_t base, bool random) {
125 // max_fit is the maximum number of levels that will fit in a node for the
126 // given size. We can't return more than max_fit, no matter what the
127 // random number generator says.
128 int max_fit = (size-OFFSETOF_MEMBER(AllocList, next)) / sizeof (AllocList *);
129 int level = IntLog2(size, base) + (random? Random() : 1);
130 if (level > max_fit) level = max_fit;
131 if (level > kMaxLevel-1) level = kMaxLevel - 1;
132 RAW_CHECK(level >= 1, "block not big enough for even one level");
133 return level;
134}
135
136// Return "atleast", the first element of AllocList *head s.t. *atleast >= *e.
137// For 0 <= i < head->levels, set prev[i] to "no_greater", where no_greater
138// points to the last element at level i in the AllocList less than *e, or is
139// head if no such element exists.
140static AllocList *LLA_SkiplistSearch(AllocList *head,
141 AllocList *e, AllocList **prev) {
142 AllocList *p = head;
143 for (int level = head->levels - 1; level >= 0; level--) {
144 for (AllocList *n; (n = p->next[level]) != 0 && n < e; p = n) {
145 }
146 prev[level] = p;
147 }
148 return (head->levels == 0) ? 0 : prev[0]->next[0];
149}
150
151// Insert element *e into AllocList *head. Set prev[] as LLA_SkiplistSearch.
152// Requires that e->levels be previously set by the caller (using
153// LLA_SkiplistLevels())
154static void LLA_SkiplistInsert(AllocList *head, AllocList *e,
155 AllocList **prev) {
156 LLA_SkiplistSearch(head, e, prev);
157 for (; head->levels < e->levels; head->levels++) { // extend prev pointers
158 prev[head->levels] = head; // to all *e's levels
159 }
160 for (int i = 0; i != e->levels; i++) { // add element to list
161 e->next[i] = prev[i]->next[i];
162 prev[i]->next[i] = e;
163 }
164}
165
166// Remove element *e from AllocList *head. Set prev[] as LLA_SkiplistSearch().
167// Requires that e->levels be previous set by the caller (using
168// LLA_SkiplistLevels())
169static void LLA_SkiplistDelete(AllocList *head, AllocList *e,
170 AllocList **prev) {
171 AllocList *found = LLA_SkiplistSearch(head, e, prev);
172 RAW_CHECK(e == found, "element not in freelist");
173 for (int i = 0; i != e->levels && prev[i]->next[i] == e; i++) {
174 prev[i]->next[i] = e->next[i];
175 }
176 while (head->levels > 0 && head->next[head->levels - 1] == 0) {
177 head->levels--; // reduce head->levels if level unused
178 }
179}
180
181// ---------------------------------------------------------------------------
182// Arena implementation
183
184struct LowLevelAlloc::Arena {
185 Arena() : mu(SpinLock::LINKER_INITIALIZED) {} // does nothing; for static init
186 explicit Arena(int) : pagesize(0) {} // set pagesize to zero explicitly
187 // for non-static init
188
189 SpinLock mu; // protects freelist, allocation_count,
190 // pagesize, roundup, min_size
191 AllocList freelist; // head of free list; sorted by addr (under mu)
192 int32 allocation_count; // count of allocated blocks (under mu)
193 int32 flags; // flags passed to NewArena (ro after init)
194 size_t pagesize; // ==getpagesize() (init under mu, then ro)
195 size_t roundup; // lowest power of 2 >= max(16,sizeof (AllocList))
196 // (init under mu, then ro)
197 size_t min_size; // smallest allocation block size
198 // (init under mu, then ro)
199};
200
201// The default arena, which is used when 0 is passed instead of an Arena
202// pointer.
203static struct LowLevelAlloc::Arena default_arena;
204
205// Non-malloc-hooked arenas: used only to allocate metadata for arenas that
206// do not want malloc hook reporting, so that for them there's no malloc hook
207// reporting even during arena creation.
208static struct LowLevelAlloc::Arena unhooked_arena;
209static struct LowLevelAlloc::Arena unhooked_async_sig_safe_arena;
210
211// magic numbers to identify allocated and unallocated blocks
212static const intptr_t kMagicAllocated = 0x4c833e95;
213static const intptr_t kMagicUnallocated = ~kMagicAllocated;
214
215namespace {
216 class SCOPED_LOCKABLE ArenaLock {
217 public:
218 explicit ArenaLock(LowLevelAlloc::Arena *arena)
219 EXCLUSIVE_LOCK_FUNCTION(arena->mu)
220 : left_(false), mask_valid_(false), arena_(arena) {
221 if ((arena->flags & LowLevelAlloc::kAsyncSignalSafe) != 0) {
222 // We've decided not to support async-signal-safe arena use until
223 // there a demonstrated need. Here's how one could do it though
224 // (would need to be made more portable).
225#if 0
226 sigset_t all;
227 sigfillset(&all);
228 this->mask_valid_ =
229 (pthread_sigmask(SIG_BLOCK, &all, &this->mask_) == 0);
230#else
231 RAW_CHECK(false, "We do not yet support async-signal-safe arena.");
232#endif
233 }
234 this->arena_->mu.Lock();
235 }
236 ~ArenaLock() { RAW_CHECK(this->left_, "haven't left Arena region"); }
237 void Leave() /*UNLOCK_FUNCTION()*/ {
238 this->arena_->mu.Unlock();
239#if 0
240 if (this->mask_valid_) {
241 pthread_sigmask(SIG_SETMASK, &this->mask_, 0);
242 }
243#endif
244 this->left_ = true;
245 }
246 private:
247 bool left_; // whether left region
248 bool mask_valid_;
249#if 0
250 sigset_t mask_; // old mask of blocked signals
251#endif
252 LowLevelAlloc::Arena *arena_;
253 DISALLOW_COPY_AND_ASSIGN(ArenaLock);
254 };
255} // anonymous namespace
256
257// create an appropriate magic number for an object at "ptr"
258// "magic" should be kMagicAllocated or kMagicUnallocated
259inline static intptr_t Magic(intptr_t magic, AllocList::Header *ptr) {
260 return magic ^ reinterpret_cast<intptr_t>(ptr);
261}
262
263// Initialize the fields of an Arena
264static void ArenaInit(LowLevelAlloc::Arena *arena) {
265 if (arena->pagesize == 0) {
266 arena->pagesize = getpagesize();
267 // Round up block sizes to a power of two close to the header size.
268 arena->roundup = 16;
269 while (arena->roundup < sizeof (arena->freelist.header)) {
270 arena->roundup += arena->roundup;
271 }
272 // Don't allocate blocks less than twice the roundup size to avoid tiny
273 // free blocks.
274 arena->min_size = 2 * arena->roundup;
275 arena->freelist.header.size = 0;
276 arena->freelist.header.magic =
277 Magic(kMagicUnallocated, &arena->freelist.header);
278 arena->freelist.header.arena = arena;
279 arena->freelist.levels = 0;
280 memset(arena->freelist.next, 0, sizeof (arena->freelist.next));
281 arena->allocation_count = 0;
282 if (arena == &default_arena) {
283 // Default arena should be hooked, e.g. for heap-checker to trace
284 // pointer chains through objects in the default arena.
285 arena->flags = LowLevelAlloc::kCallMallocHook;
286 } else if (arena == &unhooked_async_sig_safe_arena) {
287 arena->flags = LowLevelAlloc::kAsyncSignalSafe;
288 } else {
289 arena->flags = 0; // other arenas' flags may be overridden by client,
290 // but unhooked_arena will have 0 in 'flags'.
291 }
292 }
293}
294
295// L < meta_data_arena->mu
296LowLevelAlloc::Arena *LowLevelAlloc::NewArena(int32 flags,
297 Arena *meta_data_arena) {
298 RAW_CHECK(meta_data_arena != 0, "must pass a valid arena");
299 if (meta_data_arena == &default_arena) {
300 if ((flags & LowLevelAlloc::kAsyncSignalSafe) != 0) {
301 meta_data_arena = &unhooked_async_sig_safe_arena;
302 } else if ((flags & LowLevelAlloc::kCallMallocHook) == 0) {
303 meta_data_arena = &unhooked_arena;
304 }
305 }
306 // Arena(0) uses the constructor for non-static contexts
307 Arena *result =
308 new (AllocWithArena(sizeof (*result), meta_data_arena)) Arena(0);
309 ArenaInit(result);
310 result->flags = flags;
311 return result;
312}
313
314// L < arena->mu, L < arena->arena->mu
315bool LowLevelAlloc::DeleteArena(Arena *arena) {
316 RAW_CHECK(arena != 0 && arena != &default_arena && arena != &unhooked_arena,
317 "may not delete default arena");
318 ArenaLock section(arena);
319 bool empty = (arena->allocation_count == 0);
320 section.Leave();
321 if (empty) {
322 while (arena->freelist.next[0] != 0) {
323 AllocList *region = arena->freelist.next[0];
324 size_t size = region->header.size;
325 arena->freelist.next[0] = region->next[0];
326 RAW_CHECK(region->header.magic ==
327 Magic(kMagicUnallocated, &region->header),
328 "bad magic number in DeleteArena()");
329 RAW_CHECK(region->header.arena == arena,
330 "bad arena pointer in DeleteArena()");
331 RAW_CHECK(size % arena->pagesize == 0,
332 "empty arena has non-page-aligned block size");
333 RAW_CHECK(reinterpret_cast<intptr_t>(region) % arena->pagesize == 0,
334 "empty arena has non-page-aligned block");
335 int munmap_result;
336 if ((arena->flags & LowLevelAlloc::kAsyncSignalSafe) == 0) {
337 munmap_result = munmap(region, size);
338 } else {
339 munmap_result = MallocHook::UnhookedMUnmap(region, size);
340 }
341 RAW_CHECK(munmap_result == 0,
342 "LowLevelAlloc::DeleteArena: munmap failed address");
343 }
344 Free(arena);
345 }
346 return empty;
347}
348
349// ---------------------------------------------------------------------------
350
351// Return value rounded up to next multiple of align.
352// align must be a power of two.
353static intptr_t RoundUp(intptr_t addr, intptr_t align) {
354 return (addr + align - 1) & ~(align - 1);
355}
356
357// Equivalent to "return prev->next[i]" but with sanity checking
358// that the freelist is in the correct order, that it
359// consists of regions marked "unallocated", and that no two regions
360// are adjacent in memory (they should have been coalesced).
361// L < arena->mu
362static AllocList *Next(int i, AllocList *prev, LowLevelAlloc::Arena *arena) {
363 RAW_CHECK(i < prev->levels, "too few levels in Next()");
364 AllocList *next = prev->next[i];
365 if (next != 0) {
366 RAW_CHECK(next->header.magic == Magic(kMagicUnallocated, &next->header),
367 "bad magic number in Next()");
368 RAW_CHECK(next->header.arena == arena,
369 "bad arena pointer in Next()");
370 if (prev != &arena->freelist) {
371 RAW_CHECK(prev < next, "unordered freelist");
372 RAW_CHECK(reinterpret_cast<char *>(prev) + prev->header.size <
373 reinterpret_cast<char *>(next), "malformed freelist");
374 }
375 }
376 return next;
377}
378
379// Coalesce list item "a" with its successor if they are adjacent.
380static void Coalesce(AllocList *a) {
381 AllocList *n = a->next[0];
382 if (n != 0 && reinterpret_cast<char *>(a) + a->header.size ==
383 reinterpret_cast<char *>(n)) {
384 LowLevelAlloc::Arena *arena = a->header.arena;
385 a->header.size += n->header.size;
386 n->header.magic = 0;
387 n->header.arena = 0;
388 AllocList *prev[kMaxLevel];
389 LLA_SkiplistDelete(&arena->freelist, n, prev);
390 LLA_SkiplistDelete(&arena->freelist, a, prev);
391 a->levels = LLA_SkiplistLevels(a->header.size, arena->min_size, true);
392 LLA_SkiplistInsert(&arena->freelist, a, prev);
393 }
394}
395
396// Adds block at location "v" to the free list
397// L >= arena->mu
398static void AddToFreelist(void *v, LowLevelAlloc::Arena *arena) {
399 AllocList *f = reinterpret_cast<AllocList *>(
400 reinterpret_cast<char *>(v) - sizeof (f->header));
401 RAW_CHECK(f->header.magic == Magic(kMagicAllocated, &f->header),
402 "bad magic number in AddToFreelist()");
403 RAW_CHECK(f->header.arena == arena,
404 "bad arena pointer in AddToFreelist()");
405 f->levels = LLA_SkiplistLevels(f->header.size, arena->min_size, true);
406 AllocList *prev[kMaxLevel];
407 LLA_SkiplistInsert(&arena->freelist, f, prev);
408 f->header.magic = Magic(kMagicUnallocated, &f->header);
409 Coalesce(f); // maybe coalesce with successor
410 Coalesce(prev[0]); // maybe coalesce with predecessor
411}
412
413// Frees storage allocated by LowLevelAlloc::Alloc().
414// L < arena->mu
415void LowLevelAlloc::Free(void *v) {
416 if (v != 0) {
417 AllocList *f = reinterpret_cast<AllocList *>(
418 reinterpret_cast<char *>(v) - sizeof (f->header));
419 RAW_CHECK(f->header.magic == Magic(kMagicAllocated, &f->header),
420 "bad magic number in Free()");
421 LowLevelAlloc::Arena *arena = f->header.arena;
422 if ((arena->flags & kCallMallocHook) != 0) {
423 MallocHook::InvokeDeleteHook(v);
424 }
425 ArenaLock section(arena);
426 AddToFreelist(v, arena);
427 RAW_CHECK(arena->allocation_count > 0, "nothing in arena to free");
428 arena->allocation_count--;
429 section.Leave();
430 }
431}
432
433// allocates and returns a block of size bytes, to be freed with Free()
434// L < arena->mu
435static void *DoAllocWithArena(size_t request, LowLevelAlloc::Arena *arena) {
436 void *result = 0;
437 if (request != 0) {
438 AllocList *s; // will point to region that satisfies request
439 ArenaLock section(arena);
440 ArenaInit(arena);
441 // round up with header
442 size_t req_rnd = RoundUp(request + sizeof (s->header), arena->roundup);
443 for (;;) { // loop until we find a suitable region
444 // find the minimum levels that a block of this size must have
445 int i = LLA_SkiplistLevels(req_rnd, arena->min_size, false) - 1;
446 if (i < arena->freelist.levels) { // potential blocks exist
447 AllocList *before = &arena->freelist; // predecessor of s
448 while ((s = Next(i, before, arena)) != 0 && s->header.size < req_rnd) {
449 before = s;
450 }
451 if (s != 0) { // we found a region
452 break;
453 }
454 }
455 // we unlock before mmap() both because mmap() may call a callback hook,
456 // and because it may be slow.
457 arena->mu.Unlock();
458 // mmap generous 64K chunks to decrease
459 // the chances/impact of fragmentation:
460 size_t new_pages_size = RoundUp(req_rnd, arena->pagesize * 16);
461 void *new_pages;
462 if ((arena->flags & LowLevelAlloc::kAsyncSignalSafe) != 0) {
463 new_pages = MallocHook::UnhookedMMap(0, new_pages_size,
464 PROT_WRITE|PROT_READ, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
465 } else {
466 new_pages = mmap(0, new_pages_size,
467 PROT_WRITE|PROT_READ, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
468 }
469 RAW_CHECK(new_pages != MAP_FAILED, "mmap error");
470 arena->mu.Lock();
471 s = reinterpret_cast<AllocList *>(new_pages);
472 s->header.size = new_pages_size;
473 // Pretend the block is allocated; call AddToFreelist() to free it.
474 s->header.magic = Magic(kMagicAllocated, &s->header);
475 s->header.arena = arena;
476 AddToFreelist(&s->levels, arena); // insert new region into free list
477 }
478 AllocList *prev[kMaxLevel];
479 LLA_SkiplistDelete(&arena->freelist, s, prev); // remove from free list
480 // s points to the first free region that's big enough
481 if (req_rnd + arena->min_size <= s->header.size) { // big enough to split
482 AllocList *n = reinterpret_cast<AllocList *>
483 (req_rnd + reinterpret_cast<char *>(s));
484 n->header.size = s->header.size - req_rnd;
485 n->header.magic = Magic(kMagicAllocated, &n->header);
486 n->header.arena = arena;
487 s->header.size = req_rnd;
488 AddToFreelist(&n->levels, arena);
489 }
490 s->header.magic = Magic(kMagicAllocated, &s->header);
491 RAW_CHECK(s->header.arena == arena, "");
492 arena->allocation_count++;
493 section.Leave();
494 result = &s->levels;
495 }
496 ANNOTATE_NEW_MEMORY(result, request);
497 return result;
498}
499
500void *LowLevelAlloc::Alloc(size_t request) {
501 void *result = DoAllocWithArena(request, &default_arena);
502 if ((default_arena.flags & kCallMallocHook) != 0) {
503 // this call must be directly in the user-called allocator function
504 // for MallocHook::GetCallerStackTrace to work properly
505 MallocHook::InvokeNewHook(result, request);
506 }
507 return result;
508}
509
510void *LowLevelAlloc::AllocWithArena(size_t request, Arena *arena) {
511 RAW_CHECK(arena != 0, "must pass a valid arena");
512 void *result = DoAllocWithArena(request, arena);
513 if ((arena->flags & kCallMallocHook) != 0) {
514 // this call must be directly in the user-called allocator function
515 // for MallocHook::GetCallerStackTrace to work properly
516 MallocHook::InvokeNewHook(result, request);
517 }
518 return result;
519}
520
521LowLevelAlloc::Arena *LowLevelAlloc::DefaultArena() {
522 return &default_arena;
523}