/src/libreoffice/sal/rtl/alloc_arena.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
11 | | * Licensed to the Apache Software Foundation (ASF) under one or more |
12 | | * contributor license agreements. See the NOTICE file distributed |
13 | | * with this work for additional information regarding copyright |
14 | | * ownership. The ASF licenses this file to you under the Apache |
15 | | * License, Version 2.0 (the "License"); you may not use this file |
16 | | * except in compliance with the License. You may obtain a copy of |
17 | | * the License at http://www.apache.org/licenses/LICENSE-2.0 . |
18 | | */ |
19 | | |
20 | | #include <sal/config.h> |
21 | | |
22 | | #include "alloc_arena.hxx" |
23 | | |
24 | | #include "alloc_impl.hxx" |
25 | | #include <rtllifecycle.h> |
26 | | |
27 | | #include <cassert> |
28 | | #include <string.h> |
29 | | #include <stdio.h> |
30 | | |
31 | | #if defined(SAL_UNX) |
32 | | #include <unistd.h> |
33 | | #endif /* SAL_UNX */ |
34 | | |
35 | | namespace { |
36 | | |
37 | | /** |
38 | | @internal |
39 | | */ |
40 | | struct rtl_arena_list_st |
41 | | { |
42 | | rtl_memory_lock_type m_lock; |
43 | | rtl_arena_type m_arena_head; |
44 | | }; |
45 | | |
46 | | } |
47 | | |
48 | | static rtl_arena_list_st g_arena_list; |
49 | | |
50 | | /** |
51 | | provided for arena_type allocations, and hash_table resizing. |
52 | | |
53 | | @internal |
54 | | */ |
55 | | static rtl_arena_type * gp_arena_arena = nullptr; |
56 | | |
57 | | /** |
58 | | Low level virtual memory (pseudo) arena |
59 | | (platform dependent implementation) |
60 | | |
61 | | @internal |
62 | | */ |
63 | | static rtl_arena_type * gp_machdep_arena = nullptr; |
64 | | |
65 | | rtl_arena_type * gp_default_arena = nullptr; |
66 | | |
67 | | namespace |
68 | | { |
69 | | |
70 | | void * rtl_machdep_alloc( |
71 | | rtl_arena_type * pArena, |
72 | | sal_Size * pSize |
73 | | ); |
74 | | |
75 | | void rtl_machdep_free( |
76 | | rtl_arena_type * pArena, |
77 | | void * pAddr, |
78 | | sal_Size nSize |
79 | | ); |
80 | | |
81 | | sal_Size rtl_machdep_pagesize(); |
82 | | |
83 | | void rtl_arena_segment_constructor(void * obj) |
84 | 0 | { |
85 | 0 | rtl_arena_segment_type * segment = static_cast<rtl_arena_segment_type*>(obj); |
86 | |
|
87 | 0 | QUEUE_START_NAMED(segment, s); |
88 | 0 | QUEUE_START_NAMED(segment, f); |
89 | 0 | } |
90 | | |
91 | | void rtl_arena_segment_destructor(void * obj) |
92 | 0 | { |
93 | 0 | rtl_arena_segment_type * segment = static_cast< rtl_arena_segment_type * >( |
94 | 0 | obj); |
95 | 0 | assert(QUEUE_STARTED_NAMED(segment, s)); |
96 | 0 | assert(QUEUE_STARTED_NAMED(segment, f)); |
97 | 0 | (void) segment; // avoid warnings |
98 | 0 | } |
99 | | |
100 | | /** |
101 | | @precond arena->m_lock acquired. |
102 | | */ |
103 | | bool rtl_arena_segment_populate(rtl_arena_type * arena) |
104 | 0 | { |
105 | 0 | rtl_arena_segment_type *span; |
106 | 0 | sal_Size size = rtl_machdep_pagesize(); |
107 | |
|
108 | 0 | span = static_cast< rtl_arena_segment_type * >( |
109 | 0 | rtl_machdep_alloc(gp_machdep_arena, &size)); |
110 | 0 | if (span) |
111 | 0 | { |
112 | 0 | rtl_arena_segment_type *first, *last, *head; |
113 | 0 | sal_Size count = size / sizeof(rtl_arena_segment_type); |
114 | | |
115 | | /* insert onto reserve span list */ |
116 | 0 | QUEUE_INSERT_TAIL_NAMED(&(arena->m_segment_reserve_span_head), span, s); |
117 | 0 | QUEUE_START_NAMED(span, f); |
118 | 0 | span->m_addr = reinterpret_cast<sal_uIntPtr>(span); |
119 | 0 | span->m_size = size; |
120 | 0 | span->m_type = RTL_ARENA_SEGMENT_TYPE_SPAN; |
121 | | |
122 | | /* insert onto reserve list */ |
123 | 0 | head = &(arena->m_segment_reserve_head); |
124 | 0 | for (first = span + 1, last = span + count; first < last; ++first) |
125 | 0 | { |
126 | 0 | QUEUE_INSERT_TAIL_NAMED(head, first, s); |
127 | 0 | QUEUE_START_NAMED(first, f); |
128 | 0 | first->m_addr = 0; |
129 | 0 | first->m_size = 0; |
130 | 0 | first->m_type = 0; |
131 | 0 | } |
132 | 0 | } |
133 | 0 | return (span != nullptr); |
134 | 0 | } |
135 | | |
136 | | /** |
137 | | @precond arena->m_lock acquired. |
138 | | @precond (*ppSegment == 0) |
139 | | */ |
140 | | void rtl_arena_segment_get( |
141 | | rtl_arena_type * arena, |
142 | | rtl_arena_segment_type ** ppSegment |
143 | | ) |
144 | 0 | { |
145 | 0 | rtl_arena_segment_type * head; |
146 | |
|
147 | 0 | assert(!*ppSegment); |
148 | |
|
149 | 0 | head = &(arena->m_segment_reserve_head); |
150 | 0 | if (head->m_snext != head || rtl_arena_segment_populate (arena)) |
151 | 0 | { |
152 | 0 | (*ppSegment) = head->m_snext; |
153 | 0 | QUEUE_REMOVE_NAMED(*ppSegment, s); |
154 | 0 | } |
155 | 0 | } |
156 | | |
157 | | /** |
158 | | @precond arena->m_lock acquired. |
159 | | @postcond (*ppSegment == 0) |
160 | | */ |
161 | | void rtl_arena_segment_put( |
162 | | rtl_arena_type * arena, |
163 | | rtl_arena_segment_type ** ppSegment |
164 | | ) |
165 | 0 | { |
166 | 0 | rtl_arena_segment_type * head; |
167 | |
|
168 | 0 | assert(QUEUE_STARTED_NAMED(*ppSegment, s)); |
169 | 0 | assert(QUEUE_STARTED_NAMED(*ppSegment, f)); |
170 | |
|
171 | 0 | (*ppSegment)->m_addr = 0; |
172 | 0 | (*ppSegment)->m_size = 0; |
173 | |
|
174 | 0 | assert((*ppSegment)->m_type != RTL_ARENA_SEGMENT_TYPE_HEAD); |
175 | 0 | (*ppSegment)->m_type = 0; |
176 | | |
177 | | /* keep as reserve */ |
178 | 0 | head = &(arena->m_segment_reserve_head); |
179 | 0 | QUEUE_INSERT_HEAD_NAMED(head, (*ppSegment), s); |
180 | | |
181 | | /* clear */ |
182 | 0 | (*ppSegment) = nullptr; |
183 | 0 | } |
184 | | |
185 | | /** |
186 | | @precond arena->m_lock acquired. |
187 | | */ |
188 | | void rtl_arena_freelist_insert ( |
189 | | rtl_arena_type * arena, |
190 | | rtl_arena_segment_type * segment |
191 | | ) |
192 | 0 | { |
193 | 0 | rtl_arena_segment_type * head; |
194 | 0 | const auto bit = highbit(segment->m_size); |
195 | 0 | assert(bit > 0); |
196 | 0 | head = &(arena->m_freelist_head[bit - 1]); |
197 | 0 | QUEUE_INSERT_TAIL_NAMED(head, segment, f); |
198 | |
|
199 | 0 | arena->m_freelist_bitmap |= head->m_size; |
200 | 0 | } |
201 | | |
202 | | /** |
203 | | @precond arena->m_lock acquired. |
204 | | */ |
205 | | void rtl_arena_freelist_remove( |
206 | | rtl_arena_type * arena, |
207 | | rtl_arena_segment_type * segment |
208 | | ) |
209 | 0 | { |
210 | 0 | if (segment->m_fnext->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD && |
211 | 0 | segment->m_fprev->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD) |
212 | 0 | { |
213 | 0 | rtl_arena_segment_type * head; |
214 | |
|
215 | 0 | head = segment->m_fprev; |
216 | 0 | assert(arena->m_freelist_bitmap & head->m_size); |
217 | 0 | arena->m_freelist_bitmap ^= head->m_size; |
218 | 0 | } |
219 | 0 | QUEUE_REMOVE_NAMED(segment, f); |
220 | 0 | } |
221 | | |
222 | | #define RTL_ARENA_HASH_INDEX_IMPL(a, s, q, m) \ |
223 | 0 | ((((a) + ((a) >> (s)) + ((a) >> ((s) << 1))) >> (q)) & (m)) |
224 | | |
225 | | #define RTL_ARENA_HASH_INDEX(arena, addr) \ |
226 | 0 | RTL_ARENA_HASH_INDEX_IMPL((addr), (arena)->m_hash_shift, (arena)->m_quantum_shift, ((arena)->m_hash_size - 1)) |
227 | | |
228 | | /** |
229 | | @precond arena->m_lock released. |
230 | | */ |
231 | | void rtl_arena_hash_rescale( |
232 | | rtl_arena_type * arena, |
233 | | sal_Size new_size |
234 | | ) |
235 | 0 | { |
236 | 0 | assert(new_size != 0); |
237 | |
|
238 | 0 | rtl_arena_segment_type ** new_table; |
239 | 0 | sal_Size new_bytes; |
240 | |
|
241 | 0 | new_bytes = new_size * sizeof(rtl_arena_segment_type*); |
242 | 0 | new_table = static_cast<rtl_arena_segment_type **>(rtl_arena_alloc (gp_arena_arena, &new_bytes)); |
243 | |
|
244 | 0 | if (new_table) |
245 | 0 | { |
246 | 0 | rtl_arena_segment_type ** old_table; |
247 | 0 | sal_Size old_size, i; |
248 | |
|
249 | 0 | memset (new_table, 0, new_bytes); |
250 | |
|
251 | 0 | RTL_MEMORY_LOCK_ACQUIRE(&(arena->m_lock)); |
252 | |
|
253 | 0 | old_table = arena->m_hash_table; |
254 | 0 | old_size = arena->m_hash_size; |
255 | |
|
256 | 0 | arena->m_hash_table = new_table; |
257 | 0 | arena->m_hash_size = new_size; |
258 | 0 | arena->m_hash_shift = highbit(arena->m_hash_size) - 1; |
259 | |
|
260 | 0 | for (i = 0; i < old_size; i++) |
261 | 0 | { |
262 | 0 | rtl_arena_segment_type * curr = old_table[i]; |
263 | 0 | while (curr) |
264 | 0 | { |
265 | 0 | rtl_arena_segment_type * next = curr->m_fnext; |
266 | 0 | rtl_arena_segment_type ** head; |
267 | |
|
268 | 0 | head = &(arena->m_hash_table[RTL_ARENA_HASH_INDEX(arena, curr->m_addr)]); |
269 | 0 | curr->m_fnext = (*head); |
270 | 0 | (*head) = curr; |
271 | |
|
272 | 0 | curr = next; |
273 | 0 | } |
274 | 0 | old_table[i] = nullptr; |
275 | 0 | } |
276 | |
|
277 | 0 | RTL_MEMORY_LOCK_RELEASE(&(arena->m_lock)); |
278 | |
|
279 | 0 | if (old_table != arena->m_hash_table_0) |
280 | 0 | { |
281 | 0 | sal_Size old_bytes = old_size * sizeof(rtl_arena_segment_type*); |
282 | 0 | rtl_arena_free (gp_arena_arena, old_table, old_bytes); |
283 | 0 | } |
284 | 0 | } |
285 | 0 | } |
286 | | |
287 | | /** |
288 | | Insert arena hash, and update stats. |
289 | | */ |
290 | | void rtl_arena_hash_insert( |
291 | | rtl_arena_type * arena, |
292 | | rtl_arena_segment_type * segment |
293 | | ) |
294 | 0 | { |
295 | 0 | rtl_arena_segment_type ** ppSegment; |
296 | |
|
297 | 0 | ppSegment = &(arena->m_hash_table[RTL_ARENA_HASH_INDEX(arena, segment->m_addr)]); |
298 | |
|
299 | 0 | segment->m_fnext = (*ppSegment); |
300 | 0 | (*ppSegment) = segment; |
301 | |
|
302 | 0 | arena->m_stats.m_alloc += 1; |
303 | 0 | arena->m_stats.m_mem_alloc += segment->m_size; |
304 | 0 | } |
305 | | |
306 | | /** |
307 | | Remove arena hash, and update stats. |
308 | | */ |
309 | | rtl_arena_segment_type * rtl_arena_hash_remove( |
310 | | rtl_arena_type * arena, |
311 | | sal_uIntPtr addr, |
312 | | sal_Size size |
313 | | ) |
314 | 0 | { |
315 | 0 | rtl_arena_segment_type *segment, **segpp; |
316 | 0 | sal_Size lookups = 0; |
317 | |
|
318 | 0 | segpp = &(arena->m_hash_table[RTL_ARENA_HASH_INDEX(arena, addr)]); |
319 | 0 | while ((segment = *segpp)) |
320 | 0 | { |
321 | 0 | if (segment->m_addr == addr) |
322 | 0 | { |
323 | 0 | *segpp = segment->m_fnext; |
324 | 0 | segment->m_fnext = segment->m_fprev = segment; |
325 | 0 | break; |
326 | 0 | } |
327 | | |
328 | | /* update lookup miss stats */ |
329 | 0 | lookups += 1; |
330 | 0 | segpp = &(segment->m_fnext); |
331 | 0 | } |
332 | |
|
333 | 0 | assert(segment); // bad free |
334 | 0 | if (segment) |
335 | 0 | { |
336 | 0 | assert(segment->m_size == size); |
337 | 0 | (void) size; // avoid warnings |
338 | |
|
339 | 0 | arena->m_stats.m_free += 1; |
340 | 0 | arena->m_stats.m_mem_alloc -= segment->m_size; |
341 | |
|
342 | 0 | if (lookups > 1) |
343 | 0 | { |
344 | 0 | sal_Size nseg = static_cast<sal_Size>(arena->m_stats.m_alloc - arena->m_stats.m_free); |
345 | 0 | if (nseg > 4 * arena->m_hash_size) |
346 | 0 | { |
347 | 0 | if (!(arena->m_flags & RTL_ARENA_FLAG_RESCALE)) |
348 | 0 | { |
349 | 0 | sal_Size ave = nseg >> arena->m_hash_shift; |
350 | 0 | assert(ave != 0); |
351 | 0 | sal_Size new_size = arena->m_hash_size << (highbit(ave) - 1); |
352 | |
|
353 | 0 | arena->m_flags |= RTL_ARENA_FLAG_RESCALE; |
354 | 0 | RTL_MEMORY_LOCK_RELEASE(&(arena->m_lock)); |
355 | 0 | rtl_arena_hash_rescale (arena, new_size); |
356 | 0 | RTL_MEMORY_LOCK_ACQUIRE(&(arena->m_lock)); |
357 | 0 | arena->m_flags &= ~RTL_ARENA_FLAG_RESCALE; |
358 | 0 | } |
359 | 0 | } |
360 | 0 | } |
361 | 0 | } |
362 | |
|
363 | 0 | return segment; |
364 | 0 | } |
365 | | |
366 | | /** |
367 | | allocate (and remove) segment from freelist |
368 | | |
369 | | @precond arena->m_lock acquired |
370 | | @precond (*ppSegment == 0) |
371 | | */ |
372 | | bool rtl_arena_segment_alloc( |
373 | | rtl_arena_type * arena, |
374 | | sal_Size size, |
375 | | rtl_arena_segment_type ** ppSegment |
376 | | ) |
377 | 0 | { |
378 | 0 | int index = 0; |
379 | |
|
380 | 0 | assert(!*ppSegment); |
381 | 0 | if (!RTL_MEMORY_ISP2(size)) |
382 | 0 | { |
383 | 0 | unsigned int msb = highbit(size); |
384 | 0 | if (RTL_ARENA_FREELIST_SIZE == msb) |
385 | 0 | { |
386 | | /* highest possible freelist: fall back to first fit */ |
387 | 0 | rtl_arena_segment_type *head, *segment; |
388 | |
|
389 | 0 | head = &(arena->m_freelist_head[msb - 1]); |
390 | 0 | for (segment = head->m_fnext; segment != head; segment = segment->m_fnext) |
391 | 0 | { |
392 | 0 | if (segment->m_size >= size) |
393 | 0 | { |
394 | | /* allocate first fit segment */ |
395 | 0 | (*ppSegment) = segment; |
396 | 0 | break; |
397 | 0 | } |
398 | 0 | } |
399 | 0 | goto dequeue_and_leave; |
400 | 0 | } |
401 | | |
402 | | /* roundup to next power of 2 */ |
403 | 0 | size = ((sal_Size(1)) << msb); |
404 | 0 | } |
405 | | |
406 | 0 | index = lowbit(RTL_MEMORY_P2ALIGN(arena->m_freelist_bitmap, size)); |
407 | 0 | if (index > 0) |
408 | 0 | { |
409 | | /* instant fit: allocate first free segment */ |
410 | 0 | rtl_arena_segment_type *head; |
411 | |
|
412 | 0 | head = &(arena->m_freelist_head[index - 1]); |
413 | 0 | (*ppSegment) = head->m_fnext; |
414 | 0 | assert((*ppSegment) != head); |
415 | 0 | } |
416 | |
|
417 | 0 | dequeue_and_leave: |
418 | 0 | if (*ppSegment) |
419 | 0 | { |
420 | | /* remove from freelist */ |
421 | 0 | rtl_arena_freelist_remove (arena, (*ppSegment)); |
422 | 0 | } |
423 | 0 | return (*ppSegment != nullptr); |
424 | 0 | } |
425 | | |
426 | | /** |
427 | | import new (span) segment from source arena |
428 | | |
429 | | @precond arena->m_lock acquired |
430 | | @precond (*ppSegment == 0) |
431 | | */ |
432 | | bool rtl_arena_segment_create( |
433 | | rtl_arena_type * arena, |
434 | | sal_Size size, |
435 | | rtl_arena_segment_type ** ppSegment |
436 | | ) |
437 | 0 | { |
438 | 0 | assert(!*ppSegment); |
439 | 0 | if (arena->m_source_alloc) |
440 | 0 | { |
441 | 0 | rtl_arena_segment_get (arena, ppSegment); |
442 | 0 | if (*ppSegment) |
443 | 0 | { |
444 | 0 | rtl_arena_segment_type * span = nullptr; |
445 | 0 | rtl_arena_segment_get (arena, &span); |
446 | 0 | if (span) |
447 | 0 | { |
448 | | /* import new span from source arena */ |
449 | 0 | RTL_MEMORY_LOCK_RELEASE(&(arena->m_lock)); |
450 | |
|
451 | 0 | span->m_size = size; |
452 | 0 | span->m_addr = reinterpret_cast<sal_uIntPtr>( |
453 | 0 | (arena->m_source_alloc)( |
454 | 0 | arena->m_source_arena, &(span->m_size))); |
455 | |
|
456 | 0 | RTL_MEMORY_LOCK_ACQUIRE(&(arena->m_lock)); |
457 | 0 | if (span->m_addr != 0) |
458 | 0 | { |
459 | | /* insert onto segment list, update stats */ |
460 | 0 | span->m_type = RTL_ARENA_SEGMENT_TYPE_SPAN; |
461 | 0 | QUEUE_INSERT_HEAD_NAMED(&(arena->m_segment_head), span, s); |
462 | 0 | arena->m_stats.m_mem_total += span->m_size; |
463 | |
|
464 | 0 | (*ppSegment)->m_addr = span->m_addr; |
465 | 0 | (*ppSegment)->m_size = span->m_size; |
466 | 0 | (*ppSegment)->m_type = RTL_ARENA_SEGMENT_TYPE_FREE; |
467 | 0 | QUEUE_INSERT_HEAD_NAMED(span, (*ppSegment), s); |
468 | | |
469 | | /* report success */ |
470 | 0 | return true; |
471 | 0 | } |
472 | 0 | rtl_arena_segment_put (arena, &span); |
473 | 0 | } |
474 | 0 | rtl_arena_segment_put (arena, ppSegment); |
475 | 0 | } |
476 | 0 | } |
477 | 0 | return false; // failure |
478 | 0 | } |
479 | | |
480 | | /** |
481 | | mark as free and join with adjacent free segment(s) |
482 | | |
483 | | @precond arena->m_lock acquired |
484 | | @precond segment marked 'used' |
485 | | */ |
486 | | void rtl_arena_segment_coalesce( |
487 | | rtl_arena_type * arena, |
488 | | rtl_arena_segment_type * segment |
489 | | ) |
490 | 0 | { |
491 | 0 | rtl_arena_segment_type *next, *prev; |
492 | | |
493 | | /* mark segment free */ |
494 | 0 | assert(segment->m_type == RTL_ARENA_SEGMENT_TYPE_USED); |
495 | 0 | segment->m_type = RTL_ARENA_SEGMENT_TYPE_FREE; |
496 | | |
497 | | /* try to merge w/ next segment */ |
498 | 0 | next = segment->m_snext; |
499 | 0 | if (next->m_type == RTL_ARENA_SEGMENT_TYPE_FREE) |
500 | 0 | { |
501 | 0 | assert(segment->m_addr + segment->m_size == next->m_addr); |
502 | 0 | segment->m_size += next->m_size; |
503 | | |
504 | | /* remove from freelist */ |
505 | 0 | rtl_arena_freelist_remove (arena, next); |
506 | | |
507 | | /* remove from segment list */ |
508 | 0 | QUEUE_REMOVE_NAMED(next, s); |
509 | | |
510 | | /* release segment descriptor */ |
511 | 0 | rtl_arena_segment_put (arena, &next); |
512 | 0 | } |
513 | | |
514 | | /* try to merge w/ prev segment */ |
515 | 0 | prev = segment->m_sprev; |
516 | 0 | if (prev->m_type == RTL_ARENA_SEGMENT_TYPE_FREE) |
517 | 0 | { |
518 | 0 | assert(prev->m_addr + prev->m_size == segment->m_addr); |
519 | 0 | segment->m_addr = prev->m_addr; |
520 | 0 | segment->m_size += prev->m_size; |
521 | | |
522 | | /* remove from freelist */ |
523 | 0 | rtl_arena_freelist_remove (arena, prev); |
524 | | |
525 | | /* remove from segment list */ |
526 | 0 | QUEUE_REMOVE_NAMED(prev, s); |
527 | | |
528 | | /* release segment descriptor */ |
529 | 0 | rtl_arena_segment_put (arena, &prev); |
530 | 0 | } |
531 | 0 | } |
532 | | |
533 | | void rtl_arena_constructor(void * obj) |
534 | 0 | { |
535 | 0 | rtl_arena_type * arena = static_cast<rtl_arena_type*>(obj); |
536 | 0 | rtl_arena_segment_type * head; |
537 | 0 | size_t i; |
538 | |
|
539 | 0 | memset (arena, 0, sizeof(rtl_arena_type)); |
540 | |
|
541 | 0 | QUEUE_START_NAMED(arena, arena_); |
542 | |
|
543 | 0 | RTL_MEMORY_LOCK_INIT(&(arena->m_lock)); |
544 | |
|
545 | 0 | head = &(arena->m_segment_reserve_span_head); |
546 | 0 | rtl_arena_segment_constructor (head); |
547 | 0 | head->m_type = RTL_ARENA_SEGMENT_TYPE_HEAD; |
548 | |
|
549 | 0 | head = &(arena->m_segment_reserve_head); |
550 | 0 | rtl_arena_segment_constructor (head); |
551 | 0 | head->m_type = RTL_ARENA_SEGMENT_TYPE_HEAD; |
552 | |
|
553 | 0 | head = &(arena->m_segment_head); |
554 | 0 | rtl_arena_segment_constructor (head); |
555 | 0 | head->m_type = RTL_ARENA_SEGMENT_TYPE_HEAD; |
556 | |
|
557 | 0 | for (i = 0; i < RTL_ARENA_FREELIST_SIZE; i++) |
558 | 0 | { |
559 | 0 | head = &(arena->m_freelist_head[i]); |
560 | 0 | rtl_arena_segment_constructor (head); |
561 | |
|
562 | 0 | head->m_size = ((sal_Size(1)) << i); |
563 | 0 | head->m_type = RTL_ARENA_SEGMENT_TYPE_HEAD; |
564 | 0 | } |
565 | |
|
566 | 0 | arena->m_hash_table = arena->m_hash_table_0; |
567 | 0 | arena->m_hash_size = RTL_ARENA_HASH_SIZE; |
568 | 0 | arena->m_hash_shift = highbit(arena->m_hash_size) - 1; |
569 | 0 | } |
570 | | |
571 | | void rtl_arena_destructor(void * obj) |
572 | 0 | { |
573 | 0 | rtl_arena_type * arena = static_cast<rtl_arena_type*>(obj); |
574 | 0 | rtl_arena_segment_type * head; |
575 | 0 | size_t i; |
576 | |
|
577 | 0 | assert(QUEUE_STARTED_NAMED(arena, arena_)); |
578 | |
|
579 | 0 | RTL_MEMORY_LOCK_DESTROY(&(arena->m_lock)); |
580 | |
|
581 | 0 | head = &(arena->m_segment_reserve_span_head); |
582 | 0 | assert(head->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD); |
583 | 0 | rtl_arena_segment_destructor (head); |
584 | |
|
585 | 0 | head = &(arena->m_segment_reserve_head); |
586 | 0 | assert(head->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD); |
587 | 0 | rtl_arena_segment_destructor (head); |
588 | |
|
589 | 0 | head = &(arena->m_segment_head); |
590 | 0 | assert(head->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD); |
591 | 0 | rtl_arena_segment_destructor (head); |
592 | |
|
593 | 0 | for (i = 0; i < RTL_ARENA_FREELIST_SIZE; i++) |
594 | 0 | { |
595 | 0 | head = &(arena->m_freelist_head[i]); |
596 | |
|
597 | 0 | assert(head->m_size == ((sal_Size(1)) << i)); |
598 | 0 | assert(head->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD); |
599 | |
|
600 | 0 | rtl_arena_segment_destructor (head); |
601 | 0 | } |
602 | |
|
603 | 0 | assert(arena->m_hash_table == arena->m_hash_table_0); |
604 | 0 | assert(arena->m_hash_size == RTL_ARENA_HASH_SIZE); |
605 | 0 | assert(arena->m_hash_shift == highbit(arena->m_hash_size) - 1); |
606 | 0 | } |
607 | | |
608 | | rtl_arena_type * rtl_arena_activate( |
609 | | rtl_arena_type * arena, |
610 | | const char * name, |
611 | | sal_Size quantum, |
612 | | rtl_arena_type * source_arena, |
613 | | void * (SAL_CALL * source_alloc)(rtl_arena_type *, sal_Size *), |
614 | | void (SAL_CALL * source_free) (rtl_arena_type *, void *, sal_Size) |
615 | | ) |
616 | 0 | { |
617 | 0 | assert(arena); |
618 | 0 | if (arena) |
619 | 0 | { |
620 | 0 | (void) snprintf (arena->m_name, sizeof(arena->m_name), "%s", name); |
621 | |
|
622 | 0 | if (!RTL_MEMORY_ISP2(quantum)) |
623 | 0 | { |
624 | | /* roundup to next power of 2 */ |
625 | 0 | quantum = ((sal_Size(1)) << highbit(quantum)); |
626 | 0 | } |
627 | |
|
628 | 0 | arena->m_quantum = quantum; |
629 | 0 | arena->m_quantum_shift = highbit(arena->m_quantum) - 1; |
630 | |
|
631 | 0 | arena->m_source_arena = source_arena; |
632 | 0 | arena->m_source_alloc = source_alloc; |
633 | 0 | arena->m_source_free = source_free; |
634 | | |
635 | | /* insert into arena list */ |
636 | 0 | RTL_MEMORY_LOCK_ACQUIRE(&(g_arena_list.m_lock)); |
637 | 0 | QUEUE_INSERT_TAIL_NAMED(&(g_arena_list.m_arena_head), arena, arena_); |
638 | 0 | RTL_MEMORY_LOCK_RELEASE(&(g_arena_list.m_lock)); |
639 | 0 | } |
640 | 0 | return arena; |
641 | 0 | } |
642 | | |
643 | | void rtl_arena_deactivate(rtl_arena_type * arena) |
644 | 0 | { |
645 | 0 | rtl_arena_segment_type * head, * segment; |
646 | | |
647 | | /* remove from arena list */ |
648 | 0 | RTL_MEMORY_LOCK_ACQUIRE(&(g_arena_list.m_lock)); |
649 | 0 | QUEUE_REMOVE_NAMED(arena, arena_); |
650 | 0 | RTL_MEMORY_LOCK_RELEASE(&(g_arena_list.m_lock)); |
651 | | |
652 | | /* check for leaked segments */ |
653 | 0 | if (arena->m_stats.m_alloc > arena->m_stats.m_free) |
654 | 0 | { |
655 | 0 | sal_Size i, n; |
656 | | |
657 | | /* cleanup still used segment(s) */ |
658 | 0 | for (i = 0, n = arena->m_hash_size; i < n; i++) |
659 | 0 | { |
660 | 0 | while ((segment = arena->m_hash_table[i])) |
661 | 0 | { |
662 | | /* pop from hash table */ |
663 | 0 | arena->m_hash_table[i] = segment->m_fnext; |
664 | 0 | segment->m_fnext = segment->m_fprev = segment; |
665 | | |
666 | | /* coalesce w/ adjacent free segment(s) */ |
667 | 0 | rtl_arena_segment_coalesce (arena, segment); |
668 | | |
669 | | /* insert onto freelist */ |
670 | 0 | rtl_arena_freelist_insert (arena, segment); |
671 | 0 | } |
672 | 0 | } |
673 | 0 | } |
674 | | |
675 | | /* cleanup hash table */ |
676 | 0 | if (arena->m_hash_table != arena->m_hash_table_0) |
677 | 0 | { |
678 | 0 | rtl_arena_free( |
679 | 0 | gp_arena_arena, |
680 | 0 | arena->m_hash_table, |
681 | 0 | arena->m_hash_size * sizeof(rtl_arena_segment_type*)); |
682 | |
|
683 | 0 | arena->m_hash_table = arena->m_hash_table_0; |
684 | 0 | arena->m_hash_size = RTL_ARENA_HASH_SIZE; |
685 | 0 | arena->m_hash_shift = highbit(arena->m_hash_size) - 1; |
686 | 0 | } |
687 | | |
688 | | /* cleanup segment list */ |
689 | 0 | head = &(arena->m_segment_head); |
690 | 0 | for (segment = head->m_snext; segment != head; segment = head->m_snext) |
691 | 0 | { |
692 | 0 | if (segment->m_type == RTL_ARENA_SEGMENT_TYPE_FREE) |
693 | 0 | { |
694 | | /* remove from freelist */ |
695 | 0 | rtl_arena_freelist_remove (arena, segment); |
696 | 0 | } |
697 | 0 | else |
698 | 0 | { |
699 | | /* can have only free and span segments here */ |
700 | 0 | assert(segment->m_type == RTL_ARENA_SEGMENT_TYPE_SPAN); |
701 | 0 | } |
702 | | |
703 | | /* remove from segment list */ |
704 | 0 | QUEUE_REMOVE_NAMED(segment, s); |
705 | | |
706 | | /* release segment descriptor */ |
707 | 0 | rtl_arena_segment_put (arena, &segment); |
708 | 0 | } |
709 | | |
710 | | /* cleanup segment reserve list */ |
711 | 0 | head = &(arena->m_segment_reserve_head); |
712 | 0 | for (segment = head->m_snext; segment != head; segment = head->m_snext) |
713 | 0 | { |
714 | | /* remove from segment list */ |
715 | 0 | QUEUE_REMOVE_NAMED(segment, s); |
716 | 0 | } |
717 | | |
718 | | /* cleanup segment reserve span(s) */ |
719 | 0 | head = &(arena->m_segment_reserve_span_head); |
720 | 0 | for (segment = head->m_snext; segment != head; segment = head->m_snext) |
721 | 0 | { |
722 | | /* can have only span segments here */ |
723 | 0 | assert(segment->m_type == RTL_ARENA_SEGMENT_TYPE_SPAN); |
724 | | |
725 | | /* remove from segment list */ |
726 | 0 | QUEUE_REMOVE_NAMED(segment, s); |
727 | | |
728 | | /* return span to g_machdep_arena */ |
729 | 0 | rtl_machdep_free (gp_machdep_arena, reinterpret_cast<void*>(segment->m_addr), segment->m_size); |
730 | 0 | } |
731 | 0 | } |
732 | | |
733 | | } // namespace |
734 | | |
735 | | rtl_arena_type * SAL_CALL rtl_arena_create( |
736 | | const char * name, |
737 | | sal_Size quantum, |
738 | | sal_Size, |
739 | | rtl_arena_type * source_arena, |
740 | | void * (SAL_CALL * source_alloc)(rtl_arena_type *, sal_Size *), |
741 | | void (SAL_CALL * source_free) (rtl_arena_type *, void *, sal_Size), |
742 | | SAL_UNUSED_PARAMETER int |
743 | | ) noexcept |
744 | 0 | { |
745 | 0 | rtl_arena_type * result = nullptr; |
746 | 0 | sal_Size size = sizeof(rtl_arena_type); |
747 | |
|
748 | 0 | try_alloc: |
749 | 0 | result = static_cast<rtl_arena_type*>(rtl_arena_alloc (gp_arena_arena, &size)); |
750 | 0 | if (result) |
751 | 0 | { |
752 | 0 | rtl_arena_type * arena = result; |
753 | 0 | rtl_arena_constructor (arena); |
754 | |
|
755 | 0 | if (!source_arena) |
756 | 0 | { |
757 | 0 | assert(gp_default_arena); |
758 | 0 | source_arena = gp_default_arena; |
759 | 0 | } |
760 | |
|
761 | 0 | result = rtl_arena_activate ( |
762 | 0 | arena, |
763 | 0 | name, |
764 | 0 | quantum, |
765 | 0 | source_arena, |
766 | 0 | source_alloc, |
767 | 0 | source_free |
768 | 0 | ); |
769 | |
|
770 | 0 | if (!result) |
771 | 0 | { |
772 | 0 | rtl_arena_deactivate (arena); |
773 | 0 | rtl_arena_destructor (arena); |
774 | 0 | rtl_arena_free (gp_arena_arena, arena, size); |
775 | 0 | } |
776 | 0 | } |
777 | 0 | else if (!gp_arena_arena) |
778 | 0 | { |
779 | 0 | ensureArenaSingleton(); |
780 | 0 | if (gp_arena_arena) |
781 | 0 | { |
782 | | /* try again */ |
783 | 0 | goto try_alloc; |
784 | 0 | } |
785 | 0 | } |
786 | 0 | return result; |
787 | 0 | } |
788 | | |
789 | | void SAL_CALL rtl_arena_destroy(rtl_arena_type * arena) noexcept |
790 | 0 | { |
791 | 0 | if (arena) |
792 | 0 | { |
793 | 0 | rtl_arena_deactivate (arena); |
794 | 0 | rtl_arena_destructor (arena); |
795 | 0 | rtl_arena_free (gp_arena_arena, arena, sizeof(rtl_arena_type)); |
796 | 0 | } |
797 | 0 | } |
798 | | |
799 | | void * SAL_CALL rtl_arena_alloc( |
800 | | rtl_arena_type * arena, |
801 | | sal_Size * pSize |
802 | | ) noexcept |
803 | 0 | { |
804 | 0 | void * addr = nullptr; |
805 | |
|
806 | 0 | if (arena && pSize) |
807 | 0 | { |
808 | 0 | sal_Size size; |
809 | |
|
810 | 0 | size = RTL_MEMORY_ALIGN(*pSize, arena->m_quantum); |
811 | 0 | if (size > 0) |
812 | 0 | { |
813 | | /* allocate from segment list */ |
814 | 0 | rtl_arena_segment_type *segment = nullptr; |
815 | |
|
816 | 0 | RTL_MEMORY_LOCK_ACQUIRE(&(arena->m_lock)); |
817 | 0 | if (rtl_arena_segment_alloc (arena, size, &segment) || |
818 | 0 | rtl_arena_segment_create(arena, size, &segment) ) |
819 | 0 | { |
820 | | /* shrink to fit */ |
821 | 0 | sal_Size oversize; |
822 | | |
823 | | /* mark segment used */ |
824 | 0 | assert(segment->m_type == RTL_ARENA_SEGMENT_TYPE_FREE); |
825 | 0 | segment->m_type = RTL_ARENA_SEGMENT_TYPE_USED; |
826 | | |
827 | | /* resize */ |
828 | 0 | assert(segment->m_size >= size); |
829 | 0 | oversize = segment->m_size - size; |
830 | 0 | if (oversize >= arena->m_quantum) |
831 | 0 | { |
832 | 0 | rtl_arena_segment_type * remainder = nullptr; |
833 | 0 | rtl_arena_segment_get (arena, &remainder); |
834 | 0 | if (remainder) |
835 | 0 | { |
836 | 0 | segment->m_size = size; |
837 | |
|
838 | 0 | remainder->m_addr = segment->m_addr + segment->m_size; |
839 | 0 | remainder->m_size = oversize; |
840 | 0 | remainder->m_type = RTL_ARENA_SEGMENT_TYPE_FREE; |
841 | 0 | QUEUE_INSERT_HEAD_NAMED(segment, remainder, s); |
842 | |
|
843 | 0 | rtl_arena_freelist_insert (arena, remainder); |
844 | 0 | } |
845 | 0 | } |
846 | |
|
847 | 0 | rtl_arena_hash_insert (arena, segment); |
848 | |
|
849 | 0 | (*pSize) = segment->m_size; |
850 | 0 | addr = reinterpret_cast<void*>(segment->m_addr); |
851 | 0 | } |
852 | 0 | RTL_MEMORY_LOCK_RELEASE(&(arena->m_lock)); |
853 | 0 | } |
854 | 0 | } |
855 | 0 | return addr; |
856 | 0 | } |
857 | | |
858 | | void SAL_CALL rtl_arena_free ( |
859 | | rtl_arena_type * arena, |
860 | | void * addr, |
861 | | sal_Size size |
862 | | ) noexcept |
863 | 0 | { |
864 | 0 | if (arena) |
865 | 0 | { |
866 | 0 | size = RTL_MEMORY_ALIGN(size, arena->m_quantum); |
867 | 0 | if (size > 0) |
868 | 0 | { |
869 | | /* free to segment list */ |
870 | 0 | rtl_arena_segment_type * segment; |
871 | |
|
872 | 0 | RTL_MEMORY_LOCK_ACQUIRE(&(arena->m_lock)); |
873 | |
|
874 | 0 | segment = rtl_arena_hash_remove (arena, reinterpret_cast<sal_uIntPtr>(addr), size); |
875 | 0 | if (segment) |
876 | 0 | { |
877 | 0 | rtl_arena_segment_type *next, *prev; |
878 | | |
879 | | /* coalesce w/ adjacent free segment(s) */ |
880 | 0 | rtl_arena_segment_coalesce (arena, segment); |
881 | | |
882 | | /* determine (new) next and prev segment */ |
883 | 0 | next = segment->m_snext; |
884 | 0 | prev = segment->m_sprev; |
885 | | |
886 | | /* entire span free when prev is a span, and next is either a span or a list head */ |
887 | 0 | if (prev->m_type == RTL_ARENA_SEGMENT_TYPE_SPAN && |
888 | 0 | ((next->m_type == RTL_ARENA_SEGMENT_TYPE_SPAN) || |
889 | 0 | (next->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD))) |
890 | 0 | { |
891 | 0 | assert( |
892 | 0 | prev->m_addr == segment->m_addr |
893 | 0 | && prev->m_size == segment->m_size); |
894 | |
|
895 | 0 | if (arena->m_source_free) |
896 | 0 | { |
897 | 0 | addr = reinterpret_cast<void*>(prev->m_addr); |
898 | 0 | size = prev->m_size; |
899 | | |
900 | | /* remove from segment list */ |
901 | 0 | QUEUE_REMOVE_NAMED(segment, s); |
902 | | |
903 | | /* release segment descriptor */ |
904 | 0 | rtl_arena_segment_put (arena, &segment); |
905 | | |
906 | | /* remove from segment list */ |
907 | 0 | QUEUE_REMOVE_NAMED(prev, s); |
908 | | |
909 | | /* release (span) segment descriptor */ |
910 | 0 | rtl_arena_segment_put (arena, &prev); |
911 | | |
912 | | /* update stats, return span to source arena */ |
913 | 0 | arena->m_stats.m_mem_total -= size; |
914 | 0 | RTL_MEMORY_LOCK_RELEASE(&(arena->m_lock)); |
915 | |
|
916 | 0 | (arena->m_source_free)(arena->m_source_arena, addr, size); |
917 | 0 | return; |
918 | 0 | } |
919 | 0 | } |
920 | | |
921 | | /* insert onto freelist */ |
922 | 0 | rtl_arena_freelist_insert (arena, segment); |
923 | 0 | } |
924 | | |
925 | 0 | RTL_MEMORY_LOCK_RELEASE(&(arena->m_lock)); |
926 | 0 | } |
927 | 0 | } |
928 | 0 | } |
929 | | |
930 | | void rtl_arena_foreach (rtl_arena_type *arena, ArenaForeachFn foreachFn) |
931 | 0 | { |
932 | | /* used segments */ |
933 | 0 | for (int i = 0, n = arena->m_hash_size; i < n; i++) |
934 | 0 | { |
935 | 0 | for (rtl_arena_segment_type *segment = arena->m_hash_table[i]; |
936 | 0 | segment != nullptr; segment = segment->m_fnext) |
937 | 0 | { |
938 | 0 | foreachFn(reinterpret_cast<void *>(segment->m_addr), |
939 | 0 | segment->m_size); |
940 | 0 | } |
941 | 0 | } |
942 | 0 | } |
943 | | |
944 | | #if defined(SAL_UNX) |
945 | | #include <sys/mman.h> |
946 | | #elif defined(_WIN32) |
947 | | #define MAP_FAILED nullptr |
948 | | #endif /* SAL_UNX || _WIN32 */ |
949 | | |
950 | | namespace |
951 | | { |
952 | | |
953 | | void * rtl_machdep_alloc( |
954 | | rtl_arena_type * pArena, |
955 | | sal_Size * pSize |
956 | | ) |
957 | 0 | { |
958 | 0 | void * addr; |
959 | 0 | sal_Size size = *pSize; |
960 | |
|
961 | 0 | assert(pArena == gp_machdep_arena); |
962 | |
|
963 | | #if defined(__sun) && defined(SPARC) |
964 | | /* see @ mmap(2) man pages */ |
965 | | size += (pArena->m_quantum + pArena->m_quantum); /* "red-zone" pages */ |
966 | | if (size > (4 << 20)) |
967 | | size = RTL_MEMORY_P2ROUNDUP(size, (4 << 20)); |
968 | | else if (size > (512 << 10)) |
969 | | size = RTL_MEMORY_P2ROUNDUP(size, (512 << 10)); |
970 | | else |
971 | | size = RTL_MEMORY_P2ROUNDUP(size, (64 << 10)); |
972 | | size -= (pArena->m_quantum + pArena->m_quantum); /* "red-zone" pages */ |
973 | | #else |
974 | | /* default allocation granularity */ |
975 | 0 | if (pArena->m_quantum < (64 << 10)) |
976 | 0 | { |
977 | 0 | size = RTL_MEMORY_P2ROUNDUP(size, (64 << 10)); |
978 | 0 | } |
979 | 0 | else |
980 | 0 | { |
981 | 0 | size = RTL_MEMORY_P2ROUNDUP(size, pArena->m_quantum); |
982 | 0 | } |
983 | 0 | #endif |
984 | |
|
985 | 0 | #if defined(SAL_UNX) |
986 | 0 | addr = mmap (nullptr, static_cast<size_t>(size), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); |
987 | | #elif defined(_WIN32) |
988 | | addr = VirtualAlloc (nullptr, static_cast<SIZE_T>(size), MEM_COMMIT, PAGE_READWRITE); |
989 | | #endif /* (SAL_UNX || _WIN32) */ |
990 | |
|
991 | 0 | if (addr != MAP_FAILED) |
992 | 0 | { |
993 | 0 | pArena->m_stats.m_alloc += 1; |
994 | 0 | pArena->m_stats.m_mem_total += size; |
995 | 0 | pArena->m_stats.m_mem_alloc += size; |
996 | |
|
997 | 0 | (*pSize) = size; |
998 | 0 | return addr; |
999 | 0 | } |
1000 | 0 | return nullptr; |
1001 | 0 | } |
1002 | | |
1003 | | void rtl_machdep_free( |
1004 | | rtl_arena_type * pArena, |
1005 | | void * pAddr, |
1006 | | sal_Size nSize |
1007 | | ) |
1008 | 0 | { |
1009 | 0 | assert(pArena == gp_machdep_arena); |
1010 | |
|
1011 | 0 | pArena->m_stats.m_free += 1; |
1012 | 0 | pArena->m_stats.m_mem_total -= nSize; |
1013 | 0 | pArena->m_stats.m_mem_alloc -= nSize; |
1014 | |
|
1015 | 0 | #if defined(SAL_UNX) |
1016 | 0 | (void) munmap(pAddr, nSize); |
1017 | | #elif defined(_WIN32) |
1018 | | (void) VirtualFree (pAddr, SIZE_T(0), MEM_RELEASE); |
1019 | | #endif /* (SAL_UNX || _WIN32) */ |
1020 | 0 | } |
1021 | | |
1022 | | sal_Size rtl_machdep_pagesize() |
1023 | 0 | { |
1024 | 0 | #if defined(SAL_UNX) |
1025 | | #if defined(FREEBSD) || defined(NETBSD) || defined(DRAGONFLY) |
1026 | | return (sal_Size)getpagesize(); |
1027 | | #else /* POSIX */ |
1028 | 0 | return static_cast<sal_Size>(sysconf(_SC_PAGESIZE)); |
1029 | 0 | #endif /* xBSD || POSIX */ |
1030 | | #elif defined(_WIN32) |
1031 | | SYSTEM_INFO info; |
1032 | | GetSystemInfo (&info); |
1033 | | return static_cast<sal_Size>(info.dwPageSize); |
1034 | | #endif /* (SAL_UNX || _WIN32) */ |
1035 | 0 | } |
1036 | | |
1037 | | } //namespace |
1038 | | |
1039 | | void rtl_arena_init() |
1040 | 0 | { |
1041 | 0 | { |
1042 | | /* list of arenas */ |
1043 | 0 | RTL_MEMORY_LOCK_INIT(&(g_arena_list.m_lock)); |
1044 | 0 | rtl_arena_constructor (&(g_arena_list.m_arena_head)); |
1045 | 0 | } |
1046 | 0 | { |
1047 | | /* machdep (pseudo) arena */ |
1048 | 0 | static rtl_arena_type g_machdep_arena; |
1049 | |
|
1050 | 0 | assert(!gp_machdep_arena); |
1051 | 0 | rtl_arena_constructor (&g_machdep_arena); |
1052 | |
|
1053 | 0 | gp_machdep_arena = rtl_arena_activate ( |
1054 | 0 | &g_machdep_arena, |
1055 | 0 | "rtl_machdep_arena", |
1056 | 0 | rtl_machdep_pagesize(), |
1057 | 0 | nullptr, nullptr, nullptr /* no source */ |
1058 | 0 | ); |
1059 | 0 | assert(gp_machdep_arena); |
1060 | 0 | } |
1061 | 0 | { |
1062 | | /* default arena */ |
1063 | 0 | static rtl_arena_type g_default_arena; |
1064 | |
|
1065 | 0 | assert(!gp_default_arena); |
1066 | 0 | rtl_arena_constructor (&g_default_arena); |
1067 | |
|
1068 | 0 | gp_default_arena = rtl_arena_activate ( |
1069 | 0 | &g_default_arena, |
1070 | 0 | "rtl_default_arena", |
1071 | 0 | rtl_machdep_pagesize(), |
1072 | 0 | gp_machdep_arena, /* source */ |
1073 | 0 | rtl_machdep_alloc, |
1074 | 0 | rtl_machdep_free |
1075 | 0 | ); |
1076 | 0 | assert(gp_default_arena); |
1077 | 0 | } |
1078 | 0 | { |
1079 | | /* arena internal arena */ |
1080 | 0 | static rtl_arena_type g_arena_arena; |
1081 | |
|
1082 | 0 | assert(!gp_arena_arena); |
1083 | 0 | rtl_arena_constructor (&g_arena_arena); |
1084 | |
|
1085 | 0 | gp_arena_arena = rtl_arena_activate( |
1086 | 0 | &g_arena_arena, |
1087 | 0 | "rtl_arena_internal_arena", |
1088 | 0 | 64, /* quantum */ |
1089 | 0 | gp_default_arena, /* source */ |
1090 | 0 | rtl_arena_alloc, |
1091 | 0 | rtl_arena_free |
1092 | 0 | ); |
1093 | 0 | assert(gp_arena_arena); |
1094 | 0 | } |
1095 | 0 | } |
1096 | | |
1097 | | void rtl_arena_fini() |
1098 | 0 | { |
1099 | 0 | if (gp_arena_arena) |
1100 | 0 | { |
1101 | 0 | rtl_arena_type * arena, * head; |
1102 | |
|
1103 | 0 | RTL_MEMORY_LOCK_ACQUIRE(&(g_arena_list.m_lock)); |
1104 | 0 | head = &(g_arena_list.m_arena_head); |
1105 | |
|
1106 | 0 | for (arena = head->m_arena_next; arena != head; arena = arena->m_arena_next) |
1107 | 0 | { |
1108 | | // noop |
1109 | 0 | } |
1110 | 0 | RTL_MEMORY_LOCK_RELEASE(&(g_arena_list.m_lock)); |
1111 | 0 | } |
1112 | 0 | } |
1113 | | |
1114 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |