LCOV - code coverage report
Current view: top level - sal/rtl - alloc_arena.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 347 392 88.5 %
Date: 2014-11-03 Functions: 26 26 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10