blob: 3fecabdeb44637d6ce9a706986a5dcce818540d5 [file] [log] [blame]
Austin Schuh745610d2015-09-06 18:19:50 -07001// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
2// Copyright (c) 2008, 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// Author: Sanjay Ghemawat <opensource@google.com>
33
34#ifndef TCMALLOC_PAGE_HEAP_ALLOCATOR_H_
35#define TCMALLOC_PAGE_HEAP_ALLOCATOR_H_
36
37#include <stddef.h> // for NULL, size_t
38
39#include "common.h" // for MetaDataAlloc
40#include "internal_logging.h" // for ASSERT
41
42namespace tcmalloc {
43
44// Simple allocator for objects of a specified type. External locking
45// is required before accessing one of these objects.
46template <class T>
47class PageHeapAllocator {
48 public:
49 // We use an explicit Init function because these variables are statically
50 // allocated and their constructors might not have run by the time some
51 // other static variable tries to allocate memory.
52 void Init() {
53 ASSERT(sizeof(T) <= kAllocIncrement);
54 inuse_ = 0;
55 free_area_ = NULL;
56 free_avail_ = 0;
57 free_list_ = NULL;
58 // Reserve some space at the beginning to avoid fragmentation.
59 Delete(New());
60 }
61
62 T* New() {
63 // Consult free list
64 void* result;
65 if (free_list_ != NULL) {
66 result = free_list_;
67 free_list_ = *(reinterpret_cast<void**>(result));
68 } else {
69 if (free_avail_ < sizeof(T)) {
70 // Need more room. We assume that MetaDataAlloc returns
71 // suitably aligned memory.
72 free_area_ = reinterpret_cast<char*>(MetaDataAlloc(kAllocIncrement));
73 if (free_area_ == NULL) {
74 Log(kCrash, __FILE__, __LINE__,
75 "FATAL ERROR: Out of memory trying to allocate internal "
76 "tcmalloc data (bytes, object-size)",
77 kAllocIncrement, sizeof(T));
78 }
79 free_avail_ = kAllocIncrement;
80 }
81 result = free_area_;
82 free_area_ += sizeof(T);
83 free_avail_ -= sizeof(T);
84 }
85 inuse_++;
86 return reinterpret_cast<T*>(result);
87 }
88
89 void Delete(T* p) {
90 *(reinterpret_cast<void**>(p)) = free_list_;
91 free_list_ = p;
92 inuse_--;
93 }
94
95 int inuse() const { return inuse_; }
96
97 private:
98 // How much to allocate from system at a time
99 static const int kAllocIncrement = 128 << 10;
100
101 // Free area from which to carve new objects
102 char* free_area_;
103 size_t free_avail_;
104
105 // Free list of already carved objects
106 void* free_list_;
107
108 // Number of allocated but unfreed objects
109 int inuse_;
110};
111
Brian Silverman20350ac2021-11-17 18:19:55 -0800112// STL-compatible allocator which forwards allocations to a PageHeapAllocator.
113//
114// Like PageHeapAllocator, this requires external synchronization. To avoid multiple
115// separate STLPageHeapAllocator<T> from sharing the same underlying PageHeapAllocator<T>,
116// the |LockingTag| template argument should be used. Template instantiations with
117// different locking tags can safely be used concurrently.
118template <typename T, class LockingTag>
119class STLPageHeapAllocator {
120 public:
121 typedef size_t size_type;
122 typedef ptrdiff_t difference_type;
123 typedef T* pointer;
124 typedef const T* const_pointer;
125 typedef T& reference;
126 typedef const T& const_reference;
127 typedef T value_type;
128
129 template <class T1> struct rebind {
130 typedef STLPageHeapAllocator<T1, LockingTag> other;
131 };
132
133 STLPageHeapAllocator() { }
134 STLPageHeapAllocator(const STLPageHeapAllocator&) { }
135 template <class T1> STLPageHeapAllocator(const STLPageHeapAllocator<T1, LockingTag>&) { }
136 ~STLPageHeapAllocator() { }
137
138 pointer address(reference x) const { return &x; }
139 const_pointer address(const_reference x) const { return &x; }
140
141 size_type max_size() const { return size_t(-1) / sizeof(T); }
142
143 void construct(pointer p, const T& val) { ::new(p) T(val); }
144 void construct(pointer p) { ::new(p) T(); }
145 void destroy(pointer p) { p->~T(); }
146
147 // There's no state, so these allocators are always equal
148 bool operator==(const STLPageHeapAllocator&) const { return true; }
149 bool operator!=(const STLPageHeapAllocator&) const { return false; }
150
151 pointer allocate(size_type n, const void* = 0) {
152 if (!underlying_.initialized) {
153 underlying_.allocator.Init();
154 underlying_.initialized = true;
155 }
156
157 CHECK_CONDITION(n == 1);
158 return underlying_.allocator.New();
159 }
160 void deallocate(pointer p, size_type n) {
161 CHECK_CONDITION(n == 1);
162 underlying_.allocator.Delete(p);
163 }
164
165 private:
166 struct Storage {
167 explicit Storage(base::LinkerInitialized x) {}
168 PageHeapAllocator<T> allocator;
169 bool initialized;
170 };
171 static Storage underlying_;
172};
173
174template<typename T, class LockingTag>
175typename STLPageHeapAllocator<T, LockingTag>::Storage STLPageHeapAllocator<T, LockingTag>::underlying_(base::LINKER_INITIALIZED);
176
Austin Schuh745610d2015-09-06 18:19:50 -0700177} // namespace tcmalloc
178
179#endif // TCMALLOC_PAGE_HEAP_ALLOCATOR_H_