2 Copyright (c) 2003, 2004 by Juliusz Chroboczek
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 #define MB (1024 * 1024)
27 chunkCriticalMark
= 0,
28 chunkHighMark
= 8 * MB
;
33 CONFIG_VARIABLE(chunkLowMark
, CONFIG_INT
,
34 "Low mark for chunk memory (0 = auto).");
35 CONFIG_VARIABLE(chunkCriticalMark
, CONFIG_INT
,
36 "Critical mark for chunk memory (0 = auto).");
37 CONFIG_VARIABLE(chunkHighMark
, CONFIG_INT
,
38 "High mark for chunk memory.");
44 #define ROUND_CHUNKS(a) a = (((a) + CHUNK_SIZE - 1) / CHUNK_SIZE) * CHUNK_SIZE;
47 if(CHUNK_SIZE
!= 1 << log2_ceil(CHUNK_SIZE
)) {
48 do_log(L_ERROR
, "CHUNK SIZE %d is not a power of two.\n", CHUNK_SIZE
);
52 ROUND_CHUNKS(chunkHighMark
);
53 ROUND_CHUNKS(chunkCriticalMark
);
54 ROUND_CHUNKS(chunkLowMark
);
56 if(chunkHighMark
< 8 * CHUNK_SIZE
) {
57 chunkHighMark
= 8 * CHUNK_SIZE
;
58 do_log(L_WARN
, "Impossibly low chunkHighMark -- setting to %d.\n",
63 if(chunkLowMark
<= 0) q
= 1;
64 if(chunkLowMark
< 4 * CHUNK_SIZE
||
65 chunkLowMark
> chunkHighMark
- 4 * CHUNK_SIZE
) {
66 chunkLowMark
= MIN(chunkHighMark
- 4 * CHUNK_SIZE
,
67 chunkHighMark
* 3 / 4);
68 ROUND_CHUNKS(chunkLowMark
);
69 if(!q
) do_log(L_WARN
, "Inconsistent chunkLowMark -- setting to %d.\n",
74 if(chunkCriticalMark
<= 0) q
= 1;
75 if(chunkCriticalMark
>= chunkHighMark
- 2 * CHUNK_SIZE
||
76 chunkCriticalMark
<= chunkLowMark
+ 2 * CHUNK_SIZE
) {
78 MIN(chunkHighMark
- 2 * CHUNK_SIZE
,
79 chunkLowMark
+ (chunkHighMark
- chunkLowMark
) * 15 / 16);
80 ROUND_CHUNKS(chunkCriticalMark
);
81 if(!q
) do_log(L_WARN
, "Inconsistent chunkCriticalMark -- "
82 "setting to %d.\n", chunkCriticalMark
);
91 maybe_free_chunks(int arenas
, int force
)
93 if(force
|| used_chunks
>= CHUNKS(chunkHighMark
)) {
94 discardObjects(force
, force
);
100 if(used_chunks
>= CHUNKS(chunkLowMark
) && !objectExpiryScheduled
) {
101 TimeEventHandlerPtr event
;
102 event
= scheduleTimeEvent(1, discardObjectsHandler
, 0, NULL
);
104 objectExpiryScheduled
= 1;
115 do_log(L_WARN
, "Warning: using malloc(3) for chunk allocation.\n");
131 if(used_chunks
> CHUNKS(chunkHighMark
))
132 maybe_free_chunks(0, 0);
133 if(used_chunks
> CHUNKS(chunkHighMark
))
135 chunk
= malloc(CHUNK_SIZE
);
137 maybe_free_chunks(1, 1);
138 chunk
= malloc(CHUNK_SIZE
);
150 if(used_chunks
> CHUNKS(chunkHighMark
))
152 chunk
= malloc(CHUNK_SIZE
);
159 dispose_chunk(void *chunk
)
161 assert(chunk
!= NULL
);
175 #define MAP_FAILED ((void*)((long int)-1))
178 /* Memory is organised into a number of chunks of ARENA_CHUNKS chunks
179 each. Every arena is pointed at by a struct _ChunkArena. */
180 /* If currentArena is not NULL, it points at an arena with free space.
181 This gives better locality, but is mostly useful in order to have
182 very fast dipose/get sequences. */
184 /* If you change this, you'll need to provide a replacement for ffs()
186 typedef unsigned int ChunkBitmap
;
187 #define ARENA_CHUNKS ((int)sizeof(ChunkBitmap) * 8)
190 typedef struct _ChunkArena
{
193 } ChunkArenaRec
, *ChunkArenaPtr
;
195 static ChunkArenaPtr chunkArenas
, currentArena
;
196 static int numArenas
;
197 #define CHUNK_IN_ARENA(chunk, arena) \
198 ((arena)->chunks && \
199 (char*)(chunk) >= (arena)->chunks && \
200 (char*)(chunk)<(arena)->chunks + (ARENA_CHUNKS * CHUNK_SIZE))
202 #define CHUNK_ARENA_INDEX(chunk, arena) \
203 (((char*)(chunk) - (arena)->chunks) / CHUNK_SIZE)
211 pagesize
= getpagesize();
212 if((CHUNK_SIZE
* ARENA_CHUNKS
) % pagesize
!= 0) {
214 "The arena size %d (%d x %d) "
215 "is not a multiple of the page size %d.\n",
216 ARENA_CHUNKS
* CHUNK_SIZE
, ARENA_CHUNKS
, CHUNK_SIZE
, pagesize
);
220 (CHUNKS(chunkHighMark
) + (ARENA_CHUNKS
- 1)) / ARENA_CHUNKS
;
221 chunkArenas
= malloc(numArenas
* sizeof(ChunkArenaRec
));
222 if(chunkArenas
== NULL
) {
223 do_log(L_ERROR
, "Couldn't allocate chunk arenas.\n");
226 for(i
= 0; i
< numArenas
; i
++) {
227 chunkArenas
[i
].bitmap
= ~(ChunkBitmap
)0;
228 chunkArenas
[i
].chunks
= NULL
;
236 ChunkArenaPtr arena
= NULL
;
239 for(i
= 0; i
< numArenas
; i
++) {
240 arena
= &(chunkArenas
[i
]);
241 if(arena
->bitmap
!= 0)
247 assert(arena
!= NULL
);
251 p
= mmap(NULL
, CHUNK_SIZE
* ARENA_CHUNKS
, PROT_READ
| PROT_WRITE
,
252 MAP_PRIVATE
| MAP_ANONYMOUS
, -1, 0);
253 if(p
== MAP_FAILED
) {
254 do_log_error(L_ERROR
, errno
, "Couldn't allocate chunk");
255 maybe_free_chunks(1, 1);
267 ChunkArenaPtr arena
= NULL
;
270 arena
= currentArena
;
272 if(used_chunks
>= CHUNKS(chunkHighMark
))
273 maybe_free_chunks(0, 0);
275 if(used_chunks
>= CHUNKS(chunkHighMark
))
282 i
= ffs(arena
->bitmap
) - 1;
283 arena
->bitmap
&= ~(1 << i
);
284 if(arena
->bitmap
!= 0)
285 currentArena
= arena
;
289 return arena
->chunks
+ CHUNK_SIZE
* i
;
296 ChunkArenaPtr arena
= NULL
;
299 arena
= currentArena
;
301 if(used_chunks
>= CHUNKS(chunkHighMark
))
308 i
= ffs(arena
->bitmap
) - 1;
309 arena
->bitmap
&= ~(1 << i
);
310 if(arena
->bitmap
!= 0)
311 currentArena
= arena
;
315 return arena
->chunks
+ CHUNK_SIZE
* i
;
319 dispose_chunk(void *chunk
)
321 ChunkArenaPtr arena
= NULL
;
324 assert(chunk
!= NULL
);
326 if(currentArena
&& CHUNK_IN_ARENA(chunk
, currentArena
)) {
327 arena
= currentArena
;
329 for(i
= 0; i
< numArenas
; i
++) {
330 arena
= &(chunkArenas
[i
]);
331 if(CHUNK_IN_ARENA(chunk
, arena
))
335 assert(arena
&& arena
->chunks
);
337 i
= CHUNK_ARENA_INDEX(chunk
, arena
);
338 arena
->bitmap
|= (1 << i
);
340 currentArena
= arena
;
349 for(i
= 0; i
< numArenas
; i
++) {
350 arena
= &(chunkArenas
[i
]);
351 if(arena
->bitmap
== (ChunkBitmap
)~0 && arena
->chunks
) {
352 rc
= munmap(arena
->chunks
, CHUNK_SIZE
* ARENA_CHUNKS
);
354 do_log_error(L_ERROR
, errno
, "Couldn't unmap memory");
357 arena
->chunks
= NULL
;
360 if(currentArena
&& currentArena
->chunks
== NULL
)