Planeshift
|
00001 // Copyright (c) 2009, Google Inc. 00002 // All rights reserved. 00003 // 00004 // Redistribution and use in source and binary forms, with or without 00005 // modification, are permitted provided that the following conditions are 00006 // met: 00007 // 00008 // * Redistributions of source code must retain the above copyright 00009 // notice, this list of conditions and the following disclaimer. 00010 // * Redistributions in binary form must reproduce the above 00011 // copyright notice, this list of conditions and the following disclaimer 00012 // in the documentation and/or other materials provided with the 00013 // distribution. 00014 // * Neither the name of Google Inc. nor the names of its 00015 // contributors may be used to endorse or promote products derived from 00016 // this software without specific prior written permission. 00017 // 00018 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00019 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00020 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 00021 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 00022 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00023 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 00024 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 00025 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 00026 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00027 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 00028 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00029 00030 #ifndef GOOGLE_BREAKPAD_COMMON_MEMORY_H_ 00031 #define GOOGLE_BREAKPAD_COMMON_MEMORY_H_ 00032 00033 #include <stdint.h> 00034 #include <stdlib.h> 00035 #include <unistd.h> 00036 #include <sys/mman.h> 00037 00038 #include <memory> 00039 #include <vector> 00040 00041 #ifdef __APPLE__ 00042 #define sys_mmap mmap 00043 #define sys_mmap2 mmap 00044 #define sys_munmap munmap 00045 #define MAP_ANONYMOUS MAP_ANON 00046 #else 00047 #include "third_party/lss/linux_syscall_support.h" 00048 #endif 00049 00050 namespace google_breakpad { 00051 00052 // This is very simple allocator which fetches pages from the kernel directly. 00053 // Thus, it can be used even when the heap may be corrupted. 00054 // 00055 // There is no free operation. The pages are only freed when the object is 00056 // destroyed. 00057 class PageAllocator { 00058 public: 00059 PageAllocator() 00060 : page_size_(getpagesize()), 00061 last_(NULL), 00062 current_page_(NULL), 00063 page_offset_(0) { 00064 } 00065 00066 ~PageAllocator() { 00067 FreeAll(); 00068 } 00069 00070 void *Alloc(unsigned bytes) { 00071 if (!bytes) 00072 return NULL; 00073 00074 if (current_page_ && page_size_ - page_offset_ >= bytes) { 00075 uint8_t *const ret = current_page_ + page_offset_; 00076 page_offset_ += bytes; 00077 if (page_offset_ == page_size_) { 00078 page_offset_ = 0; 00079 current_page_ = NULL; 00080 } 00081 00082 return ret; 00083 } 00084 00085 const unsigned pages = 00086 (bytes + sizeof(PageHeader) + page_size_ - 1) / page_size_; 00087 uint8_t *const ret = GetNPages(pages); 00088 if (!ret) 00089 return NULL; 00090 00091 page_offset_ = 00092 (page_size_ - (page_size_ * pages - (bytes + sizeof(PageHeader)))) % 00093 page_size_; 00094 current_page_ = page_offset_ ? ret + page_size_ * (pages - 1) : NULL; 00095 00096 return ret + sizeof(PageHeader); 00097 } 00098 00099 // Checks whether the page allocator owns the passed-in pointer. 00100 // This method exists for testing pursposes only. 00101 bool OwnsPointer(const void* p) { 00102 for (PageHeader* header = last_; header; header = header->next) { 00103 const char* current = reinterpret_cast<char*>(header); 00104 if ((p >= current) && (p < current + header->num_pages * page_size_)) 00105 return true; 00106 } 00107 00108 return false; 00109 } 00110 00111 private: 00112 uint8_t *GetNPages(unsigned num_pages) { 00113 #ifdef __x86_64 00114 void *a = sys_mmap(NULL, page_size_ * num_pages, PROT_READ | PROT_WRITE, 00115 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 00116 #else 00117 void *a = sys_mmap2(NULL, page_size_ * num_pages, PROT_READ | PROT_WRITE, 00118 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 00119 #endif 00120 if (a == MAP_FAILED) 00121 return NULL; 00122 00123 struct PageHeader *header = reinterpret_cast<PageHeader*>(a); 00124 header->next = last_; 00125 header->num_pages = num_pages; 00126 last_ = header; 00127 00128 return reinterpret_cast<uint8_t*>(a); 00129 } 00130 00131 void FreeAll() { 00132 PageHeader *next; 00133 00134 for (PageHeader *cur = last_; cur; cur = next) { 00135 next = cur->next; 00136 sys_munmap(cur, cur->num_pages * page_size_); 00137 } 00138 } 00139 00140 struct PageHeader { 00141 PageHeader *next; // pointer to the start of the next set of pages. 00142 unsigned num_pages; // the number of pages in this set. 00143 }; 00144 00145 const unsigned page_size_; 00146 PageHeader *last_; 00147 uint8_t *current_page_; 00148 unsigned page_offset_; 00149 }; 00150 00151 // Wrapper to use with STL containers 00152 template <typename T> 00153 struct PageStdAllocator : public std::allocator<T> { 00154 typedef typename std::allocator<T>::pointer pointer; 00155 typedef typename std::allocator<T>::size_type size_type; 00156 00157 explicit PageStdAllocator(PageAllocator& allocator): allocator_(allocator) {} 00158 template <class Other> PageStdAllocator(const PageStdAllocator<Other>& other) 00159 : allocator_(other.allocator_) {} 00160 00161 inline pointer allocate(size_type n, const void* = 0) { 00162 return static_cast<pointer>(allocator_.Alloc(sizeof(T) * n)); 00163 } 00164 00165 inline void deallocate(pointer, size_type) { 00166 // The PageAllocator doesn't free. 00167 } 00168 00169 template <typename U> struct rebind { 00170 typedef PageStdAllocator<U> other; 00171 }; 00172 00173 private: 00174 // Silly workaround for the gcc from Android's ndk (gcc 4.6), which will 00175 // otherwise complain that `other.allocator_` is private in the constructor 00176 // code. 00177 template<typename Other> friend struct PageStdAllocator; 00178 00179 PageAllocator& allocator_; 00180 }; 00181 00182 // A wasteful vector is a std::vector, except that it allocates memory from a 00183 // PageAllocator. It's wasteful because, when resizing, it always allocates a 00184 // whole new array since the PageAllocator doesn't support realloc. 00185 template<class T> 00186 class wasteful_vector : public std::vector<T, PageStdAllocator<T> > { 00187 public: 00188 wasteful_vector(PageAllocator* allocator, unsigned size_hint = 16) 00189 : std::vector<T, PageStdAllocator<T> >(PageStdAllocator<T>(*allocator)) { 00190 std::vector<T, PageStdAllocator<T> >::reserve(size_hint); 00191 } 00192 }; 00193 00194 } // namespace google_breakpad 00195 00196 inline void* operator new(size_t nbytes, 00197 google_breakpad::PageAllocator& allocator) { 00198 return allocator.Alloc(nbytes); 00199 } 00200 00201 #endif // GOOGLE_BREAKPAD_COMMON_MEMORY_H_