/thirdparty/breakpad/common/memory.h

http://github.com/tomahawk-player/tomahawk · C Header · 218 lines · 147 code · 33 blank · 38 comment · 17 complexity · 7a3e05f177804ae20aa256bb1f5d0242 MD5 · raw 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. #ifndef GOOGLE_BREAKPAD_COMMON_MEMORY_H_
  30. #define GOOGLE_BREAKPAD_COMMON_MEMORY_H_
  31. #include <stdint.h>
  32. #include <stdlib.h>
  33. #include <unistd.h>
  34. #include <sys/mman.h>
  35. #ifdef __APPLE__
  36. #define sys_mmap mmap
  37. #define sys_mmap2 mmap
  38. #define sys_munmap munmap
  39. #define MAP_ANONYMOUS MAP_ANON
  40. #else
  41. #include "third_party/lss/linux_syscall_support.h"
  42. #endif
  43. namespace google_breakpad {
  44. // This is very simple allocator which fetches pages from the kernel directly.
  45. // Thus, it can be used even when the heap may be corrupted.
  46. //
  47. // There is no free operation. The pages are only freed when the object is
  48. // destroyed.
  49. class PageAllocator {
  50. public:
  51. PageAllocator()
  52. : page_size_(getpagesize()),
  53. last_(NULL),
  54. current_page_(NULL),
  55. page_offset_(0) {
  56. }
  57. ~PageAllocator() {
  58. FreeAll();
  59. }
  60. void *Alloc(unsigned bytes) {
  61. if (!bytes)
  62. return NULL;
  63. if (current_page_ && page_size_ - page_offset_ >= bytes) {
  64. uint8_t *const ret = current_page_ + page_offset_;
  65. page_offset_ += bytes;
  66. if (page_offset_ == page_size_) {
  67. page_offset_ = 0;
  68. current_page_ = NULL;
  69. }
  70. return ret;
  71. }
  72. const unsigned pages =
  73. (bytes + sizeof(PageHeader) + page_size_ - 1) / page_size_;
  74. uint8_t *const ret = GetNPages(pages);
  75. if (!ret)
  76. return NULL;
  77. page_offset_ = (page_size_ - (page_size_ * pages - (bytes + sizeof(PageHeader)))) % page_size_;
  78. current_page_ = page_offset_ ? ret + page_size_ * (pages - 1) : NULL;
  79. return ret + sizeof(PageHeader);
  80. }
  81. private:
  82. uint8_t *GetNPages(unsigned num_pages) {
  83. #ifdef __x86_64
  84. void *a = sys_mmap(NULL, page_size_ * num_pages, PROT_READ | PROT_WRITE,
  85. MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
  86. #else
  87. void *a = sys_mmap2(NULL, page_size_ * num_pages, PROT_READ | PROT_WRITE,
  88. MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
  89. #endif
  90. if (a == MAP_FAILED)
  91. return NULL;
  92. struct PageHeader *header = reinterpret_cast<PageHeader*>(a);
  93. header->next = last_;
  94. header->num_pages = num_pages;
  95. last_ = header;
  96. return reinterpret_cast<uint8_t*>(a);
  97. }
  98. void FreeAll() {
  99. PageHeader *next;
  100. for (PageHeader *cur = last_; cur; cur = next) {
  101. next = cur->next;
  102. sys_munmap(cur, cur->num_pages * page_size_);
  103. }
  104. }
  105. struct PageHeader {
  106. PageHeader *next; // pointer to the start of the next set of pages.
  107. unsigned num_pages; // the number of pages in this set.
  108. };
  109. const unsigned page_size_;
  110. PageHeader *last_;
  111. uint8_t *current_page_;
  112. unsigned page_offset_;
  113. };
  114. // A wasteful vector is like a normal std::vector, except that it's very much
  115. // simplier and it allocates memory from a PageAllocator. It's wasteful
  116. // because, when resizing, it always allocates a whole new array since the
  117. // PageAllocator doesn't support realloc.
  118. template<class T>
  119. class wasteful_vector {
  120. public:
  121. wasteful_vector(PageAllocator *allocator, unsigned size_hint = 16)
  122. : allocator_(allocator),
  123. a_((T*) allocator->Alloc(sizeof(T) * size_hint)),
  124. allocated_(size_hint),
  125. used_(0) {
  126. }
  127. T& back() {
  128. return a_[used_ - 1];
  129. }
  130. const T& back() const {
  131. return a_[used_ - 1];
  132. }
  133. bool empty() const {
  134. return used_ == 0;
  135. }
  136. void push_back(const T& new_element) {
  137. if (used_ == allocated_)
  138. Realloc(allocated_ * 2);
  139. a_[used_++] = new_element;
  140. }
  141. size_t size() const {
  142. return used_;
  143. }
  144. void resize(unsigned sz, T c = T()) {
  145. // No need to test "sz >= 0", as "sz" is unsigned.
  146. if (sz <= used_) {
  147. used_ = sz;
  148. } else {
  149. unsigned a = allocated_;
  150. if (sz > a) {
  151. while (sz > a) {
  152. a *= 2;
  153. }
  154. Realloc(a);
  155. }
  156. while (sz > used_) {
  157. a_[used_++] = c;
  158. }
  159. }
  160. }
  161. T& operator[](size_t index) {
  162. return a_[index];
  163. }
  164. const T& operator[](size_t index) const {
  165. return a_[index];
  166. }
  167. private:
  168. void Realloc(unsigned new_size) {
  169. T *new_array =
  170. reinterpret_cast<T*>(allocator_->Alloc(sizeof(T) * new_size));
  171. memcpy(new_array, a_, used_ * sizeof(T));
  172. a_ = new_array;
  173. allocated_ = new_size;
  174. }
  175. PageAllocator *const allocator_;
  176. T *a_; // pointer to an array of |allocated_| elements.
  177. unsigned allocated_; // size of |a_|, in elements.
  178. unsigned used_; // number of used slots in |a_|.
  179. };
  180. } // namespace google_breakpad
  181. inline void* operator new(size_t nbytes,
  182. google_breakpad::PageAllocator& allocator) {
  183. return allocator.Alloc(nbytes);
  184. }
  185. #endif // GOOGLE_BREAKPAD_COMMON_MEMORY_H_