Planeshift
memory.h
Go to the documentation of this file.
1 // Copyright (c) 2009, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 
30 #ifndef GOOGLE_BREAKPAD_COMMON_MEMORY_H_
31 #define GOOGLE_BREAKPAD_COMMON_MEMORY_H_
32 
33 #include <stdint.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <sys/mman.h>
37 
38 #include <memory>
39 #include <vector>
40 
41 #ifdef __APPLE__
42 #define sys_mmap mmap
43 #define sys_mmap2 mmap
44 #define sys_munmap munmap
45 #define MAP_ANONYMOUS MAP_ANON
46 #else
48 #endif
49 
50 namespace google_breakpad {
51 
52 // This is very simple allocator which fetches pages from the kernel directly.
53 // Thus, it can be used even when the heap may be corrupted.
54 //
55 // There is no free operation. The pages are only freed when the object is
56 // destroyed.
58  public:
60  : page_size_(getpagesize()),
61  last_(NULL),
62  current_page_(NULL),
63  page_offset_(0) {
64  }
65 
67  FreeAll();
68  }
69 
70  void *Alloc(unsigned bytes) {
71  if (!bytes)
72  return NULL;
73 
74  if (current_page_ && page_size_ - page_offset_ >= bytes) {
75  uint8_t *const ret = current_page_ + page_offset_;
76  page_offset_ += bytes;
77  if (page_offset_ == page_size_) {
78  page_offset_ = 0;
79  current_page_ = NULL;
80  }
81 
82  return ret;
83  }
84 
85  const unsigned pages =
86  (bytes + sizeof(PageHeader) + page_size_ - 1) / page_size_;
87  uint8_t *const ret = GetNPages(pages);
88  if (!ret)
89  return NULL;
90 
91  page_offset_ =
92  (page_size_ - (page_size_ * pages - (bytes + sizeof(PageHeader)))) %
93  page_size_;
94  current_page_ = page_offset_ ? ret + page_size_ * (pages - 1) : NULL;
95 
96  return ret + sizeof(PageHeader);
97  }
98 
99  // Checks whether the page allocator owns the passed-in pointer.
100  // This method exists for testing pursposes only.
101  bool OwnsPointer(const void* p) {
102  for (PageHeader* header = last_; header; header = header->next) {
103  const char* current = reinterpret_cast<char*>(header);
104  if ((p >= current) && (p < current + header->num_pages * page_size_))
105  return true;
106  }
107 
108  return false;
109  }
110 
111  private:
112  uint8_t *GetNPages(unsigned num_pages) {
113 #ifdef __x86_64
114  void *a = sys_mmap(NULL, page_size_ * num_pages, PROT_READ | PROT_WRITE,
115  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
116 #else
117  void *a = sys_mmap2(NULL, page_size_ * num_pages, PROT_READ | PROT_WRITE,
118  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
119 #endif
120  if (a == MAP_FAILED)
121  return NULL;
122 
123  struct PageHeader *header = reinterpret_cast<PageHeader*>(a);
124  header->next = last_;
125  header->num_pages = num_pages;
126  last_ = header;
127 
128  return reinterpret_cast<uint8_t*>(a);
129  }
130 
131  void FreeAll() {
132  PageHeader *next;
133 
134  for (PageHeader *cur = last_; cur; cur = next) {
135  next = cur->next;
136  sys_munmap(cur, cur->num_pages * page_size_);
137  }
138  }
139 
140  struct PageHeader {
141  PageHeader *next; // pointer to the start of the next set of pages.
142  unsigned num_pages; // the number of pages in this set.
143  };
144 
145  const unsigned page_size_;
146  PageHeader *last_;
147  uint8_t *current_page_;
148  unsigned page_offset_;
149 };
150 
151 // Wrapper to use with STL containers
152 template <typename T>
153 struct PageStdAllocator : public std::allocator<T> {
154  typedef typename std::allocator<T>::pointer pointer;
155  typedef typename std::allocator<T>::size_type size_type;
156 
157  explicit PageStdAllocator(PageAllocator& allocator): allocator_(allocator) {}
158  template <class Other> PageStdAllocator(const PageStdAllocator<Other>& other)
159  : allocator_(other.allocator_) {}
160 
161  inline pointer allocate(size_type n, const void* = 0) {
162  return static_cast<pointer>(allocator_.Alloc(sizeof(T) * n));
163  }
164 
165  inline void deallocate(pointer, size_type) {
166  // The PageAllocator doesn't free.
167  }
168 
169  template <typename U> struct rebind {
171  };
172 
173  private:
174  // Silly workaround for the gcc from Android's ndk (gcc 4.6), which will
175  // otherwise complain that `other.allocator_` is private in the constructor
176  // code.
177  template<typename Other> friend struct PageStdAllocator;
178 
179  PageAllocator& allocator_;
180 };
181 
182 // A wasteful vector is a std::vector, except that it allocates memory from a
183 // PageAllocator. It's wasteful because, when resizing, it always allocates a
184 // whole new array since the PageAllocator doesn't support realloc.
185 template<class T>
186 class wasteful_vector : public std::vector<T, PageStdAllocator<T> > {
187  public:
188  wasteful_vector(PageAllocator* allocator, unsigned size_hint = 16)
189  : std::vector<T, PageStdAllocator<T> >(PageStdAllocator<T>(*allocator)) {
190  std::vector<T, PageStdAllocator<T> >::reserve(size_hint);
191  }
192 };
193 
194 } // namespace google_breakpad
195 
196 inline void* operator new(size_t nbytes,
197  google_breakpad::PageAllocator& allocator) {
198  return allocator.Alloc(nbytes);
199 }
200 
201 #endif // GOOGLE_BREAKPAD_COMMON_MEMORY_H_
void deallocate(pointer, size_type)
Definition: memory.h:165
pointer allocate(size_type n, const void *=0)
Definition: memory.h:161
std::allocator< T >::pointer pointer
Definition: memory.h:154
PageStdAllocator(PageAllocator &allocator)
Definition: memory.h:157
std::allocator< T >::size_type size_type
Definition: memory.h:155
PageStdAllocator(const PageStdAllocator< Other > &other)
Definition: memory.h:158
void * Alloc(unsigned bytes)
Definition: memory.h:70
bool OwnsPointer(const void *p)
Definition: memory.h:101
wasteful_vector(PageAllocator *allocator, unsigned size_hint=16)
Definition: memory.h:188