secondary.h revision 353358
1//===-- secondary.h ---------------------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef SCUDO_SECONDARY_H_
10#define SCUDO_SECONDARY_H_
11
12#include "common.h"
13#include "mutex.h"
14#include "stats.h"
15
16namespace scudo {
17
18// This allocator wraps the platform allocation primitives, and as such is on
19// the slower side and should preferably be used for larger sized allocations.
20// Blocks allocated will be preceded and followed by a guard page, and hold
21// their own header that is not checksummed: the guard pages and the Combined
22// header should be enough for our purpose.
23
24namespace LargeBlock {
25
26struct Header {
27  LargeBlock::Header *Prev;
28  LargeBlock::Header *Next;
29  uptr BlockEnd;
30  uptr MapBase;
31  uptr MapSize;
32  MapPlatformData Data;
33};
34
35constexpr uptr getHeaderSize() {
36  return roundUpTo(sizeof(Header), 1U << SCUDO_MIN_ALIGNMENT_LOG);
37}
38
39static Header *getHeader(uptr Ptr) {
40  return reinterpret_cast<Header *>(Ptr - getHeaderSize());
41}
42
43static Header *getHeader(const void *Ptr) {
44  return getHeader(reinterpret_cast<uptr>(Ptr));
45}
46
47} // namespace LargeBlock
48
49class MapAllocator {
50public:
51  void initLinkerInitialized(GlobalStats *S) {
52    Stats.initLinkerInitialized();
53    if (S)
54      S->link(&Stats);
55  }
56  void init(GlobalStats *S) {
57    memset(this, 0, sizeof(*this));
58    initLinkerInitialized(S);
59  }
60
61  void *allocate(uptr Size, uptr AlignmentHint = 0, uptr *BlockEnd = nullptr);
62
63  void deallocate(void *Ptr);
64
65  static uptr getBlockEnd(void *Ptr) {
66    return LargeBlock::getHeader(Ptr)->BlockEnd;
67  }
68
69  static uptr getBlockSize(void *Ptr) {
70    return getBlockEnd(Ptr) - reinterpret_cast<uptr>(Ptr);
71  }
72
73  void printStats() const;
74
75  void disable() { Mutex.lock(); }
76
77  void enable() { Mutex.unlock(); }
78
79  template <typename F> void iterateOverBlocks(F Callback) const {
80    for (LargeBlock::Header *H = Tail; H != nullptr; H = H->Prev)
81      Callback(reinterpret_cast<uptr>(H) + LargeBlock::getHeaderSize());
82  }
83
84private:
85  HybridMutex Mutex;
86  LargeBlock::Header *Tail;
87  uptr AllocatedBytes;
88  uptr FreedBytes;
89  uptr LargestSize;
90  u32 NumberOfAllocs;
91  u32 NumberOfFrees;
92  LocalStats Stats;
93};
94
95} // namespace scudo
96
97#endif // SCUDO_SECONDARY_H_
98