1//===-- sanitizer_persistent_allocator.h ------------------------*- C++ -*-===//
2//
3// This file is distributed under the University of Illinois Open Source
4// License. See LICENSE.TXT for details.
5//
6//===----------------------------------------------------------------------===//
7//
8// A fast memory allocator that does not support free() nor realloc().
9// All allocations are forever.
10//===----------------------------------------------------------------------===//
11
12#ifndef SANITIZER_PERSISTENT_ALLOCATOR_H
13#define SANITIZER_PERSISTENT_ALLOCATOR_H
14
15#include "sanitizer_internal_defs.h"
16#include "sanitizer_mutex.h"
17#include "sanitizer_atomic.h"
18#include "sanitizer_common.h"
19
20namespace __sanitizer {
21
22class PersistentAllocator {
23 public:
24  void *alloc(uptr size);
25
26 private:
27  void *tryAlloc(uptr size);
28  StaticSpinMutex mtx;  // Protects alloc of new blocks for region allocator.
29  atomic_uintptr_t region_pos;  // Region allocator for Node's.
30  atomic_uintptr_t region_end;
31};
32
33inline void *PersistentAllocator::tryAlloc(uptr size) {
34  // Optimisic lock-free allocation, essentially try to bump the region ptr.
35  for (;;) {
36    uptr cmp = atomic_load(&region_pos, memory_order_acquire);
37    uptr end = atomic_load(&region_end, memory_order_acquire);
38    if (cmp == 0 || cmp + size > end) return nullptr;
39    if (atomic_compare_exchange_weak(&region_pos, &cmp, cmp + size,
40                                     memory_order_acquire))
41      return (void *)cmp;
42  }
43}
44
45inline void *PersistentAllocator::alloc(uptr size) {
46  // First, try to allocate optimisitically.
47  void *s = tryAlloc(size);
48  if (s) return s;
49  // If failed, lock, retry and alloc new superblock.
50  SpinMutexLock l(&mtx);
51  for (;;) {
52    s = tryAlloc(size);
53    if (s) return s;
54    atomic_store(&region_pos, 0, memory_order_relaxed);
55    uptr allocsz = 64 * 1024;
56    if (allocsz < size) allocsz = size;
57    uptr mem = (uptr)MmapOrDie(allocsz, "stack depot");
58    atomic_store(&region_end, mem + allocsz, memory_order_release);
59    atomic_store(&region_pos, mem, memory_order_release);
60  }
61}
62
63extern PersistentAllocator thePersistentAllocator;
64inline void *PersistentAlloc(uptr sz) {
65  return thePersistentAllocator.alloc(sz);
66}
67
68} // namespace __sanitizer
69
70#endif // SANITIZER_PERSISTENT_ALLOCATOR_H
71