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

Generated by: LCOV version 1.10