ChipMaster's trial hacks on C++CMS starting with v1.2.1. Not sure I'll follow on with the v2 since it looks to be breaking and mostly frivolous.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

324 lines
8.0 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (C) 2008-2012 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
  4. //
  5. // See accompanying file COPYING.TXT file for licensing details.
  6. //
  7. ///////////////////////////////////////////////////////////////////////////////
  8. #ifndef CPPCMS_PRIVATE_BUDDY_ALLOCATOR_H
  9. #define CPPCMS_PRIVATE_BUDDY_ALLOCATOR_H
  10. #include <cppcms/defs.h>
  11. #include <stddef.h>
  12. #include <assert.h>
  13. #include <memory.h>
  14. #ifdef DEBUG_ALLOCATOR
  15. #include <stdio.h>
  16. #define LOG(...) do { printf("%5d:",__LINE__); printf( __VA_ARGS__ ); printf("\n"); } while(0)
  17. #else
  18. #define LOG(...) do {} while(0)
  19. #endif
  20. #ifdef TEST_ALLOCATOR
  21. #include <map>
  22. #include <utility>
  23. #endif
  24. namespace cppcms {
  25. namespace impl {
  26. class buddy_allocator {
  27. struct page;
  28. public:
  29. static const int alignment_bits = (sizeof(void*) > 4 ? 4 : 3);
  30. static const size_t alignment = (1 << alignment_bits); // 8 or 16 at 32 and 64 bit platform
  31. buddy_allocator(size_t memory_size)
  32. {
  33. assert(sizeof(*this) <= memory_size);
  34. assert(sizeof(page) <= alignment * 2);
  35. assert(sizeof(*this) % alignment == 0);
  36. memory_size_ = memory_size - sizeof(*this);
  37. max_bit_size_ = -1;
  38. memset(free_list_,0,sizeof(free_list_));
  39. LOG("Usable memory %zd",memory_size_);
  40. char *pos = memory();
  41. size_t reminder = memory_size_;
  42. for(;;) {
  43. int bits = containts_bits(reminder);
  44. if(bits < alignment_bits + 1)
  45. break;
  46. size_t page_size = size_t(1) << bits;
  47. page *p=reinterpret_cast<page *>(pos);
  48. reminder -= page_size;
  49. LOG("Added chunk of size %zd (%d) at pos %zx reminder %zd",page_size,bits,pos - memory(),reminder);
  50. pos+= page_size;
  51. p->bits = bits;
  52. p->prev = 0;
  53. p->next = 0;
  54. free_list_[bits] = p;
  55. if(max_bit_size_ == -1)
  56. max_bit_size_ = bits;
  57. }
  58. }
  59. void *malloc(size_t required_size)
  60. {
  61. size_t n = ((required_size+alignment-1)/alignment + 1)*alignment;
  62. int bits = get_bits(n);
  63. LOG("Allocating chunk of size %zd (%d) for request of %zd",n,bits,required_size);
  64. page *p = page_alloc(bits);
  65. LOG("Got %zx",(p?(char*)(p) - memory():0));
  66. if(!p)
  67. return 0;
  68. void *r = reinterpret_cast<char *>(p) + alignment;
  69. return r;
  70. }
  71. void free(void *ptr)
  72. {
  73. if(!ptr)
  74. return;
  75. page *p = reinterpret_cast<page *>(static_cast<char *>(ptr) - alignment);
  76. assert(p->bits & page_in_use);
  77. LOG("Freeing page %zx with bits %d",(char *)(p) - memory() , p->bits - page_in_use);
  78. free_page(p);
  79. }
  80. size_t total_free_memory()
  81. {
  82. size_t total = 0;
  83. for(unsigned i=0;i<sizeof(void*)*8;i++) {
  84. total += total_free_at(i);
  85. }
  86. return total;
  87. }
  88. size_t max_free_chunk()
  89. {
  90. for(int bits=sizeof(void*)*8-1;bits>0;bits--) {
  91. if(free_list_[bits])
  92. return total_free_at(bits);
  93. }
  94. return 0;
  95. }
  96. size_t total_free_at(int bits)
  97. {
  98. size_t count=0;
  99. for(page *p=free_list_[bits];p;p=p->next)
  100. count++;
  101. return count * ((size_t(1) << bits) - alignment);
  102. }
  103. #ifdef TEST_ALLOCATOR
  104. void test_free() {
  105. char *p=memory();
  106. for(int i=max_bit_size_;i>=0;i--) {
  107. if(free_list_[i]) {
  108. TEST((char*)free_list_[i]==p);
  109. TEST(free_list_[i]->bits == i);
  110. p += 1ul << free_list_[i]->bits;
  111. }
  112. }
  113. TEST(p<= memory() + memory_size_);
  114. TEST(memory() + memory_size_ - p < int(alignment * 2));
  115. }
  116. void test_and_get_free_pages(std::map<page *,bool> *all_pages=0)
  117. {
  118. for(int i=0;i<int(sizeof(void*)*8);i++) {
  119. if(i+1 < alignment_bits)
  120. TEST(free_list_[i]==0);
  121. if(i>max_bit_size_)
  122. TEST(free_list_[i]==0);
  123. for(page *p=free_list_[i];p;p=p->next) {
  124. // check bit marks
  125. TEST(p->bits == i);
  126. // check linked list
  127. if(p==free_list_[i])
  128. TEST(p->prev == 0);
  129. else
  130. TEST(p->prev->next == p);
  131. if(p->next != 0)
  132. TEST(p->next->prev == p);
  133. if(all_pages) {
  134. TEST(all_pages->find(p) == all_pages->end());
  135. all_pages->insert(std::make_pair(p,true));
  136. }
  137. page *buddy = get_buddy(p);
  138. if(buddy) {
  139. TEST((buddy->bits & page_in_use) || (buddy->bits < p->bits));
  140. TEST((buddy->bits & 0xFF) <= p->bits);
  141. if(all_pages && (buddy->bits & page_in_use))
  142. TEST(all_pages->find(buddy) == all_pages->end());
  143. }
  144. }
  145. }
  146. }
  147. void test_consistent(void * const *allocated,size_t allocated_size)
  148. {
  149. std::map<page *,bool> all_pages;
  150. test_and_get_free_pages(&all_pages);
  151. for(size_t i=0;i<allocated_size;i++) {
  152. if(allocated[i]==0)
  153. continue;
  154. page *p=reinterpret_cast<page *>(static_cast<char *>(allocated[i]) - alignment);
  155. TEST(p->bits & page_in_use);
  156. TEST(all_pages.find(p)==all_pages.end());
  157. all_pages[p]=false;
  158. }
  159. size_t pos = 0;
  160. for(std::map<page *,bool>::const_iterator pg=all_pages.begin();pg!=all_pages.end();++pg) {
  161. page *p=pg->first;
  162. bool is_free = pg->second;
  163. TEST(is_free == !(p->bits & page_in_use));
  164. size_t page_pos = reinterpret_cast<char *>(pg->first) - memory();
  165. TEST(pos == page_pos);
  166. size_t page_size = size_t(1) << (pg->first->bits & 0xFF);
  167. pos+= page_size;
  168. TEST(pos <= memory_size_);
  169. }
  170. TEST(memory_size_ - pos < size_t(alignment * 2));
  171. }
  172. void test_consistent()
  173. {
  174. test_and_get_free_pages(0);
  175. }
  176. #endif
  177. private:
  178. static const int page_in_use = 0x100;
  179. struct page {
  180. int bits;
  181. page *next;
  182. page *prev;
  183. };
  184. static int containts_bits(size_t n)
  185. {
  186. for(int i=sizeof(n)*8-2;i>0;i--) {
  187. size_t upper = size_t(1) << (i + 1);
  188. size_t lower = upper / 2;
  189. if(lower <= n && n< upper)
  190. return i;
  191. }
  192. return -1;
  193. }
  194. static int get_bits(size_t n)
  195. {
  196. int i;
  197. for(i=0;i<int(sizeof(n) * 8);i++) {
  198. if( (1ull << i) >= n)
  199. break;
  200. }
  201. return i;
  202. }
  203. page *page_alloc(int bit_size)
  204. {
  205. LOG("Allocating page %d bits",bit_size);
  206. if(bit_size > max_bit_size_) {
  207. LOG("Too big size requested %d > %d",bit_size,max_bit_size_);
  208. return 0;
  209. }
  210. page *result = 0;
  211. if(free_list_[bit_size]==0) {
  212. LOG("No page for bits %d, splitting",bit_size);
  213. page *to_split = page_alloc(bit_size + 1);
  214. if(!to_split)
  215. return 0;
  216. page *unused = reinterpret_cast<page *>(reinterpret_cast<char *>(to_split) + (size_t(1)<<bit_size));
  217. unused->prev = 0;
  218. unused->next = 0;
  219. unused->bits = bit_size;
  220. free_list_[bit_size] = unused;
  221. result = to_split;
  222. LOG("Got %zx; %zx is spare",(char*)to_split - memory(),(char*)unused - memory());
  223. }
  224. else {
  225. result = free_list_[bit_size];
  226. free_list_[bit_size]=result->next;
  227. if(free_list_[bit_size])
  228. free_list_[bit_size]->prev = 0;
  229. LOG("Using free page %zx, disconnecting",(char*)result - memory());
  230. }
  231. result->next = 0;
  232. result->prev = 0;
  233. result->bits = bit_size + page_in_use;
  234. LOG("Result is %zx",(char*)result - memory());
  235. return result;
  236. }
  237. page *get_buddy(page *p)
  238. {
  239. size_t p_ptr = reinterpret_cast<char *>(p) - memory();
  240. size_t p_len = size_t(1) << p->bits;
  241. size_t b_ptr = p_len ^ p_ptr;
  242. if(b_ptr + p_len > memory_size_)
  243. return 0;
  244. return reinterpret_cast<page *>(b_ptr + memory());
  245. }
  246. void free_page(page *p)
  247. {
  248. assert(p->bits & page_in_use);
  249. for(;;) {
  250. p->bits -= page_in_use;
  251. int bits = p->bits;
  252. LOG("Freing page with bits %d at %zx",bits,(char*)(p) - memory());
  253. page *buddy = get_buddy(p);
  254. if(buddy != 0 && buddy->bits == bits) {
  255. page *bnext = buddy->next;
  256. page *bprev = buddy->prev;
  257. if(bnext)
  258. bnext->prev = bprev;
  259. if(bprev)
  260. bprev->next = bnext;
  261. if(bprev==0) {
  262. free_list_[bits]=bnext;
  263. }
  264. if(buddy < p)
  265. p=buddy;
  266. LOG("Found free buddy merging to %zx with bits %d freeing it as well",(char*)(p)-memory(),bits+1);
  267. p->bits = (bits+1) + page_in_use;
  268. continue; // tail recursion
  269. }
  270. else {
  271. LOG("No buddy avalible - adding to free list");
  272. p->next = free_list_[bits];
  273. p->prev = 0;
  274. if(p->next)
  275. p->next->prev = p;
  276. free_list_[bits] = p;
  277. return;
  278. }
  279. }
  280. }
  281. char *memory()
  282. {
  283. return reinterpret_cast<char *>(this) + sizeof(*this);
  284. }
  285. private:
  286. // DATA
  287. page *free_list_[sizeof(void*)*8]; // 16 always
  288. size_t memory_size_;
  289. int max_bit_size_; // at least sizeof(size_t)
  290. CPPCMS_UNUSED_MEMBER size_t padding_for_alignment_[2];
  291. };
  292. } // impl
  293. } // cppcms
  294. #endif