chunk.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. /*
  2. Copyright (c) 2003-2006 by Juliusz Chroboczek
  3. Permission is hereby granted, free of charge, to any person obtaining a copy
  4. of this software and associated documentation files (the "Software"), to deal
  5. in the Software without restriction, including without limitation the rights
  6. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. copies of the Software, and to permit persons to whom the Software is
  8. furnished to do so, subject to the following conditions:
  9. The above copyright notice and this permission notice shall be included in
  10. all copies or substantial portions of the Software.
  11. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  12. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  13. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  14. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  15. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  16. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  17. THE SOFTWARE.
  18. */
  19. #include "polipo.h"
  20. #define MB (1024 * 1024)
  21. int chunkLowMark = 0,
  22. chunkCriticalMark = 0,
  23. chunkHighMark = 0;
  24. void
  25. preinitChunks()
  26. {
  27. CONFIG_VARIABLE(chunkLowMark, CONFIG_INT,
  28. "Low mark for chunk memory (0 = auto).");
  29. CONFIG_VARIABLE(chunkCriticalMark, CONFIG_INT,
  30. "Critical mark for chunk memory (0 = auto).");
  31. CONFIG_VARIABLE(chunkHighMark, CONFIG_INT,
  32. "High mark for chunk memory.");
  33. }
  34. static void
  35. initChunksCommon()
  36. {
  37. #define ROUND_CHUNKS(a) a = (((unsigned long)(a) + CHUNK_SIZE - 1) / CHUNK_SIZE) * CHUNK_SIZE;
  38. int q;
  39. if(CHUNK_SIZE != 1 << log2_ceil(CHUNK_SIZE)) {
  40. do_log(L_ERROR, "CHUNK SIZE %d is not a power of two.\n", CHUNK_SIZE);
  41. exit(1);
  42. }
  43. ROUND_CHUNKS(chunkHighMark);
  44. ROUND_CHUNKS(chunkCriticalMark);
  45. ROUND_CHUNKS(chunkLowMark);
  46. if(chunkHighMark < 8 * CHUNK_SIZE) {
  47. int mem = physicalMemory();
  48. if(mem > 0)
  49. chunkHighMark = mem / 4;
  50. else
  51. chunkHighMark = 24 * MB;
  52. chunkHighMark = MIN(chunkHighMark, 24 * MB);
  53. chunkHighMark = MAX(chunkHighMark, 8 * CHUNK_SIZE);
  54. }
  55. if(chunkHighMark < MB / 2)
  56. fprintf(stderr,
  57. "Warning: little chunk memory (%d bytes)\n", chunkHighMark);
  58. q = 0;
  59. if(chunkLowMark <= 0) q = 1;
  60. if(chunkLowMark < 4 * CHUNK_SIZE ||
  61. chunkLowMark > chunkHighMark - 4 * CHUNK_SIZE) {
  62. chunkLowMark = MIN(chunkHighMark - 4 * CHUNK_SIZE,
  63. chunkHighMark * 3 / 4);
  64. ROUND_CHUNKS(chunkLowMark);
  65. if(!q) do_log(L_WARN, "Inconsistent chunkLowMark -- setting to %d.\n",
  66. chunkLowMark);
  67. }
  68. q = 0;
  69. if(chunkCriticalMark <= 0) q = 1;
  70. if(chunkCriticalMark >= chunkHighMark - 2 * CHUNK_SIZE ||
  71. chunkCriticalMark <= chunkLowMark + 2 * CHUNK_SIZE) {
  72. chunkCriticalMark =
  73. MIN(chunkHighMark - 2 * CHUNK_SIZE,
  74. chunkLowMark + (chunkHighMark - chunkLowMark) * 15 / 16);
  75. ROUND_CHUNKS(chunkCriticalMark);
  76. if(!q) do_log(L_WARN, "Inconsistent chunkCriticalMark -- "
  77. "setting to %d.\n", chunkCriticalMark);
  78. }
  79. #undef ROUND_CHUNKS
  80. }
  81. int used_chunks = 0;
  82. static void
  83. maybe_free_chunks(int arenas, int force)
  84. {
  85. if(force || used_chunks >= CHUNKS(chunkHighMark)) {
  86. discardObjects(force, force);
  87. }
  88. if(arenas)
  89. free_chunk_arenas();
  90. if(used_chunks >= CHUNKS(chunkLowMark) && !objectExpiryScheduled) {
  91. TimeEventHandlerPtr event;
  92. event = scheduleTimeEvent(1, discardObjectsHandler, 0, NULL);
  93. if(event)
  94. objectExpiryScheduled = 1;
  95. }
  96. }
  97. #ifdef MALLOC_CHUNKS
  98. void
  99. initChunks(void)
  100. {
  101. do_log(L_WARN, "Warning: using malloc(3) for chunk allocation.\n");
  102. used_chunks = 0;
  103. initChunksCommon();
  104. }
  105. void
  106. free_chunk_arenas()
  107. {
  108. return;
  109. }
  110. void *
  111. get_chunk()
  112. {
  113. void *chunk;
  114. if(used_chunks > CHUNKS(chunkHighMark))
  115. maybe_free_chunks(0, 0);
  116. if(used_chunks > CHUNKS(chunkHighMark))
  117. return NULL;
  118. chunk = malloc(CHUNK_SIZE);
  119. if(!chunk) {
  120. maybe_free_chunks(1, 1);
  121. chunk = malloc(CHUNK_SIZE);
  122. if(!chunk)
  123. return NULL;
  124. }
  125. used_chunks++;
  126. return chunk;
  127. }
  128. void *
  129. maybe_get_chunk()
  130. {
  131. void *chunk;
  132. if(used_chunks > CHUNKS(chunkHighMark))
  133. return NULL;
  134. chunk = malloc(CHUNK_SIZE);
  135. if(chunk)
  136. used_chunks++;
  137. return chunk;
  138. }
  139. void
  140. dispose_chunk(void *chunk)
  141. {
  142. assert(chunk != NULL);
  143. free(chunk);
  144. used_chunks--;
  145. }
  146. void
  147. free_chunks()
  148. {
  149. return;
  150. }
  151. int
  152. totalChunkArenaSize()
  153. {
  154. return used_chunks * CHUNK_SIZE;
  155. }
  156. #else
  157. #ifdef WIN32 /*MINGW*/
  158. #define MAP_FAILED NULL
  159. #define getpagesize() (64 * 1024)
  160. static void *
  161. alloc_arena(size_t size)
  162. {
  163. return VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
  164. }
  165. static int
  166. free_arena(void *addr, size_t size)
  167. {
  168. int rc;
  169. rc = VirtualFree(addr, size, MEM_RELEASE);
  170. if(!rc)
  171. rc = -1;
  172. return rc;
  173. }
  174. #else
  175. #ifndef MAP_FAILED
  176. #define MAP_FAILED ((void*)((long int)-1))
  177. #endif
  178. static void *
  179. alloc_arena(size_t size)
  180. {
  181. return mmap(NULL, size, PROT_READ | PROT_WRITE,
  182. MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
  183. }
  184. static int
  185. free_arena(void *addr, size_t size)
  186. {
  187. return munmap(addr, size);
  188. }
  189. #endif
  190. /* Memory is organised into a number of chunks of ARENA_CHUNKS chunks
  191. each. Every arena is pointed at by a struct _ChunkArena. */
  192. /* If currentArena is not NULL, it points at the last arena used,
  193. which gives very fast dispose/get sequences. */
  194. #define DEFINE_FFS(type, ffs_name) \
  195. int \
  196. ffs_name(type i) \
  197. { \
  198. int n; \
  199. if(i == 0) return 0; \
  200. n = 1; \
  201. while((i & 1) == 0) { \
  202. i >>= 1; \
  203. n++; \
  204. } \
  205. return n; \
  206. }
  207. #if defined(DEFAULT_ARENA_BITMAPS) + defined(LONG_ARENA_BITMAPS) + defined(LONG_LONG_ARENA_BITMAPS) > 1
  208. #error "Multiple sizes of arenas defined"
  209. #endif
  210. #if defined(DEFAULT_ARENA_BITMAPS) + defined(LONG_ARENA_BITMAPS) + defined(LONG_LONG_ARENA_BITMAPS) == 0
  211. #ifdef HAVE_FFSL
  212. /* This gives us 32-bit arena bitmaps on LP32, and 64-bit ones on LP64 */
  213. #define LONG_ARENA_BITMAPS
  214. #else
  215. #define DEFAULT_ARENA_BITMAPS
  216. #endif
  217. #endif
  218. #if defined(DEFAULT_ARENA_BITMAPS)
  219. #ifndef HAVE_FFS
  220. DEFINE_FFS(int, ffs)
  221. #endif
  222. typedef unsigned int ChunkBitmap;
  223. #define BITMAP_FFS(bitmap) (ffs(bitmap))
  224. #elif defined(LONG_ARENA_BITMAPS)
  225. #ifndef HAVE_FFSL
  226. DEFINE_FFS(long, ffsl)
  227. #endif
  228. typedef unsigned long ChunkBitmap;
  229. #define BITMAP_FFS(bitmap) (ffsl(bitmap))
  230. #elif defined(LONG_LONG_ARENA_BITMAPS)
  231. #ifndef HAVE_FFSLL
  232. DEFINE_FFS(long long, ffsll)
  233. #endif
  234. typedef unsigned long long ChunkBitmap;
  235. #define BITMAP_FFS(bitmap) (ffsll(bitmap))
  236. #else
  237. #error "You lose"
  238. #endif
  239. #define ARENA_CHUNKS ((unsigned)sizeof(ChunkBitmap) * 8)
  240. #define EMPTY_BITMAP (~(ChunkBitmap)0)
  241. #define BITMAP_BIT(i) (((ChunkBitmap)1) << (i))
  242. static int pagesize;
  243. typedef struct _ChunkArena {
  244. ChunkBitmap bitmap;
  245. char *chunks;
  246. } ChunkArenaRec, *ChunkArenaPtr;
  247. static ChunkArenaPtr chunkArenas, currentArena;
  248. static int numArenas;
  249. #define CHUNK_IN_ARENA(chunk, arena) \
  250. ((arena)->chunks && \
  251. (char*)(chunk) >= (arena)->chunks && \
  252. (char*)(chunk) < (arena)->chunks + (ARENA_CHUNKS * CHUNK_SIZE))
  253. #define CHUNK_ARENA_INDEX(chunk, arena) \
  254. ((unsigned)((unsigned long)(((char*)(chunk) - (arena)->chunks)) / \
  255. CHUNK_SIZE))
  256. void
  257. initChunks(void)
  258. {
  259. int i;
  260. used_chunks = 0;
  261. initChunksCommon();
  262. pagesize = getpagesize();
  263. if((CHUNK_SIZE * ARENA_CHUNKS) % pagesize != 0) {
  264. do_log(L_ERROR,
  265. "The arena size %d (%d x %d) "
  266. "is not a multiple of the page size %d.\n",
  267. ARENA_CHUNKS * CHUNK_SIZE, ARENA_CHUNKS, CHUNK_SIZE, pagesize);
  268. abort();
  269. }
  270. numArenas =
  271. (CHUNKS(chunkHighMark) + (ARENA_CHUNKS - 1)) / ARENA_CHUNKS;
  272. chunkArenas = malloc(numArenas * sizeof(ChunkArenaRec));
  273. if(chunkArenas == NULL) {
  274. do_log(L_ERROR, "Couldn't allocate chunk arenas.\n");
  275. exit (1);
  276. }
  277. for(i = 0; i < numArenas; i++) {
  278. chunkArenas[i].bitmap = EMPTY_BITMAP;
  279. chunkArenas[i].chunks = NULL;
  280. }
  281. currentArena = NULL;
  282. }
  283. static ChunkArenaPtr
  284. findArena()
  285. {
  286. ChunkArenaPtr arena = NULL;
  287. int i;
  288. for(i = 0; i < numArenas; i++) {
  289. arena = &(chunkArenas[i]);
  290. if(arena->bitmap != 0)
  291. break;
  292. else
  293. arena = NULL;
  294. }
  295. assert(arena != NULL);
  296. if(!arena->chunks) {
  297. void *p;
  298. p = alloc_arena(CHUNK_SIZE * ARENA_CHUNKS);
  299. if(p == MAP_FAILED) {
  300. do_log_error(L_ERROR, errno, "Couldn't allocate chunk");
  301. maybe_free_chunks(1, 1);
  302. return NULL;
  303. }
  304. arena->chunks = p;
  305. }
  306. return arena;
  307. }
  308. void *
  309. get_chunk()
  310. {
  311. unsigned i;
  312. ChunkArenaPtr arena = NULL;
  313. if(currentArena && currentArena->bitmap != 0) {
  314. arena = currentArena;
  315. } else {
  316. if(used_chunks >= CHUNKS(chunkHighMark))
  317. maybe_free_chunks(0, 0);
  318. if(used_chunks >= CHUNKS(chunkHighMark))
  319. return NULL;
  320. arena = findArena();
  321. if(!arena)
  322. return NULL;
  323. currentArena = arena;
  324. }
  325. i = BITMAP_FFS(arena->bitmap) - 1;
  326. arena->bitmap &= ~BITMAP_BIT(i);
  327. used_chunks++;
  328. return arena->chunks + CHUNK_SIZE * i;
  329. }
  330. void *
  331. maybe_get_chunk()
  332. {
  333. unsigned i;
  334. ChunkArenaPtr arena = NULL;
  335. if(currentArena && currentArena->bitmap != 0) {
  336. arena = currentArena;
  337. } else {
  338. if(used_chunks >= CHUNKS(chunkHighMark))
  339. return NULL;
  340. arena = findArena();
  341. if(!arena)
  342. return NULL;
  343. currentArena = arena;
  344. }
  345. i = BITMAP_FFS(arena->bitmap) - 1;
  346. arena->bitmap &= ~BITMAP_BIT(i);
  347. used_chunks++;
  348. return arena->chunks + CHUNK_SIZE * i;
  349. }
  350. void
  351. dispose_chunk(void *chunk)
  352. {
  353. ChunkArenaPtr arena = NULL;
  354. unsigned i;
  355. assert(chunk != NULL);
  356. if(currentArena && CHUNK_IN_ARENA(chunk, currentArena)) {
  357. arena = currentArena;
  358. } else {
  359. for(i = 0; i < numArenas; i++) {
  360. arena = &(chunkArenas[i]);
  361. if(CHUNK_IN_ARENA(chunk, arena))
  362. break;
  363. }
  364. assert(arena != NULL);
  365. currentArena = arena;
  366. }
  367. i = CHUNK_ARENA_INDEX(chunk, arena);
  368. arena->bitmap |= BITMAP_BIT(i);
  369. used_chunks--;
  370. }
  371. void
  372. free_chunk_arenas()
  373. {
  374. ChunkArenaPtr arena;
  375. int i, rc;
  376. for(i = 0; i < numArenas; i++) {
  377. arena = &(chunkArenas[i]);
  378. if(arena->bitmap == EMPTY_BITMAP && arena->chunks) {
  379. rc = free_arena(arena->chunks, CHUNK_SIZE * ARENA_CHUNKS);
  380. if(rc < 0) {
  381. do_log_error(L_ERROR, errno, "Couldn't unmap memory");
  382. continue;
  383. }
  384. arena->chunks = NULL;
  385. }
  386. }
  387. if(currentArena && currentArena->chunks == NULL)
  388. currentArena = NULL;
  389. }
  390. int
  391. totalChunkArenaSize()
  392. {
  393. ChunkArenaPtr arena;
  394. int i, size = 0;
  395. for(i = 0; i < numArenas; i++) {
  396. arena = &(chunkArenas[i]);
  397. if(arena->chunks)
  398. size += (CHUNK_SIZE * ARENA_CHUNKS);
  399. }
  400. return size;
  401. }
  402. #endif