Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #define _BSD_SOURCE /* sys/mman.h: MAP_ANON */
30 : : #include "alloc_arena.hxx"
31 : :
32 : : #include "alloc_impl.hxx"
33 : : #include "internal/rtllifecycle.h"
34 : : #include "sal/macros.h"
35 : : #include "osl/diagnose.h"
36 : :
37 : : #include <cassert>
38 : : #include <string.h>
39 : : #include <stdio.h>
40 : :
41 : : extern AllocMode alloc_mode;
42 : :
43 : : /* ================================================================= *
44 : : *
45 : : * arena internals.
46 : : *
47 : : * ================================================================= */
48 : :
49 : : /** g_arena_list
50 : : * @internal
51 : : */
52 : : struct rtl_arena_list_st
53 : : {
54 : : rtl_memory_lock_type m_lock;
55 : : rtl_arena_type m_arena_head;
56 : : };
57 : :
58 : : static rtl_arena_list_st g_arena_list;
59 : :
60 : :
61 : : /** gp_arena_arena
62 : : * provided for arena_type allocations, and hash_table resizing.
63 : : *
64 : : * @internal
65 : : */
66 : : static rtl_arena_type * gp_arena_arena = 0;
67 : :
68 : :
69 : : /** gp_machdep_arena
70 : : *
71 : : * Low level virtual memory (pseudo) arena
72 : : * (platform dependent implementation)
73 : : *
74 : : * @internal
75 : : */
76 : : static rtl_arena_type * gp_machdep_arena = 0;
77 : :
78 : :
79 : : static void *
80 : : SAL_CALL rtl_machdep_alloc (
81 : : rtl_arena_type * pArena,
82 : : sal_Size * pSize
83 : : );
84 : :
85 : : static void
86 : : SAL_CALL rtl_machdep_free (
87 : : rtl_arena_type * pArena,
88 : : void * pAddr,
89 : : sal_Size nSize
90 : : );
91 : :
92 : : static sal_Size
93 : : rtl_machdep_pagesize();
94 : :
95 : :
96 : : /** gp_default_arena
97 : : */
98 : : rtl_arena_type * gp_default_arena = 0;
99 : :
100 : :
101 : : /* ================================================================= */
102 : :
103 : : /** rtl_arena_segment_constructor()
104 : : */
105 : : static int
106 : 647465 : rtl_arena_segment_constructor (void * obj)
107 : : {
108 : 647465 : rtl_arena_segment_type * segment = (rtl_arena_segment_type*)(obj);
109 : :
110 : 647465 : QUEUE_START_NAMED(segment, s);
111 : 647465 : QUEUE_START_NAMED(segment, f);
112 : :
113 : 647465 : return (1);
114 : : }
115 : :
116 : :
117 : : /** rtl_arena_segment_destructor()
118 : : */
119 : : static void
120 : 227045 : rtl_arena_segment_destructor (void * obj)
121 : : {
122 : : rtl_arena_segment_type * segment = static_cast< rtl_arena_segment_type * >(
123 : 227045 : obj);
124 : : assert(QUEUE_STARTED_NAMED(segment, s));
125 : : assert(QUEUE_STARTED_NAMED(segment, f));
126 : : (void) segment; // avoid warnings
127 : 227045 : }
128 : :
129 : : /* ================================================================= */
130 : :
131 : : /** rtl_arena_segment_populate()
132 : : *
133 : : * @precond arena->m_lock acquired.
134 : : */
135 : : static int
136 : 10265 : rtl_arena_segment_populate (
137 : : rtl_arena_type * arena
138 : : )
139 : : {
140 : : rtl_arena_segment_type *span;
141 : 10265 : sal_Size size = rtl_machdep_pagesize();
142 : :
143 : : span = static_cast< rtl_arena_segment_type * >(
144 : 10265 : rtl_machdep_alloc(gp_machdep_arena, &size));
145 [ + - ]: 10265 : if (span != 0)
146 : : {
147 : : rtl_arena_segment_type *first, *last, *head;
148 : 10265 : sal_Size count = size / sizeof(rtl_arena_segment_type);
149 : :
150 : : /* insert onto reserve span list */
151 : 10265 : QUEUE_INSERT_TAIL_NAMED(&(arena->m_segment_reserve_span_head), span, s);
152 : 10265 : QUEUE_START_NAMED(span, f);
153 : 10265 : span->m_addr = (sal_uIntPtr)(span);
154 : 10265 : span->m_size = size;
155 : 10265 : span->m_type = RTL_ARENA_SEGMENT_TYPE_SPAN;
156 : :
157 : : /* insert onto reserve list */
158 : 10265 : head = &(arena->m_segment_reserve_head);
159 [ + + ]: 24020100 : for (first = span + 1, last = span + count; first < last; ++first)
160 : : {
161 : 24009835 : QUEUE_INSERT_TAIL_NAMED(head, first, s);
162 : 24009835 : QUEUE_START_NAMED(first, f);
163 : 24009835 : first->m_addr = 0;
164 : 24009835 : first->m_size = 0;
165 : 24009835 : first->m_type = 0;
166 : : }
167 : : }
168 : 10265 : return (span != 0);
169 : : }
170 : :
171 : :
172 : : /** rtl_arena_segment_get()
173 : : *
174 : : * @precond arena->m_lock acquired.
175 : : * @precond (*ppSegment == 0)
176 : : */
177 : : static RTL_MEMORY_INLINE void
178 : 1072103 : rtl_arena_segment_get (
179 : : rtl_arena_type * arena,
180 : : rtl_arena_segment_type ** ppSegment
181 : : )
182 : : {
183 : : rtl_arena_segment_type * head;
184 : :
185 : : assert(*ppSegment == 0);
186 : :
187 : 1072103 : head = &(arena->m_segment_reserve_head);
188 [ + + ][ + - ]: 1072103 : if ((head->m_snext != head) || rtl_arena_segment_populate (arena))
[ + - ]
189 : : {
190 : 1072103 : (*ppSegment) = head->m_snext;
191 : 1072103 : QUEUE_REMOVE_NAMED((*ppSegment), s);
192 : : }
193 : 1072103 : }
194 : :
195 : : #if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
196 : : #pragma inline(rtl_arena_segment_get)
197 : : #endif
198 : :
199 : :
200 : : /** rtl_arena_segment_put()
201 : : *
202 : : * @precond arena->m_lock acquired.
203 : : * @postcond (*ppSegment == 0)
204 : : */
205 : : static RTL_MEMORY_INLINE void
206 : 905667 : rtl_arena_segment_put (
207 : : rtl_arena_type * arena,
208 : : rtl_arena_segment_type ** ppSegment
209 : : )
210 : : {
211 : : rtl_arena_segment_type * head;
212 : :
213 : : assert(QUEUE_STARTED_NAMED((*ppSegment), s));
214 : : assert(QUEUE_STARTED_NAMED((*ppSegment), f));
215 : :
216 : 905667 : (*ppSegment)->m_addr = 0;
217 : 905667 : (*ppSegment)->m_size = 0;
218 : :
219 : : assert((*ppSegment)->m_type != RTL_ARENA_SEGMENT_TYPE_HEAD);
220 : 905667 : (*ppSegment)->m_type = 0;
221 : :
222 : : /* keep as reserve */
223 : 905667 : head = &(arena->m_segment_reserve_head);
224 : 905667 : QUEUE_INSERT_HEAD_NAMED(head, (*ppSegment), s);
225 : :
226 : : /* clear */
227 : 905667 : (*ppSegment) = 0;
228 : 905667 : }
229 : :
230 : : #if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
231 : : #pragma inline(rtl_arena_segment_put)
232 : : #endif
233 : :
234 : : /* ================================================================= */
235 : :
236 : : /** rtl_arena_freelist_insert()
237 : : *
238 : : * @precond arena->m_lock acquired.
239 : : */
240 : : static RTL_MEMORY_INLINE void
241 : 1049068 : rtl_arena_freelist_insert (
242 : : rtl_arena_type * arena,
243 : : rtl_arena_segment_type * segment
244 : : )
245 : : {
246 : : rtl_arena_segment_type * head;
247 : :
248 : 1049068 : head = &(arena->m_freelist_head[highbit(segment->m_size) - 1]);
249 : 1049068 : QUEUE_INSERT_TAIL_NAMED(head, segment, f);
250 : :
251 : 1049068 : arena->m_freelist_bitmap |= head->m_size;
252 : 1049068 : }
253 : :
254 : : #if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
255 : : #pragma inline(rtl_arena_freelist_insert)
256 : : #endif /* __SUNPRO_C */
257 : :
258 : :
259 : : /** rtl_arena_freelist_remove()
260 : : *
261 : : * @precond arena->m_lock acquired.
262 : : */
263 : : static RTL_MEMORY_INLINE void
264 : 1018300 : rtl_arena_freelist_remove (
265 : : rtl_arena_type * arena,
266 : : rtl_arena_segment_type * segment
267 : : )
268 : : {
269 [ + + ][ + + ]: 1018300 : if ((segment->m_fnext->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD) &&
270 : : (segment->m_fprev->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD) )
271 : : {
272 : : rtl_arena_segment_type * head;
273 : :
274 : 646561 : head = segment->m_fprev;
275 : : assert(arena->m_freelist_bitmap & head->m_size);
276 : 646561 : arena->m_freelist_bitmap ^= head->m_size;
277 : : }
278 : 1018300 : QUEUE_REMOVE_NAMED(segment, f);
279 : 1018300 : }
280 : :
281 : : #if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
282 : : #pragma inline(rtl_arena_freelist_remove)
283 : : #endif /* __SUNPRO_C */
284 : :
285 : :
286 : : /* ================================================================= */
287 : :
288 : : /** RTL_ARENA_HASH_INDEX()
289 : : */
290 : : #define RTL_ARENA_HASH_INDEX_IMPL(a, s, q, m) \
291 : : ((((a) + ((a) >> (s)) + ((a) >> ((s) << 1))) >> (q)) & (m))
292 : :
293 : : #define RTL_ARENA_HASH_INDEX(arena, addr) \
294 : : RTL_ARENA_HASH_INDEX_IMPL((addr), (arena)->m_hash_shift, (arena)->m_quantum_shift, ((arena)->m_hash_size - 1))
295 : :
296 : : /** rtl_arena_hash_rescale()
297 : : *
298 : : * @precond arena->m_lock released.
299 : : */
300 : : static void
301 : 217 : rtl_arena_hash_rescale (
302 : : rtl_arena_type * arena,
303 : : sal_Size new_size
304 : : )
305 : : {
306 : : rtl_arena_segment_type ** new_table;
307 : : sal_Size new_bytes;
308 : :
309 : 217 : new_bytes = new_size * sizeof(rtl_arena_segment_type*);
310 : 217 : new_table = (rtl_arena_segment_type **)rtl_arena_alloc (gp_arena_arena, &new_bytes);
311 : :
312 [ + - ]: 217 : if (new_table != 0)
313 : : {
314 : : rtl_arena_segment_type ** old_table;
315 : : sal_Size old_size, i;
316 : :
317 : 217 : memset (new_table, 0, new_bytes);
318 : :
319 : 217 : RTL_MEMORY_LOCK_ACQUIRE(&(arena->m_lock));
320 : :
321 : 217 : old_table = arena->m_hash_table;
322 : 217 : old_size = arena->m_hash_size;
323 : :
324 : : // SAL_INFO(
325 : : // "sal",
326 : : // "rtl_arena_hash_rescale(" << arena->m_name << "): nseg: "
327 : : // << (arena->m_stats.m_alloc - arena->m_stats.m_free) << " (ave: "
328 : : // << ((arena->m_stats.m_alloc - arena->m_stats.m_free)
329 : : // >> arena->m_hash_shift)
330 : : // << "), frees: " << arena->m_stats.m_free << " [old_size: "
331 : : // << old_size << ", new_size: " << new_size << ']');
332 : :
333 : 217 : arena->m_hash_table = new_table;
334 : 217 : arena->m_hash_size = new_size;
335 : 217 : arena->m_hash_shift = highbit(arena->m_hash_size) - 1;
336 : :
337 [ + + ]: 14105 : for (i = 0; i < old_size; i++)
338 : : {
339 : 13888 : rtl_arena_segment_type * curr = old_table[i];
340 [ + + ]: 191491 : while (curr != 0)
341 : : {
342 : 177603 : rtl_arena_segment_type * next = curr->m_fnext;
343 : : rtl_arena_segment_type ** head;
344 : :
345 : 177603 : head = &(arena->m_hash_table[RTL_ARENA_HASH_INDEX(arena, curr->m_addr)]);
346 : 177603 : curr->m_fnext = (*head);
347 : 177603 : (*head) = curr;
348 : :
349 : 177603 : curr = next;
350 : : }
351 : 13888 : old_table[i] = 0;
352 : : }
353 : :
354 : 217 : RTL_MEMORY_LOCK_RELEASE(&(arena->m_lock));
355 : :
356 [ - + ]: 217 : if (old_table != arena->m_hash_table_0)
357 : : {
358 : 0 : sal_Size old_bytes = old_size * sizeof(rtl_arena_segment_type*);
359 : 0 : rtl_arena_free (gp_arena_arena, old_table, old_bytes);
360 : : }
361 : : }
362 : 217 : }
363 : :
364 : :
365 : : /** rtl_arena_hash_insert()
366 : : * ...and update stats.
367 : : */
368 : : static RTL_MEMORY_INLINE void
369 : 714703 : rtl_arena_hash_insert (
370 : : rtl_arena_type * arena,
371 : : rtl_arena_segment_type * segment
372 : : )
373 : : {
374 : : rtl_arena_segment_type ** ppSegment;
375 : :
376 : 714703 : ppSegment = &(arena->m_hash_table[RTL_ARENA_HASH_INDEX(arena, segment->m_addr)]);
377 : :
378 : 714703 : segment->m_fnext = (*ppSegment);
379 : 714703 : (*ppSegment) = segment;
380 : :
381 : 714703 : arena->m_stats.m_alloc += 1;
382 : 714703 : arena->m_stats.m_mem_alloc += segment->m_size;
383 : 714703 : }
384 : :
385 : : #if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
386 : : #pragma inline(rtl_arena_hash_insert)
387 : : #endif /* __SUNPRO_C */
388 : :
389 : :
390 : : /** rtl_arena_hash_remove()
391 : : * ...and update stats.
392 : : */
393 : : static rtl_arena_segment_type *
394 : 595844 : rtl_arena_hash_remove (
395 : : rtl_arena_type * arena,
396 : : sal_uIntPtr addr,
397 : : sal_Size size
398 : : )
399 : : {
400 : : rtl_arena_segment_type *segment, **segpp;
401 : 595844 : sal_Size lookups = 0;
402 : :
403 : 595844 : segpp = &(arena->m_hash_table[RTL_ARENA_HASH_INDEX(arena, addr)]);
404 [ + - ]: 671396 : while ((segment = *segpp) != 0)
405 : : {
406 [ + + ]: 671396 : if (segment->m_addr == addr)
407 : : {
408 : 595844 : *segpp = segment->m_fnext, segment->m_fnext = segment->m_fprev = segment;
409 : 595844 : break;
410 : : }
411 : :
412 : : /* update lookup miss stats */
413 : 75552 : lookups += 1;
414 : 75552 : segpp = &(segment->m_fnext);
415 : : }
416 : :
417 : : assert(segment != 0); // bad free
418 [ + - ]: 595844 : if (segment != 0)
419 : : {
420 : : assert(segment->m_size == size);
421 : : (void) size; // avoid warnings
422 : :
423 : 595844 : arena->m_stats.m_free += 1;
424 : 595844 : arena->m_stats.m_mem_alloc -= segment->m_size;
425 : :
426 [ + + ]: 595844 : if (lookups > 1)
427 : : {
428 : 12651 : sal_Size nseg = (sal_Size)(arena->m_stats.m_alloc - arena->m_stats.m_free);
429 [ + + ]: 12651 : if (nseg > 4 * arena->m_hash_size)
430 : : {
431 [ + - ]: 217 : if (!(arena->m_flags & RTL_ARENA_FLAG_RESCALE))
432 : : {
433 : 217 : sal_Size ave = nseg >> arena->m_hash_shift;
434 : 217 : sal_Size new_size = arena->m_hash_size << (highbit(ave) - 1);
435 : :
436 : 217 : arena->m_flags |= RTL_ARENA_FLAG_RESCALE;
437 : 217 : RTL_MEMORY_LOCK_RELEASE(&(arena->m_lock));
438 : 217 : rtl_arena_hash_rescale (arena, new_size);
439 : 217 : RTL_MEMORY_LOCK_ACQUIRE(&(arena->m_lock));
440 : 217 : arena->m_flags &= ~RTL_ARENA_FLAG_RESCALE;
441 : : }
442 : : }
443 : : }
444 : : }
445 : :
446 : 595844 : return (segment);
447 : : }
448 : :
449 : : /* ================================================================= */
450 : :
451 : : /** rtl_arena_segment_alloc()
452 : : * allocate (and remove) segment from freelist
453 : : *
454 : : * @precond arena->m_lock acquired
455 : : * @precond (*ppSegment == 0)
456 : : */
457 : : static int
458 : 714703 : rtl_arena_segment_alloc (
459 : : rtl_arena_type * arena,
460 : : sal_Size size,
461 : : rtl_arena_segment_type ** ppSegment
462 : : )
463 : : {
464 : 714703 : int index = 0;
465 : :
466 : : assert(*ppSegment == 0);
467 [ + + ]: 714703 : if (!RTL_MEMORY_ISP2(size))
468 : : {
469 : 336613 : int msb = highbit(size);
470 [ - + ]: 336613 : if (RTL_ARENA_FREELIST_SIZE == sal::static_int_cast< size_t >(msb))
471 : : {
472 : : /* highest possible freelist: fall back to first fit */
473 : : rtl_arena_segment_type *head, *segment;
474 : :
475 : 0 : head = &(arena->m_freelist_head[msb - 1]);
476 [ # # ]: 0 : for (segment = head->m_fnext; segment != head; segment = segment->m_fnext)
477 : : {
478 [ # # ]: 0 : if (segment->m_size >= size)
479 : : {
480 : : /* allocate first fit segment */
481 : 0 : (*ppSegment) = segment;
482 : 0 : break;
483 : : }
484 : : }
485 : 0 : goto dequeue_and_leave;
486 : : }
487 : :
488 : : /* roundup to next power of 2 */
489 : 336613 : size = (1UL << msb);
490 : : }
491 : :
492 : 714703 : index = lowbit(RTL_MEMORY_P2ALIGN(arena->m_freelist_bitmap, size));
493 [ + + ]: 714703 : if (index > 0)
494 : : {
495 : : /* instant fit: allocate first free segment */
496 : : rtl_arena_segment_type *head;
497 : :
498 : 501653 : head = &(arena->m_freelist_head[index - 1]);
499 : 501653 : (*ppSegment) = head->m_fnext;
500 : : assert((*ppSegment) != head);
501 : : }
502 : :
503 : : dequeue_and_leave:
504 [ + + ]: 714703 : if (*ppSegment != 0)
505 : : {
506 : : /* remove from freelist */
507 : 501653 : rtl_arena_freelist_remove (arena, (*ppSegment));
508 : : }
509 : 714703 : return (*ppSegment != 0);
510 : : }
511 : :
512 : :
513 : : /** rtl_arena_segment_create()
514 : : * import new (span) segment from source arena
515 : : *
516 : : * @precond arena->m_lock acquired
517 : : * @precond (*ppSegment == 0)
518 : : */
519 : : static int
520 : 213050 : rtl_arena_segment_create (
521 : : rtl_arena_type * arena,
522 : : sal_Size size,
523 : : rtl_arena_segment_type ** ppSegment
524 : : )
525 : : {
526 : : assert((*ppSegment) == 0);
527 [ + - ]: 213050 : if (arena->m_source_alloc != 0)
528 : : {
529 : 213050 : rtl_arena_segment_get (arena, ppSegment);
530 [ + - ]: 213050 : if (*ppSegment != 0)
531 : : {
532 : 213050 : rtl_arena_segment_type * span = 0;
533 [ + - ]: 213050 : rtl_arena_segment_get (arena, &span);
534 [ + - ]: 213050 : if (span != 0)
535 : : {
536 : : /* import new span from source arena */
537 : 213050 : RTL_MEMORY_LOCK_RELEASE(&(arena->m_lock));
538 : :
539 : 213050 : span->m_size = size;
540 : : span->m_addr = (sal_uIntPtr)(arena->m_source_alloc)(
541 [ + - ]: 213050 : arena->m_source_arena, &(span->m_size));
542 : :
543 : 213050 : RTL_MEMORY_LOCK_ACQUIRE(&(arena->m_lock));
544 [ + - ]: 213050 : if (span->m_addr != 0)
545 : : {
546 : : /* insert onto segment list, update stats */
547 : 213050 : span->m_type = RTL_ARENA_SEGMENT_TYPE_SPAN;
548 : 213050 : QUEUE_INSERT_HEAD_NAMED(&(arena->m_segment_head), span, s);
549 : 213050 : arena->m_stats.m_mem_total += span->m_size;
550 : :
551 : 213050 : (*ppSegment)->m_addr = span->m_addr;
552 : 213050 : (*ppSegment)->m_size = span->m_size;
553 : 213050 : (*ppSegment)->m_type = RTL_ARENA_SEGMENT_TYPE_FREE;
554 : 213050 : QUEUE_INSERT_HEAD_NAMED(span, (*ppSegment), s);
555 : :
556 : : /* report success */
557 : 213050 : return (1);
558 : : }
559 : 0 : rtl_arena_segment_put (arena, &span);
560 : : }
561 : 0 : rtl_arena_segment_put (arena, ppSegment);
562 : : }
563 : : }
564 : 213050 : return (0);
565 : : }
566 : :
567 : :
568 : : /** rtl_arena_segment_coalesce()
569 : : * mark as free and join with adjacent free segment(s)
570 : : *
571 : : * @precond arena->m_lock acquired
572 : : * @precond segment marked 'used'
573 : : */
574 : : static void
575 : 596998 : rtl_arena_segment_coalesce (
576 : : rtl_arena_type * arena,
577 : : rtl_arena_segment_type * segment
578 : : )
579 : : {
580 : : rtl_arena_segment_type *next, *prev;
581 : :
582 : : /* mark segment free */
583 : : assert(segment->m_type == RTL_ARENA_SEGMENT_TYPE_USED);
584 : 596998 : segment->m_type = RTL_ARENA_SEGMENT_TYPE_FREE;
585 : :
586 : : /* try to merge w/ next segment */
587 : 596998 : next = segment->m_snext;
588 [ + + ]: 596998 : if (next->m_type == RTL_ARENA_SEGMENT_TYPE_FREE)
589 : : {
590 : : assert(segment->m_addr + segment->m_size == next->m_addr);
591 : 277181 : segment->m_size += next->m_size;
592 : :
593 : : /* remove from freelist */
594 : 277181 : rtl_arena_freelist_remove (arena, next);
595 : :
596 : : /* remove from segment list */
597 : 277181 : QUEUE_REMOVE_NAMED(next, s);
598 : :
599 : : /* release segment descriptor */
600 : 277181 : rtl_arena_segment_put (arena, &next);
601 : : }
602 : :
603 : : /* try to merge w/ prev segment */
604 : 596998 : prev = segment->m_sprev;
605 [ + + ]: 596998 : if (prev->m_type == RTL_ARENA_SEGMENT_TYPE_FREE)
606 : : {
607 : : assert(prev->m_addr + prev->m_size == segment->m_addr);
608 : 238312 : segment->m_addr = prev->m_addr;
609 : 238312 : segment->m_size += prev->m_size;
610 : :
611 : : /* remove from freelist */
612 : 238312 : rtl_arena_freelist_remove (arena, prev);
613 : :
614 : : /* remove from segment list */
615 : 238312 : QUEUE_REMOVE_NAMED(prev, s);
616 : :
617 : : /* release segment descriptor */
618 : 238312 : rtl_arena_segment_put (arena, &prev);
619 : : }
620 : 596998 : }
621 : :
622 : : /* ================================================================= */
623 : :
624 : : /** rtl_arena_constructor()
625 : : */
626 : : static void
627 : 18499 : rtl_arena_constructor (void * obj)
628 : : {
629 : 18499 : rtl_arena_type * arena = (rtl_arena_type*)(obj);
630 : : rtl_arena_segment_type * head;
631 : : size_t i;
632 : :
633 : 18499 : memset (arena, 0, sizeof(rtl_arena_type));
634 : :
635 : 18499 : QUEUE_START_NAMED(arena, arena_);
636 : :
637 : 18499 : (void) RTL_MEMORY_LOCK_INIT(&(arena->m_lock));
638 : :
639 : 18499 : head = &(arena->m_segment_reserve_span_head);
640 : 18499 : rtl_arena_segment_constructor (head);
641 : 18499 : head->m_type = RTL_ARENA_SEGMENT_TYPE_HEAD;
642 : :
643 : 18499 : head = &(arena->m_segment_reserve_head);
644 : 18499 : rtl_arena_segment_constructor (head);
645 : 18499 : head->m_type = RTL_ARENA_SEGMENT_TYPE_HEAD;
646 : :
647 : 18499 : head = &(arena->m_segment_head);
648 : 18499 : rtl_arena_segment_constructor (head);
649 : 18499 : head->m_type = RTL_ARENA_SEGMENT_TYPE_HEAD;
650 : :
651 [ + + ]: 610467 : for (i = 0; i < RTL_ARENA_FREELIST_SIZE; i++)
652 : : {
653 : 591968 : head = &(arena->m_freelist_head[i]);
654 : 591968 : rtl_arena_segment_constructor (head);
655 : :
656 : 591968 : head->m_size = (1UL << i);
657 : 591968 : head->m_type = RTL_ARENA_SEGMENT_TYPE_HEAD;
658 : : }
659 : :
660 : 18499 : arena->m_hash_table = arena->m_hash_table_0;
661 : 18499 : arena->m_hash_size = RTL_ARENA_HASH_SIZE;
662 : 18499 : arena->m_hash_shift = highbit(arena->m_hash_size) - 1;
663 : 18499 : }
664 : :
665 : :
666 : : /** rtl_arena_destructor()
667 : : */
668 : : static void
669 : 6487 : rtl_arena_destructor (void * obj)
670 : : {
671 : 6487 : rtl_arena_type * arena = (rtl_arena_type*)(obj);
672 : : rtl_arena_segment_type * head;
673 : : size_t i;
674 : :
675 : : assert(QUEUE_STARTED_NAMED(arena, arena_));
676 : :
677 : 6487 : RTL_MEMORY_LOCK_DESTROY(&(arena->m_lock));
678 : :
679 : 6487 : head = &(arena->m_segment_reserve_span_head);
680 : : assert(head->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD);
681 : 6487 : rtl_arena_segment_destructor (head);
682 : :
683 : 6487 : head = &(arena->m_segment_reserve_head);
684 : : assert(head->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD);
685 : 6487 : rtl_arena_segment_destructor (head);
686 : :
687 : 6487 : head = &(arena->m_segment_head);
688 : : assert(head->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD);
689 : 6487 : rtl_arena_segment_destructor (head);
690 : :
691 [ + + ]: 214071 : for (i = 0; i < RTL_ARENA_FREELIST_SIZE; i++)
692 : : {
693 : 207584 : head = &(arena->m_freelist_head[i]);
694 : :
695 : : assert(head->m_size == (1UL << i));
696 : : assert(head->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD);
697 : :
698 : 207584 : rtl_arena_segment_destructor (head);
699 : : }
700 : :
701 : : assert(arena->m_hash_table == arena->m_hash_table_0);
702 : : assert(arena->m_hash_size == RTL_ARENA_HASH_SIZE);
703 : : assert(
704 : : arena->m_hash_shift ==
705 : : sal::static_int_cast< unsigned >(highbit(arena->m_hash_size) - 1));
706 : 6487 : }
707 : :
708 : : /* ================================================================= */
709 : :
710 : : /** rtl_arena_activate()
711 : : */
712 : : static rtl_arena_type *
713 : 15496 : rtl_arena_activate (
714 : : rtl_arena_type * arena,
715 : : const char * name,
716 : : sal_Size quantum,
717 : : sal_Size quantum_cache_max,
718 : : rtl_arena_type * source_arena,
719 : : void * (SAL_CALL * source_alloc)(rtl_arena_type *, sal_Size *),
720 : : void (SAL_CALL * source_free) (rtl_arena_type *, void *, sal_Size)
721 : : )
722 : : {
723 : : assert(arena != 0);
724 [ + - ]: 15496 : if (arena != 0)
725 : : {
726 : 15496 : (void) snprintf (arena->m_name, sizeof(arena->m_name), "%s", name);
727 : :
728 [ - + ]: 15496 : if (!RTL_MEMORY_ISP2(quantum))
729 : : {
730 : : /* roundup to next power of 2 */
731 : 0 : quantum = (1UL << highbit(quantum));
732 : : }
733 : 15496 : quantum_cache_max = RTL_MEMORY_P2ROUNDUP(quantum_cache_max, quantum);
734 : :
735 : 15496 : arena->m_quantum = quantum;
736 : 15496 : arena->m_quantum_shift = highbit(arena->m_quantum) - 1;
737 : 15496 : arena->m_qcache_max = quantum_cache_max;
738 : :
739 : 15496 : arena->m_source_arena = source_arena;
740 : 15496 : arena->m_source_alloc = source_alloc;
741 : 15496 : arena->m_source_free = source_free;
742 : :
743 [ - + ]: 15496 : if (arena->m_qcache_max > 0)
744 : : {
745 : : char namebuf[RTL_ARENA_NAME_LENGTH + 1];
746 : 0 : int i, n = (arena->m_qcache_max >> arena->m_quantum_shift);
747 : :
748 : 0 : sal_Size size = n * sizeof(rtl_cache_type*);
749 : 0 : arena->m_qcache_ptr = (rtl_cache_type**)rtl_arena_alloc (gp_arena_arena, &size);
750 [ # # ]: 0 : if (!(arena->m_qcache_ptr))
751 : : {
752 : : /* out of memory */
753 : 0 : return (0);
754 : : }
755 [ # # ]: 0 : for (i = 1; i <= n; i++)
756 : : {
757 : 0 : size = i * arena->m_quantum;
758 : 0 : (void) snprintf (namebuf, sizeof(namebuf), "%s_%lu", arena->m_name, size);
759 : 0 : arena->m_qcache_ptr[i - 1] = rtl_cache_create(namebuf, size, 0, NULL, NULL, NULL, NULL, arena, RTL_CACHE_FLAG_QUANTUMCACHE);
760 : : }
761 : : }
762 : :
763 : : /* insert into arena list */
764 : 15496 : RTL_MEMORY_LOCK_ACQUIRE(&(g_arena_list.m_lock));
765 : 15496 : QUEUE_INSERT_TAIL_NAMED(&(g_arena_list.m_arena_head), arena, arena_);
766 : 15496 : RTL_MEMORY_LOCK_RELEASE(&(g_arena_list.m_lock));
767 : : }
768 : 15496 : return (arena);
769 : : }
770 : :
771 : : /** rtl_arena_deactivate()
772 : : */
773 : : static void
774 : 6487 : rtl_arena_deactivate (
775 : : rtl_arena_type * arena
776 : : )
777 : : {
778 : : rtl_arena_segment_type * head, * segment;
779 : :
780 : : /* remove from arena list */
781 : 6487 : RTL_MEMORY_LOCK_ACQUIRE(&(g_arena_list.m_lock));
782 : 6487 : QUEUE_REMOVE_NAMED(arena, arena_);
783 : 6487 : RTL_MEMORY_LOCK_RELEASE(&(g_arena_list.m_lock));
784 : :
785 : : /* cleanup quantum cache(s) */
786 [ # # ][ - + ]: 6487 : if ((arena->m_qcache_max > 0) && (arena->m_qcache_ptr != 0))
787 : : {
788 : 0 : int i, n = (arena->m_qcache_max >> arena->m_quantum_shift);
789 [ # # ]: 0 : for (i = 1; i <= n; i++)
790 : : {
791 [ # # ]: 0 : if (arena->m_qcache_ptr[i - 1] != 0)
792 : : {
793 : 0 : rtl_cache_destroy (arena->m_qcache_ptr[i - 1]);
794 : 0 : arena->m_qcache_ptr[i - 1] = 0;
795 : : }
796 : : }
797 : : rtl_arena_free (
798 : : gp_arena_arena,
799 : : arena->m_qcache_ptr,
800 : 0 : n * sizeof(rtl_cache_type*));
801 : :
802 : 0 : arena->m_qcache_ptr = 0;
803 : : }
804 : :
805 : : /* check for leaked segments */
806 : : // SAL_INFO(
807 : : // "sal",
808 : : // "rtl_arena_deactivate(" << arena->m_name << "): allocs: "
809 : : // << arena->m_stats.m_alloc << ", frees: " << arena->m_stats.m_free
810 : : // << "; total: " << arena->m_stats.m_mem_total << ", used: "
811 : : // << arena->m_stats.m_mem_alloc);
812 [ + + ]: 6487 : if (arena->m_stats.m_alloc > arena->m_stats.m_free)
813 : : {
814 : : sal_Size i, n;
815 : :
816 : : // SAL_INFO(
817 : : // "sal",
818 : : // "rtl_arena_deactivate(" << arena->m_name << "): cleaning up "
819 : : // << (arena->m_stats.m_alloc - arena->m_stats.m_free)
820 : : // << " leaked segment(s) [" << arena->m_stats.m_mem_alloc
821 : : // << " bytes]");
822 : :
823 : : /* cleanup still used segment(s) */
824 [ + + ]: 8775 : for (i = 0, n = arena->m_hash_size; i < n; i++)
825 : : {
826 [ + + ]: 9794 : while ((segment = arena->m_hash_table[i]) != 0)
827 : : {
828 : : /* pop from hash table */
829 : 1154 : arena->m_hash_table[i] = segment->m_fnext, segment->m_fnext = segment->m_fprev = segment;
830 : :
831 : : /* coalesce w/ adjacent free segment(s) */
832 : 1154 : rtl_arena_segment_coalesce (arena, segment);
833 : :
834 : : /* insert onto freelist */
835 : 1154 : rtl_arena_freelist_insert (arena, segment);
836 : : }
837 : : }
838 : : }
839 : :
840 : : /* cleanup hash table */
841 [ - + ]: 6487 : if (arena->m_hash_table != arena->m_hash_table_0)
842 : : {
843 : : rtl_arena_free (
844 : : gp_arena_arena,
845 : : arena->m_hash_table,
846 : 0 : arena->m_hash_size * sizeof(rtl_arena_segment_type*));
847 : :
848 : 0 : arena->m_hash_table = arena->m_hash_table_0;
849 : 0 : arena->m_hash_size = RTL_ARENA_HASH_SIZE;
850 : 0 : arena->m_hash_shift = highbit(arena->m_hash_size) - 1;
851 : : }
852 : :
853 : : /* cleanup segment list */
854 : 6487 : head = &(arena->m_segment_head);
855 [ + + ]: 8795 : for (segment = head->m_snext; segment != head; segment = head->m_snext)
856 : : {
857 [ + + ]: 2308 : if (segment->m_type == RTL_ARENA_SEGMENT_TYPE_FREE)
858 : : {
859 : : /* remove from freelist */
860 : 1154 : rtl_arena_freelist_remove (arena, segment);
861 : : }
862 : : else
863 : : {
864 : : /* can have only free and span segments here */
865 : : assert(segment->m_type == RTL_ARENA_SEGMENT_TYPE_SPAN);
866 : : }
867 : :
868 : : /* remove from segment list */
869 : 2308 : QUEUE_REMOVE_NAMED(segment, s);
870 : :
871 : : /* release segment descriptor */
872 : 2308 : rtl_arena_segment_put (arena, &segment);
873 : : }
874 : :
875 : : /* cleanup segment reserve list */
876 : 6487 : head = &(arena->m_segment_reserve_head);
877 [ + + ]: 11184568 : for (segment = head->m_snext; segment != head; segment = head->m_snext)
878 : : {
879 : : /* remove from segment list */
880 : 11178081 : QUEUE_REMOVE_NAMED(segment, s);
881 : : }
882 : :
883 : : /* cleanup segment reserve span(s) */
884 : 6487 : head = &(arena->m_segment_reserve_span_head);
885 [ + + ]: 11266 : for (segment = head->m_snext; segment != head; segment = head->m_snext)
886 : : {
887 : : /* can have only span segments here */
888 : : assert(segment->m_type == RTL_ARENA_SEGMENT_TYPE_SPAN);
889 : :
890 : : /* remove from segment list */
891 : 4779 : QUEUE_REMOVE_NAMED(segment, s);
892 : :
893 : : /* return span to g_machdep_arena */
894 : 4779 : rtl_machdep_free (gp_machdep_arena, (void*)(segment->m_addr), segment->m_size);
895 : : }
896 : 6487 : }
897 : :
898 : : /* ================================================================= *
899 : : *
900 : : * arena implementation.
901 : : *
902 : : * ================================================================= */
903 : :
904 : : /** rtl_arena_create()
905 : : */
906 : : rtl_arena_type *
907 : 6487 : SAL_CALL rtl_arena_create (
908 : : const char * name,
909 : : sal_Size quantum,
910 : : sal_Size quantum_cache_max,
911 : : rtl_arena_type * source_arena,
912 : : void * (SAL_CALL * source_alloc)(rtl_arena_type *, sal_Size *),
913 : : void (SAL_CALL * source_free) (rtl_arena_type *, void *, sal_Size),
914 : : SAL_UNUSED_PARAMETER int
915 : : ) SAL_THROW_EXTERN_C()
916 : : {
917 : 6487 : rtl_arena_type * result = 0;
918 : 6487 : sal_Size size = sizeof(rtl_arena_type);
919 : :
920 : : try_alloc:
921 : 9490 : result = (rtl_arena_type*)rtl_arena_alloc (gp_arena_arena, &size);
922 [ + + ]: 9490 : if (result != 0)
923 : : {
924 : 6487 : rtl_arena_type * arena = result;
925 : 6487 : rtl_arena_constructor (arena);
926 : :
927 [ + + ]: 6487 : if (!source_arena)
928 : : {
929 : : assert(gp_default_arena != 0);
930 : 5745 : source_arena = gp_default_arena;
931 : : }
932 : :
933 : : result = rtl_arena_activate (
934 : : arena,
935 : : name,
936 : : quantum,
937 : : quantum_cache_max,
938 : : source_arena,
939 : : source_alloc,
940 : : source_free
941 : 6487 : );
942 : :
943 [ - + ]: 6487 : if (result == 0)
944 : : {
945 [ # # ]: 0 : rtl_arena_deactivate (arena);
946 : 0 : rtl_arena_destructor (arena);
947 : 0 : rtl_arena_free (gp_arena_arena, arena, size);
948 : : }
949 : : }
950 [ + - ]: 3003 : else if (gp_arena_arena == 0)
951 : : {
952 [ + - ]: 3003 : ensureArenaSingleton();
953 [ + - ]: 3003 : if (gp_arena_arena)
954 : : {
955 : : /* try again */
956 : 3003 : goto try_alloc;
957 : : }
958 : : }
959 : 6487 : return (result);
960 : : }
961 : :
962 : : /** rtl_arena_destroy()
963 : : */
964 : : void
965 : 6487 : SAL_CALL rtl_arena_destroy (
966 : : rtl_arena_type * arena
967 : : ) SAL_THROW_EXTERN_C()
968 : : {
969 [ + - ]: 6487 : if (arena != 0)
970 : : {
971 : 6487 : rtl_arena_deactivate (arena);
972 : 6487 : rtl_arena_destructor (arena);
973 : 6487 : rtl_arena_free (gp_arena_arena, arena, sizeof(rtl_arena_type));
974 : : }
975 : 6487 : }
976 : :
977 : : /** rtl_arena_alloc()
978 : : */
979 : : void *
980 : 724091 : SAL_CALL rtl_arena_alloc (
981 : : rtl_arena_type * arena,
982 : : sal_Size * pSize
983 : : ) SAL_THROW_EXTERN_C()
984 : : {
985 : 724091 : void * addr = 0;
986 : :
987 [ + + ][ + - ]: 724091 : if ((arena != 0) && (pSize != 0))
988 : : {
989 : : sal_Size size;
990 : :
991 [ + + ]: 718085 : if (alloc_mode == AMode_SYSTEM)
992 : 3382 : return rtl_allocateMemory(*pSize);
993 : :
994 : 714703 : size = RTL_MEMORY_ALIGN((*pSize), arena->m_quantum);
995 [ + - ]: 714703 : if (size > arena->m_qcache_max)
996 : : {
997 : : /* allocate from segment list */
998 : 714703 : rtl_arena_segment_type *segment = 0;
999 : :
1000 : 714703 : RTL_MEMORY_LOCK_ACQUIRE(&(arena->m_lock));
1001 [ + + ][ + - ]: 927753 : if (rtl_arena_segment_alloc (arena, size, &segment) ||
[ + - ][ + - ]
1002 [ + - ]: 213050 : rtl_arena_segment_create(arena, size, &segment) )
1003 : : {
1004 : : /* shrink to fit */
1005 : : sal_Size oversize;
1006 : :
1007 : : /* mark segment used */
1008 : : assert(segment->m_type == RTL_ARENA_SEGMENT_TYPE_FREE);
1009 : 714703 : segment->m_type = RTL_ARENA_SEGMENT_TYPE_USED;
1010 : :
1011 : : /* resize */
1012 : : assert(segment->m_size >= size);
1013 : 714703 : oversize = segment->m_size - size;
1014 [ + - ][ + + ]: 714703 : if (oversize >= SAL_MAX(arena->m_quantum, arena->m_qcache_max))
1015 : : {
1016 : 646003 : rtl_arena_segment_type * remainder = 0;
1017 [ + - ]: 646003 : rtl_arena_segment_get (arena, &remainder);
1018 [ + - ]: 646003 : if (remainder != 0)
1019 : : {
1020 : 646003 : segment->m_size = size;
1021 : :
1022 : 646003 : remainder->m_addr = segment->m_addr + segment->m_size;
1023 : 646003 : remainder->m_size = oversize;
1024 : 646003 : remainder->m_type = RTL_ARENA_SEGMENT_TYPE_FREE;
1025 : 646003 : QUEUE_INSERT_HEAD_NAMED(segment, remainder, s);
1026 : :
1027 : 646003 : rtl_arena_freelist_insert (arena, remainder);
1028 : : }
1029 : : }
1030 : :
1031 : 714703 : rtl_arena_hash_insert (arena, segment);
1032 : :
1033 : 714703 : (*pSize) = segment->m_size;
1034 : 714703 : addr = (void*)(segment->m_addr);
1035 : : }
1036 : 714703 : RTL_MEMORY_LOCK_RELEASE(&(arena->m_lock));
1037 : : }
1038 [ # # ]: 0 : else if (size > 0)
1039 : : {
1040 : : /* allocate from quantum cache(s) */
1041 : 0 : int index = (size >> arena->m_quantum_shift) - 1;
1042 : : assert(arena->m_qcache_ptr[index] != 0);
1043 : :
1044 : 0 : addr = rtl_cache_alloc (arena->m_qcache_ptr[index]);
1045 [ # # ]: 0 : if (addr != 0)
1046 : 0 : (*pSize) = size;
1047 : : }
1048 : : }
1049 : 724091 : return (addr);
1050 : : }
1051 : :
1052 : : /** rtl_arena_free()
1053 : : */
1054 : : void
1055 : 599226 : SAL_CALL rtl_arena_free (
1056 : : rtl_arena_type * arena,
1057 : : void * addr,
1058 : : sal_Size size
1059 : : ) SAL_THROW_EXTERN_C()
1060 : : {
1061 [ + - ]: 599226 : if (arena != 0)
1062 : : {
1063 [ + + ]: 599226 : if (alloc_mode == AMode_SYSTEM)
1064 : : {
1065 : 3382 : rtl_freeMemory(addr);
1066 : 3382 : return;
1067 : : }
1068 : :
1069 : 595844 : size = RTL_MEMORY_ALIGN(size, arena->m_quantum);
1070 [ + - ]: 595844 : if (size > arena->m_qcache_max)
1071 : : {
1072 : : /* free to segment list */
1073 : : rtl_arena_segment_type * segment;
1074 : :
1075 : 595844 : RTL_MEMORY_LOCK_ACQUIRE(&(arena->m_lock));
1076 : :
1077 : 595844 : segment = rtl_arena_hash_remove (arena, (sal_uIntPtr)(addr), size);
1078 [ + - ]: 595844 : if (segment != 0)
1079 : : {
1080 : : rtl_arena_segment_type *next, *prev;
1081 : :
1082 : : /* coalesce w/ adjacent free segment(s) */
1083 : 595844 : rtl_arena_segment_coalesce (arena, segment);
1084 : :
1085 : : /* determine (new) next and prev segment */
1086 : 595844 : next = segment->m_snext, prev = segment->m_sprev;
1087 : :
1088 : : /* entire span free when prev is a span, and next is either a span or a list head */
1089 [ + + ][ + + ]: 595844 : if (((prev->m_type == RTL_ARENA_SEGMENT_TYPE_SPAN)) &&
[ + + ]
1090 : : ((next->m_type == RTL_ARENA_SEGMENT_TYPE_SPAN) ||
1091 : : (next->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD)) )
1092 : : {
1093 : : assert(
1094 : : prev->m_addr == segment->m_addr
1095 : : && prev->m_size == segment->m_size);
1096 : :
1097 [ + - ]: 193933 : if (arena->m_source_free)
1098 : : {
1099 : 193933 : addr = (void*)(prev->m_addr);
1100 : 193933 : size = prev->m_size;
1101 : :
1102 : : /* remove from segment list */
1103 : 193933 : QUEUE_REMOVE_NAMED(segment, s);
1104 : :
1105 : : /* release segment descriptor */
1106 : 193933 : rtl_arena_segment_put (arena, &segment);
1107 : :
1108 : : /* remove from segment list */
1109 : 193933 : QUEUE_REMOVE_NAMED(prev, s);
1110 : :
1111 : : /* release (span) segment descriptor */
1112 : 193933 : rtl_arena_segment_put (arena, &prev);
1113 : :
1114 : : /* update stats, return span to source arena */
1115 : 193933 : arena->m_stats.m_mem_total -= size;
1116 : 193933 : RTL_MEMORY_LOCK_RELEASE(&(arena->m_lock));
1117 : :
1118 [ + - ]: 193933 : (arena->m_source_free)(arena->m_source_arena, addr, size);
1119 : : return;
1120 : : }
1121 : : }
1122 : :
1123 : : /* insert onto freelist */
1124 : 595844 : rtl_arena_freelist_insert (arena, segment);
1125 : : }
1126 : :
1127 : 401911 : RTL_MEMORY_LOCK_RELEASE(&(arena->m_lock));
1128 : : }
1129 [ # # ]: 0 : else if (size > 0)
1130 : : {
1131 : : /* free to quantum cache(s) */
1132 : 0 : int index = (size >> arena->m_quantum_shift) - 1;
1133 : : assert(arena->m_qcache_ptr[index] != 0);
1134 : :
1135 : 599226 : rtl_cache_free (arena->m_qcache_ptr[index], addr);
1136 : : }
1137 : : }
1138 : : }
1139 : :
1140 : : /* ================================================================= *
1141 : : *
1142 : : * machdep internals.
1143 : : *
1144 : : * ================================================================= */
1145 : :
1146 : : #if defined(SAL_UNX)
1147 : : #include <sys/mman.h>
1148 : : #elif defined(SAL_W32)
1149 : : #define MAP_FAILED 0
1150 : : #endif /* SAL_UNX || SAL_W32 */
1151 : :
1152 : : /** rtl_machdep_alloc()
1153 : : */
1154 : : static void *
1155 : 98110 : SAL_CALL rtl_machdep_alloc (
1156 : : rtl_arena_type * pArena,
1157 : : sal_Size * pSize
1158 : : )
1159 : : {
1160 : : void * addr;
1161 : 98110 : sal_Size size = (*pSize);
1162 : :
1163 : : assert(pArena == gp_machdep_arena);
1164 : :
1165 : : #if defined(SOLARIS) && defined(SPARC)
1166 : : /* see @ mmap(2) man pages */
1167 : : size += (pArena->m_quantum + pArena->m_quantum); /* "red-zone" pages */
1168 : : if (size > (4 << 20))
1169 : : size = RTL_MEMORY_P2ROUNDUP(size, (4 << 20));
1170 : : else if (size > (512 << 10))
1171 : : size = RTL_MEMORY_P2ROUNDUP(size, (512 << 10));
1172 : : else
1173 : : size = RTL_MEMORY_P2ROUNDUP(size, (64 << 10));
1174 : : size -= (pArena->m_quantum + pArena->m_quantum); /* "red-zone" pages */
1175 : : #else
1176 : : /* default allocation granularity */
1177 : 98110 : size = RTL_MEMORY_P2ROUNDUP(size, SAL_MAX(pArena->m_quantum, 64 << 10));
1178 : : #endif
1179 : :
1180 : : #if defined(SAL_UNX)
1181 : 98110 : addr = mmap (NULL, (size_t)(size), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
1182 : : #elif defined(SAL_W32)
1183 : : addr = VirtualAlloc (NULL, (SIZE_T)(size), MEM_COMMIT, PAGE_READWRITE);
1184 : : #endif /* (SAL_UNX || SAL_W32) */
1185 : :
1186 [ + - ]: 98110 : if (addr != MAP_FAILED)
1187 : : {
1188 : 98110 : pArena->m_stats.m_alloc += 1;
1189 : 98110 : pArena->m_stats.m_mem_total += size;
1190 : 98110 : pArena->m_stats.m_mem_alloc += size;
1191 : :
1192 : 98110 : (*pSize) = size;
1193 : 98110 : return (addr);
1194 : : }
1195 : 98110 : return (NULL);
1196 : : }
1197 : :
1198 : : /** rtl_machdep_free()
1199 : : */
1200 : : static void
1201 : 74878 : SAL_CALL rtl_machdep_free (
1202 : : rtl_arena_type * pArena,
1203 : : void * pAddr,
1204 : : sal_Size nSize
1205 : : )
1206 : : {
1207 : : assert(pArena == gp_machdep_arena);
1208 : :
1209 : 74878 : pArena->m_stats.m_free += 1;
1210 : 74878 : pArena->m_stats.m_mem_total -= nSize;
1211 : 74878 : pArena->m_stats.m_mem_alloc -= nSize;
1212 : :
1213 : : #if defined(SAL_UNX)
1214 : 74878 : (void) munmap(pAddr, nSize);
1215 : : #elif defined(SAL_W32)
1216 : : (void) VirtualFree ((LPVOID)(pAddr), (SIZE_T)(0), MEM_RELEASE);
1217 : : #endif /* (SAL_UNX || SAL_W32) */
1218 : 74878 : }
1219 : :
1220 : : /** rtl_machdep_pagesize()
1221 : : */
1222 : : static sal_Size
1223 : 16271 : rtl_machdep_pagesize()
1224 : : {
1225 : : #if defined(SAL_UNX)
1226 : : #if defined(FREEBSD) || defined(NETBSD) || defined(DRAGONFLY)
1227 : : return ((sal_Size)getpagesize());
1228 : : #else /* POSIX */
1229 : 16271 : return ((sal_Size)sysconf(_SC_PAGESIZE));
1230 : : #endif /* xBSD || POSIX */
1231 : : #elif defined(SAL_W32)
1232 : : SYSTEM_INFO info;
1233 : : GetSystemInfo (&info);
1234 : : return ((sal_Size)(info.dwPageSize));
1235 : : #endif /* (SAL_UNX || SAL_W32) */
1236 : : }
1237 : :
1238 : : /* ================================================================= *
1239 : : *
1240 : : * arena initialization.
1241 : : *
1242 : : * ================================================================= */
1243 : :
1244 : : void
1245 : 3003 : rtl_arena_init()
1246 : : {
1247 : : {
1248 : : /* list of arenas */
1249 : 3003 : RTL_MEMORY_LOCK_INIT(&(g_arena_list.m_lock));
1250 : 3003 : rtl_arena_constructor (&(g_arena_list.m_arena_head));
1251 : : }
1252 : : {
1253 : : /* machdep (pseudo) arena */
1254 : : static rtl_arena_type g_machdep_arena;
1255 : :
1256 : : assert(gp_machdep_arena == 0);
1257 : 3003 : rtl_arena_constructor (&g_machdep_arena);
1258 : :
1259 : : gp_machdep_arena = rtl_arena_activate (
1260 : : &g_machdep_arena,
1261 : : "rtl_machdep_arena",
1262 : : rtl_machdep_pagesize(),
1263 : : 0, /* no quantum caching */
1264 : : 0, 0, 0 /* no source */
1265 : 3003 : );
1266 : : assert(gp_machdep_arena != 0);
1267 : : }
1268 : : {
1269 : : /* default arena */
1270 : : static rtl_arena_type g_default_arena;
1271 : :
1272 : : assert(gp_default_arena == 0);
1273 : 3003 : rtl_arena_constructor (&g_default_arena);
1274 : :
1275 : : gp_default_arena = rtl_arena_activate (
1276 : : &g_default_arena,
1277 : : "rtl_default_arena",
1278 : : rtl_machdep_pagesize(),
1279 : : 0, /* no quantum caching */
1280 : : gp_machdep_arena, /* source */
1281 : : rtl_machdep_alloc,
1282 : : rtl_machdep_free
1283 : 3003 : );
1284 : : assert(gp_default_arena != 0);
1285 : : }
1286 : : {
1287 : : /* arena internal arena */
1288 : : static rtl_arena_type g_arena_arena;
1289 : :
1290 : : assert(gp_arena_arena == 0);
1291 : 3003 : rtl_arena_constructor (&g_arena_arena);
1292 : :
1293 : : gp_arena_arena = rtl_arena_activate (
1294 : : &g_arena_arena,
1295 : : "rtl_arena_internal_arena",
1296 : : 64, /* quantum */
1297 : : 0, /* no quantum caching */
1298 : : gp_default_arena, /* source */
1299 : : rtl_arena_alloc,
1300 : : rtl_arena_free
1301 : 3003 : );
1302 : : assert(gp_arena_arena != 0);
1303 : : }
1304 : : // SAL_INFO("sal", "rtl_arena_init completed");
1305 : 3003 : }
1306 : :
1307 : : /* ================================================================= */
1308 : :
1309 : : void
1310 : 3003 : rtl_arena_fini()
1311 : : {
1312 [ + - ]: 3003 : if (gp_arena_arena != 0)
1313 : : {
1314 : : rtl_arena_type * arena, * head;
1315 : :
1316 : 3003 : RTL_MEMORY_LOCK_ACQUIRE(&(g_arena_list.m_lock));
1317 : 3003 : head = &(g_arena_list.m_arena_head);
1318 : :
1319 [ + + ]: 12355 : for (arena = head->m_arena_next; arena != head; arena = arena->m_arena_next)
1320 : : {
1321 : : // SAL_INFO(
1322 : : // "sal",
1323 : : // "rtl_arena_fini(" << arena->m_name << "): allocs: "
1324 : : // << arena->m_stats.m_alloc << ", frees: "
1325 : : // << arena->m_stats.m_free << "; total: "
1326 : : // << arena->m_stats.m_mem_total << ", used: "
1327 : : // << arena->m_stats.m_mem_alloc);
1328 : : }
1329 : 3003 : RTL_MEMORY_LOCK_RELEASE(&(g_arena_list.m_lock));
1330 : : }
1331 : : // SAL_INFO("sal", "rtl_arena_fini completed");
1332 : 3003 : }
1333 : :
1334 : : /* ================================================================= */
1335 : :
1336 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|