LCOV - code coverage report
Current view: top level - libreoffice/sal/rtl/source - alloc_cache.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 468 494 94.7 %
Date: 2012-12-27 Functions: 34 34 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_cache.hxx"
      21             : #include "alloc_impl.hxx"
      22             : #include "alloc_arena.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             :  * cache internals.
      36             :  *
      37             :  * ================================================================= */
      38             : 
      39             : /** g_cache_list
      40             :  *  @internal
      41             :  */
      42             : struct rtl_cache_list_st
      43             : {
      44             :     rtl_memory_lock_type m_lock;
      45             :     rtl_cache_type       m_cache_head;
      46             : 
      47             : #if defined(SAL_UNX)
      48             :     pthread_t            m_update_thread;
      49             :     pthread_cond_t       m_update_cond;
      50             : #elif defined(SAL_W32)
      51             :     HANDLE               m_update_thread;
      52             :     HANDLE               m_update_cond;
      53             : #endif /* SAL_UNX || SAL_W32 */
      54             :     int                  m_update_done;
      55             : };
      56             : 
      57             : static rtl_cache_list_st g_cache_list;
      58             : 
      59             : 
      60             : /** gp_cache_arena
      61             :  *  provided for cache_type allocations, and hash_table resizing.
      62             :  *
      63             :  *  @internal
      64             :  */
      65             : static rtl_arena_type * gp_cache_arena = 0;
      66             : 
      67             : 
      68             : /** gp_cache_magazine_cache
      69             :  *  @internal
      70             :  */
      71             : static rtl_cache_type * gp_cache_magazine_cache = 0;
      72             : 
      73             : 
      74             : /** gp_cache_slab_cache
      75             :  *  @internal
      76             :  */
      77             : static rtl_cache_type * gp_cache_slab_cache = 0;
      78             : 
      79             : 
      80             : /** gp_cache_bufctl_cache
      81             :  *  @internal
      82             :  */
      83             : static rtl_cache_type * gp_cache_bufctl_cache = 0;
      84             : 
      85             : 
      86             : /* ================================================================= */
      87             : 
      88             : /** RTL_CACHE_HASH_INDEX()
      89             :  */
      90             : #define RTL_CACHE_HASH_INDEX_IMPL(a, s, q, m) \
      91             :      ((((a) + ((a) >> (s)) + ((a) >> ((s) << 1))) >> (q)) & (m))
      92             : 
      93             : #define RTL_CACHE_HASH_INDEX(cache, addr) \
      94             :     RTL_CACHE_HASH_INDEX_IMPL((addr), (cache)->m_hash_shift, (cache)->m_type_shift, ((cache)->m_hash_size - 1))
      95             : 
      96             : 
      97             : /** rtl_cache_hash_rescale()
      98             :  */
      99             : static void
     100          52 : rtl_cache_hash_rescale (
     101             :     rtl_cache_type * cache,
     102             :     sal_Size         new_size
     103             : )
     104             : {
     105             :     rtl_cache_bufctl_type ** new_table;
     106             :     sal_Size                 new_bytes;
     107             : 
     108          52 :     new_bytes = new_size * sizeof(rtl_cache_bufctl_type*);
     109          52 :     new_table = (rtl_cache_bufctl_type**)rtl_arena_alloc(gp_cache_arena, &new_bytes);
     110             : 
     111          52 :     if (new_table != 0)
     112             :     {
     113             :         rtl_cache_bufctl_type ** old_table;
     114             :         sal_Size                 old_size, i;
     115             : 
     116          52 :         memset (new_table, 0, new_bytes);
     117             : 
     118          52 :         RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_slab_lock));
     119             : 
     120          52 :         old_table = cache->m_hash_table;
     121          52 :         old_size  = cache->m_hash_size;
     122             : 
     123             :         // SAL_INFO(
     124             :         //  "sal.rtl",
     125             :         //  "rtl_cache_hash_rescale(" << cache->m_name << "): nbuf: "
     126             :         //      << (cache->m_slab_stats.m_alloc - cache->m_slab_stats.m_free)
     127             :         //      << " (ave: "
     128             :         //      << ((cache->m_slab_stats.m_alloc - cache->m_slab_stats.m_free)
     129             :         //          >> cache->m_hash_shift)
     130             :         //      << "), frees: " << cache->m_slab_stats.m_free << " [old_size: "
     131             :         //      << old_size << ", new_size: " << new_size << ']');
     132             : 
     133          52 :         cache->m_hash_table = new_table;
     134          52 :         cache->m_hash_size  = new_size;
     135          52 :         cache->m_hash_shift = highbit(cache->m_hash_size) - 1;
     136             : 
     137         468 :         for (i = 0; i < old_size; i++)
     138             :         {
     139         416 :             rtl_cache_bufctl_type * curr = old_table[i];
     140        7496 :             while (curr != 0)
     141             :             {
     142        6664 :                 rtl_cache_bufctl_type  * next = curr->m_next;
     143             :                 rtl_cache_bufctl_type ** head;
     144             : 
     145        6664 :                 head = &(cache->m_hash_table[RTL_CACHE_HASH_INDEX(cache, curr->m_addr)]);
     146        6664 :                 curr->m_next = (*head);
     147        6664 :                 (*head) = curr;
     148             : 
     149        6664 :                 curr = next;
     150             :             }
     151         416 :             old_table[i] = 0;
     152             :         }
     153             : 
     154          52 :         RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock));
     155             : 
     156          52 :         if (old_table != cache->m_hash_table_0)
     157             :         {
     158           0 :             sal_Size old_bytes = old_size * sizeof(rtl_cache_bufctl_type*);
     159           0 :             rtl_arena_free (gp_cache_arena, old_table, old_bytes);
     160             :         }
     161             :     }
     162          52 : }
     163             : 
     164             : /** rtl_cache_hash_insert()
     165             :  */
     166             : static RTL_MEMORY_INLINE sal_uIntPtr
     167       46205 : rtl_cache_hash_insert (
     168             :     rtl_cache_type *        cache,
     169             :     rtl_cache_bufctl_type * bufctl
     170             : )
     171             : {
     172             :     rtl_cache_bufctl_type ** ppHead;
     173             : 
     174       46205 :     ppHead = &(cache->m_hash_table[RTL_CACHE_HASH_INDEX(cache, bufctl->m_addr)]);
     175             : 
     176       46205 :     bufctl->m_next = (*ppHead);
     177       46205 :     (*ppHead) = bufctl;
     178             : 
     179       46205 :     return (bufctl->m_addr);
     180             : }
     181             : 
     182             : #if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
     183             : #pragma inline(rtl_cache_hash_insert)
     184             : #endif /* __SUNPRO_C */
     185             : 
     186             : 
     187             : /** rtl_cache_hash_remove()
     188             :  */
     189             : static rtl_cache_bufctl_type *
     190       40272 : rtl_cache_hash_remove (
     191             :     rtl_cache_type * cache,
     192             :     sal_uIntPtr      addr
     193             : )
     194             : {
     195             :     rtl_cache_bufctl_type ** ppHead;
     196             :     rtl_cache_bufctl_type  * bufctl;
     197       40272 :     sal_Size                 lookups = 0;
     198             : 
     199       40272 :     ppHead = &(cache->m_hash_table[RTL_CACHE_HASH_INDEX(cache, addr)]);
     200       82607 :     while ((bufctl = *ppHead) != 0)
     201             :     {
     202       42335 :         if (bufctl->m_addr == addr)
     203             :         {
     204       40272 :             *ppHead = bufctl->m_next, bufctl->m_next = 0;
     205       40272 :             break;
     206             :         }
     207             : 
     208        2063 :         lookups += 1;
     209        2063 :         ppHead = &(bufctl->m_next);
     210             :     }
     211             : 
     212             :     assert(bufctl != 0); // bad free
     213             : 
     214       40272 :     if (lookups > 1)
     215             :     {
     216         291 :         sal_Size nbuf = (sal_Size)(cache->m_slab_stats.m_alloc - cache->m_slab_stats.m_free);
     217         291 :         if (nbuf > 4 * cache->m_hash_size)
     218             :         {
     219          52 :             if (!(cache->m_features & RTL_CACHE_FEATURE_RESCALE))
     220             :             {
     221          52 :                 sal_Size ave = nbuf >> cache->m_hash_shift;
     222          52 :                 sal_Size new_size = cache->m_hash_size << (highbit(ave) - 1);
     223             : 
     224          52 :                 cache->m_features |= RTL_CACHE_FEATURE_RESCALE;
     225          52 :                 RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock));
     226          52 :                 rtl_cache_hash_rescale (cache, new_size);
     227          52 :                 RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_slab_lock));
     228          52 :                 cache->m_features &= ~RTL_CACHE_FEATURE_RESCALE;
     229             :             }
     230             :         }
     231             :     }
     232             : 
     233       40272 :     return (bufctl);
     234             : }
     235             : 
     236             : /* ================================================================= */
     237             : 
     238             : /** RTL_CACHE_SLAB()
     239             :  */
     240             : #define RTL_CACHE_SLAB(addr, size) \
     241             :     (((rtl_cache_slab_type*)(RTL_MEMORY_P2END((sal_uIntPtr)(addr), (size)))) - 1)
     242             : 
     243             : 
     244             : /** rtl_cache_slab_constructor()
     245             :  */
     246             : static int
     247      145408 : rtl_cache_slab_constructor (void * obj, SAL_UNUSED_PARAMETER void *)
     248             : {
     249      145408 :     rtl_cache_slab_type * slab = (rtl_cache_slab_type*)(obj);
     250             : 
     251      145408 :     QUEUE_START_NAMED(slab, slab_);
     252      145408 :     slab->m_ntypes = 0;
     253             : 
     254      145408 :     return (1);
     255             : }
     256             : 
     257             : 
     258             : /** rtl_cache_slab_destructor()
     259             :  */
     260             : static void
     261      145408 : rtl_cache_slab_destructor (void * obj, SAL_UNUSED_PARAMETER void *)
     262             : {
     263      145408 :     rtl_cache_slab_type * slab = static_cast< rtl_cache_slab_type * >(obj);
     264             :     assert(QUEUE_STARTED_NAMED(slab, slab_)); // assure removed from queue(s)
     265             :     assert(slab->m_ntypes == 0); // assure no longer referenced
     266             :     (void) slab; // avoid warnings
     267      145408 : }
     268             : 
     269             : 
     270             : /** rtl_cache_slab_create()
     271             :  *
     272             :  *  @precond cache->m_slab_lock released.
     273             :  */
     274             : static rtl_cache_slab_type *
     275      145408 : rtl_cache_slab_create (
     276             :     rtl_cache_type * cache
     277             : )
     278             : {
     279      145408 :     rtl_cache_slab_type * slab = 0;
     280             :     void *                addr;
     281             :     sal_Size              size;
     282             : 
     283      145408 :     size = cache->m_slab_size;
     284      145408 :     addr = rtl_arena_alloc (cache->m_source, &size);
     285      145408 :     if (addr != 0)
     286             :     {
     287             :         assert(size >= cache->m_slab_size);
     288             : 
     289      145408 :         if (cache->m_features & RTL_CACHE_FEATURE_HASH)
     290             :         {
     291             :             /* allocate slab struct from slab cache */
     292             :             assert(cache != gp_cache_slab_cache);
     293       18813 :             slab = (rtl_cache_slab_type*)rtl_cache_alloc (gp_cache_slab_cache);
     294             :         }
     295             :         else
     296             :         {
     297             :             /* construct embedded slab struct */
     298      126595 :             slab = RTL_CACHE_SLAB(addr, cache->m_slab_size);
     299      126595 :             (void) rtl_cache_slab_constructor (slab, 0);
     300             :         }
     301      145408 :         if (slab != 0)
     302             :         {
     303      145408 :             slab->m_data = (sal_uIntPtr)(addr);
     304             : 
     305             :             /* dynamic freelist initialization */
     306      145408 :             slab->m_bp = slab->m_data;
     307      145408 :             slab->m_sp = 0;
     308             :         }
     309             :         else
     310             :         {
     311           0 :             rtl_arena_free (cache->m_source, addr, size);
     312             :         }
     313             :     }
     314      145408 :     return (slab);
     315             : }
     316             : 
     317             : 
     318             : /** rtl_cache_slab_destroy()
     319             :  *
     320             :  *  @precond cache->m_slab_lock released.
     321             :  */
     322             : static void
     323      145408 : rtl_cache_slab_destroy (
     324             :     rtl_cache_type *      cache,
     325             :     rtl_cache_slab_type * slab
     326             : )
     327             : {
     328      145408 :     void *   addr   = (void*)(slab->m_data);
     329      145408 :     sal_Size refcnt = slab->m_ntypes; slab->m_ntypes = 0;
     330             : 
     331      145408 :     if (cache->m_features & RTL_CACHE_FEATURE_HASH)
     332             :     {
     333             :         /* cleanup bufctl(s) for free buffer(s) */
     334       18813 :         sal_Size ntypes = (slab->m_bp - slab->m_data) / cache->m_type_size;
     335       59085 :         for (ntypes -= refcnt; slab->m_sp != 0; ntypes--)
     336             :         {
     337       40272 :             rtl_cache_bufctl_type * bufctl = slab->m_sp;
     338             : 
     339             :             /* pop from freelist */
     340       40272 :             slab->m_sp = bufctl->m_next, bufctl->m_next = 0;
     341             : 
     342             :             /* return bufctl struct to bufctl cache */
     343       40272 :             rtl_cache_free (gp_cache_bufctl_cache, bufctl);
     344             :         }
     345             :         assert(ntypes == 0);
     346             : 
     347             :         /* return slab struct to slab cache */
     348       18813 :         rtl_cache_free (gp_cache_slab_cache, slab);
     349             :     }
     350             :     else
     351             :     {
     352             :         /* destruct embedded slab struct */
     353      126595 :         rtl_cache_slab_destructor (slab, 0);
     354             :     }
     355             : 
     356      145408 :     if ((refcnt == 0) || (cache->m_features & RTL_CACHE_FEATURE_BULKDESTROY))
     357             :     {
     358             :         /* free memory */
     359       84117 :         rtl_arena_free (cache->m_source, addr, cache->m_slab_size);
     360             :     }
     361      145408 : }
     362             : 
     363             : 
     364             : /** rtl_cache_slab_populate()
     365             :  *
     366             :  *  @precond cache->m_slab_lock acquired.
     367             :  */
     368             : static int
     369      145408 : rtl_cache_slab_populate (
     370             :     rtl_cache_type * cache
     371             : )
     372             : {
     373             :     rtl_cache_slab_type * slab;
     374             : 
     375      145408 :     RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock));
     376      145408 :     slab = rtl_cache_slab_create (cache);
     377      145408 :     RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_slab_lock));
     378      145408 :     if (slab != 0)
     379             :     {
     380             :         /* update buffer start addr w/ current color */
     381      145408 :         slab->m_bp += cache->m_ncolor;
     382             : 
     383             :         /* update color for next slab */
     384      145408 :         cache->m_ncolor += cache->m_type_align;
     385      145408 :         if (cache->m_ncolor > cache->m_ncolor_max)
     386       15657 :             cache->m_ncolor = 0;
     387             : 
     388             :         /* update stats */
     389      145408 :         cache->m_slab_stats.m_mem_total += cache->m_slab_size;
     390             : 
     391             :         /* insert onto 'free' queue */
     392      145408 :         QUEUE_INSERT_HEAD_NAMED(&(cache->m_free_head), slab, slab_);
     393             :     }
     394      145408 :     return (slab != 0);
     395             : }
     396             : 
     397             : /* ================================================================= */
     398             : 
     399             : /** rtl_cache_slab_alloc()
     400             :  *
     401             :  *  Allocate a buffer from slab layer; used by magazine layer.
     402             :  */
     403             : static void *
     404     7080916 : rtl_cache_slab_alloc (
     405             :     rtl_cache_type * cache
     406             : )
     407             : {
     408     7080916 :     void                * addr = 0;
     409             :     rtl_cache_slab_type * head;
     410             : 
     411     7080916 :     RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_slab_lock));
     412             : 
     413     7080916 :     head = &(cache->m_free_head);
     414     7080916 :     if ((head->m_slab_next != head) || rtl_cache_slab_populate (cache))
     415             :     {
     416             :         rtl_cache_slab_type   * slab;
     417             :         rtl_cache_bufctl_type * bufctl;
     418             : 
     419     7080916 :         slab = head->m_slab_next;
     420             :         assert(slab->m_ntypes < cache->m_ntypes);
     421             : 
     422     7080916 :         if (slab->m_sp == 0)
     423             :         {
     424             :             /* initialize bufctl w/ current 'slab->m_bp' */
     425             :             assert(slab->m_bp < slab->m_data + cache->m_ntypes * cache->m_type_size + cache->m_ncolor_max);
     426     7080805 :             if (cache->m_features & RTL_CACHE_FEATURE_HASH)
     427             :             {
     428             :                 /* allocate bufctl */
     429             :                 assert(cache != gp_cache_bufctl_cache);
     430       46205 :                 bufctl = (rtl_cache_bufctl_type*)rtl_cache_alloc (gp_cache_bufctl_cache);
     431       46205 :                 if (bufctl == 0)
     432             :                 {
     433             :                     /* out of memory */
     434           0 :                     RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock));
     435           0 :                     return (0);
     436             :                 }
     437             : 
     438       46205 :                 bufctl->m_addr = slab->m_bp;
     439       46205 :                 bufctl->m_slab = (sal_uIntPtr)(slab);
     440             :             }
     441             :             else
     442             :             {
     443             :                 /* embedded bufctl */
     444     7034600 :                 bufctl = (rtl_cache_bufctl_type*)(slab->m_bp);
     445             :             }
     446     7080805 :             bufctl->m_next = 0;
     447             : 
     448             :             /* update 'slab->m_bp' to next free buffer */
     449     7080805 :             slab->m_bp += cache->m_type_size;
     450             : 
     451             :             /* assign bufctl to freelist */
     452     7080805 :             slab->m_sp = bufctl;
     453             :         }
     454             : 
     455             :         /* pop front */
     456     7080916 :         bufctl = slab->m_sp;
     457     7080916 :         slab->m_sp = bufctl->m_next;
     458             : 
     459             :         /* increment usage, check for full slab */
     460     7080916 :         if ((slab->m_ntypes += 1) == cache->m_ntypes)
     461             :         {
     462             :             /* remove from 'free' queue */
     463       94819 :             QUEUE_REMOVE_NAMED(slab, slab_);
     464             : 
     465             :             /* insert onto 'used' queue (tail) */
     466       94819 :             QUEUE_INSERT_TAIL_NAMED(&(cache->m_used_head), slab, slab_);
     467             :         }
     468             : 
     469             :         /* update stats */
     470     7080916 :         cache->m_slab_stats.m_alloc     += 1;
     471     7080916 :         cache->m_slab_stats.m_mem_alloc += cache->m_type_size;
     472             : 
     473     7080916 :         if (cache->m_features & RTL_CACHE_FEATURE_HASH)
     474       46205 :             addr = (void*)rtl_cache_hash_insert (cache, bufctl);
     475             :         else
     476     7034711 :             addr = bufctl;
     477             :     }
     478             : 
     479     7080916 :     RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock));
     480     7080916 :     return (addr);
     481             : }
     482             : 
     483             : 
     484             : /** rtl_cache_slab_free()
     485             :  *
     486             :  *  Return a buffer to slab layer; used by magazine layer.
     487             :  */
     488             : static void
     489     4478682 : rtl_cache_slab_free (
     490             :     rtl_cache_type * cache,
     491             :     void *           addr
     492             : )
     493             : {
     494             :     rtl_cache_bufctl_type * bufctl;
     495             :     rtl_cache_slab_type   * slab;
     496             : 
     497     4478682 :     RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_slab_lock));
     498             : 
     499             :     /* determine slab from addr */
     500     4478682 :     if (cache->m_features & RTL_CACHE_FEATURE_HASH)
     501             :     {
     502       40272 :         bufctl = rtl_cache_hash_remove (cache, (sal_uIntPtr)(addr));
     503       40272 :         slab = (bufctl != 0) ? (rtl_cache_slab_type*)(bufctl->m_slab) : 0;
     504             :     }
     505             :     else
     506             :     {
     507             :         /* embedded slab struct */
     508     4438410 :         bufctl = (rtl_cache_bufctl_type*)(addr);
     509     4438410 :         slab = RTL_CACHE_SLAB(addr, cache->m_slab_size);
     510             :     }
     511             : 
     512     4478682 :     if (slab != 0)
     513             :     {
     514             :         /* check for full slab */
     515     4478682 :         if (slab->m_ntypes == cache->m_ntypes)
     516             :         {
     517             :             /* remove from 'used' queue */
     518       70264 :             QUEUE_REMOVE_NAMED(slab, slab_);
     519             : 
     520             :             /* insert onto 'free' queue (head) */
     521       70264 :             QUEUE_INSERT_HEAD_NAMED(&(cache->m_free_head), slab, slab_);
     522             :         }
     523             : 
     524             :         /* push front */
     525     4478682 :         bufctl->m_next = slab->m_sp;
     526     4478682 :         slab->m_sp = bufctl;
     527             : 
     528             :         /* update stats */
     529     4478682 :         cache->m_slab_stats.m_free      += 1;
     530     4478682 :         cache->m_slab_stats.m_mem_alloc -= cache->m_type_size;
     531             : 
     532             :         /* decrement usage, check for empty slab */
     533     4478682 :         if ((slab->m_ntypes -= 1) == 0)
     534             :         {
     535             :             /* remove from 'free' queue */
     536       84117 :             QUEUE_REMOVE_NAMED(slab, slab_);
     537             : 
     538             :             /* update stats */
     539       84117 :             cache->m_slab_stats.m_mem_total -= cache->m_slab_size;
     540             : 
     541             :             /* free 'empty' slab */
     542       84117 :             RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock));
     543       84117 :             rtl_cache_slab_destroy (cache, slab);
     544     4562799 :             return;
     545             :         }
     546             :     }
     547             : 
     548     4394565 :     RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock));
     549             : }
     550             : 
     551             : /* ================================================================= */
     552             : 
     553             : /** rtl_cache_magazine_constructor()
     554             :  */
     555             : static int
     556      106237 : rtl_cache_magazine_constructor (void * obj, SAL_UNUSED_PARAMETER void *)
     557             : {
     558      106237 :     rtl_cache_magazine_type * mag = (rtl_cache_magazine_type*)(obj);
     559             :     /* @@@ sal_Size size = (sal_Size)(arg); @@@ */
     560             : 
     561      106237 :     mag->m_mag_next = 0;
     562      106237 :     mag->m_mag_size = RTL_CACHE_MAGAZINE_SIZE;
     563      106237 :     mag->m_mag_used = 0;
     564             : 
     565      106237 :     return (1);
     566             : }
     567             : 
     568             : 
     569             : /** rtl_cache_magazine_destructor()
     570             :  */
     571             : static void
     572      106209 : rtl_cache_magazine_destructor (void * obj, SAL_UNUSED_PARAMETER void *)
     573             : {
     574             :     rtl_cache_magazine_type * mag = static_cast< rtl_cache_magazine_type * >(
     575      106209 :         obj);
     576             :     assert(mag->m_mag_next == 0); // assure removed from queue(s)
     577             :     assert(mag->m_mag_used == 0); // assure no longer referenced
     578             :     (void) mag; // avoid warnings
     579      106209 : }
     580             : 
     581             : 
     582             : /** rtl_cache_magazine_clear()
     583             :  */
     584             : static void
     585      115104 : rtl_cache_magazine_clear (
     586             :     rtl_cache_type *          cache,
     587             :     rtl_cache_magazine_type * mag
     588             : )
     589             : {
     590     4591337 :     for (; mag->m_mag_used > 0; --mag->m_mag_used)
     591             :     {
     592     4476233 :         void * obj = mag->m_objects[mag->m_mag_used - 1];
     593     4476233 :         mag->m_objects[mag->m_mag_used - 1] = 0;
     594             : 
     595     4476233 :         if (cache->m_destructor != 0)
     596             :         {
     597             :             /* destruct object */
     598      122573 :             (cache->m_destructor)(obj, cache->m_userarg);
     599             :         }
     600             : 
     601             :         /* return buffer to slab layer */
     602     4476233 :         rtl_cache_slab_free (cache, obj);
     603             :     }
     604      115104 : }
     605             : 
     606             : /* ================================================================= */
     607             : 
     608             : /** rtl_cache_depot_enqueue()
     609             :  *
     610             :  *  @precond cache->m_depot_lock acquired.
     611             :  */
     612             : static RTL_MEMORY_INLINE void
     613      196434 : rtl_cache_depot_enqueue (
     614             :     rtl_cache_depot_type *    depot,
     615             :     rtl_cache_magazine_type * mag
     616             : )
     617             : {
     618             :     /* enqueue empty magazine */
     619      196434 :     mag->m_mag_next = depot->m_mag_next;
     620      196434 :     depot->m_mag_next = mag;
     621             : 
     622             :     /* update depot stats */
     623      196434 :     depot->m_mag_count++;
     624      196434 : }
     625             : 
     626             : #if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
     627             : #pragma inline(rtl_cache_depot_enqueue)
     628             : #endif /* __SUNPRO_C */
     629             : 
     630             : 
     631             : /** rtl_cache_depot_dequeue()
     632             :  *
     633             :  *  @precond cache->m_depot_lock acquired.
     634             :  */
     635             : static RTL_MEMORY_INLINE rtl_cache_magazine_type *
     636     7125171 : rtl_cache_depot_dequeue (
     637             :     rtl_cache_depot_type * depot
     638             : )
     639             : {
     640     7125171 :     rtl_cache_magazine_type * mag = 0;
     641     7125171 :     if (depot->m_mag_count > 0)
     642             :     {
     643             :         /* dequeue magazine */
     644             :         assert(depot->m_mag_next != 0);
     645             : 
     646      196434 :         mag = depot->m_mag_next;
     647      196434 :         depot->m_mag_next = mag->m_mag_next;
     648      196434 :         mag->m_mag_next = 0;
     649             : 
     650             :         /* update depot stats */
     651      196434 :         depot->m_mag_count--;
     652      196434 :         if(depot->m_curr_min > depot->m_mag_count)
     653             :         {
     654        5344 :             depot->m_curr_min = depot->m_mag_count;
     655             :         }
     656             :     }
     657     7125171 :     return (mag);
     658             : }
     659             : 
     660             : #if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
     661             : #pragma inline(rtl_cache_depot_dequeue)
     662             : #endif /* __SUNPRO_C */
     663             : 
     664             : 
     665             : /** rtl_cache_depot_exchange_alloc()
     666             :  *
     667             :  *  @precond cache->m_depot_lock acquired.
     668             :  */
     669             : static RTL_MEMORY_INLINE rtl_cache_magazine_type *
     670     6699250 : rtl_cache_depot_exchange_alloc (
     671             :     rtl_cache_type *          cache,
     672             :     rtl_cache_magazine_type * empty
     673             : )
     674             : {
     675             :     rtl_cache_magazine_type * full;
     676             : 
     677             :     assert((empty == 0) || (empty->m_mag_used == 0));
     678             : 
     679             :     /* dequeue full magazine */
     680     6699250 :     full = rtl_cache_depot_dequeue (&(cache->m_depot_full));
     681     6699250 :     if ((full != 0) && (empty != 0))
     682             :     {
     683             :         /* enqueue empty magazine */
     684       11312 :         rtl_cache_depot_enqueue (&(cache->m_depot_empty), empty);
     685             :     }
     686             : 
     687             :     assert((full == 0) || (full->m_mag_used > 0));
     688             : 
     689     6699250 :     return (full);
     690             : }
     691             : 
     692             : #if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
     693             : #pragma inline(rtl_cache_depot_exchange_alloc)
     694             : #endif /* __SUNPRO_C */
     695             : 
     696             : 
     697             : /** rtl_cache_depot_exchange_free()
     698             :  *
     699             :  *  @precond cache->m_depot_lock acquired.
     700             :  */
     701             : static RTL_MEMORY_INLINE rtl_cache_magazine_type *
     702      243854 : rtl_cache_depot_exchange_free (
     703             :     rtl_cache_type *          cache,
     704             :     rtl_cache_magazine_type * full
     705             : )
     706             : {
     707             :     rtl_cache_magazine_type * empty;
     708             : 
     709             :     assert((full == 0) || (full->m_mag_used > 0));
     710             : 
     711             :     /* dequeue empty magazine */
     712      243854 :     empty = rtl_cache_depot_dequeue (&(cache->m_depot_empty));
     713      243854 :     if ((empty != 0) && (full != 0))
     714             :     {
     715             :         /* enqueue full magazine */
     716       70012 :         rtl_cache_depot_enqueue (&(cache->m_depot_full), full);
     717             :     }
     718             : 
     719             :     assert((empty == 0) || (empty->m_mag_used == 0));
     720             : 
     721      243854 :     return (empty);
     722             : }
     723             : 
     724             : #if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
     725             : #pragma inline(rtl_cache_depot_exchange_free)
     726             : #endif /* __SUNPRO_C */
     727             : 
     728             : 
     729             : /** rtl_cache_depot_populate()
     730             :  *
     731             :  *  @precond cache->m_depot_lock acquired.
     732             :  */
     733             : static int
     734      117559 : rtl_cache_depot_populate (
     735             :     rtl_cache_type * cache
     736             : )
     737             : {
     738      117559 :     rtl_cache_magazine_type * empty = 0;
     739             : 
     740      117559 :     if (cache->m_magazine_cache != 0)
     741             :     {
     742             :         /* allocate new empty magazine */
     743      115110 :         RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock));
     744      115110 :         empty = (rtl_cache_magazine_type*)rtl_cache_alloc (cache->m_magazine_cache);
     745      115110 :         RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_depot_lock));
     746      115110 :         if (empty != 0)
     747             :         {
     748             :             /* enqueue (new) empty magazine */
     749      115110 :             rtl_cache_depot_enqueue (&(cache->m_depot_empty), empty);
     750             :         }
     751             :     }
     752      117559 :     return (empty != 0);
     753             : }
     754             : 
     755             : /* ================================================================= */
     756             : 
     757             : /** rtl_cache_constructor()
     758             :  */
     759             : static int
     760       62895 : rtl_cache_constructor (void * obj)
     761             : {
     762       62895 :     rtl_cache_type * cache = (rtl_cache_type*)(obj);
     763             : 
     764       62895 :     memset (cache, 0, sizeof(rtl_cache_type));
     765             : 
     766             :     /* linkage */
     767       62895 :     QUEUE_START_NAMED(cache, cache_);
     768             : 
     769             :     /* slab layer */
     770       62895 :     (void)RTL_MEMORY_LOCK_INIT(&(cache->m_slab_lock));
     771             : 
     772       62895 :     QUEUE_START_NAMED(&(cache->m_free_head), slab_);
     773       62895 :     QUEUE_START_NAMED(&(cache->m_used_head), slab_);
     774             : 
     775       62895 :     cache->m_hash_table = cache->m_hash_table_0;
     776       62895 :     cache->m_hash_size  = RTL_CACHE_HASH_SIZE;
     777       62895 :     cache->m_hash_shift = highbit(cache->m_hash_size) - 1;
     778             : 
     779             :     /* depot layer */
     780       62895 :     (void)RTL_MEMORY_LOCK_INIT(&(cache->m_depot_lock));
     781             : 
     782       62895 :     return (1);
     783             : }
     784             : 
     785             : /** rtl_cache_destructor()
     786             :  */
     787             : static void
     788       61620 : rtl_cache_destructor (void * obj)
     789             : {
     790       61620 :     rtl_cache_type * cache = (rtl_cache_type*)(obj);
     791             : 
     792             :     /* linkage */
     793             :     assert(QUEUE_STARTED_NAMED(cache, cache_));
     794             : 
     795             :     /* slab layer */
     796       61620 :     (void)RTL_MEMORY_LOCK_DESTROY(&(cache->m_slab_lock));
     797             : 
     798             :     assert(QUEUE_STARTED_NAMED(&(cache->m_free_head), slab_));
     799             :     assert(QUEUE_STARTED_NAMED(&(cache->m_used_head), slab_));
     800             : 
     801             :     assert(cache->m_hash_table == cache->m_hash_table_0);
     802             :     assert(cache->m_hash_size  == RTL_CACHE_HASH_SIZE);
     803             :     assert(cache->m_hash_shift == (sal_Size)(highbit(cache->m_hash_size) - 1));
     804             : 
     805             :     /* depot layer */
     806       61620 :     (void)RTL_MEMORY_LOCK_DESTROY(&(cache->m_depot_lock));
     807       61620 : }
     808             : 
     809             : /* ================================================================= */
     810             : 
     811             : /** rtl_cache_activate()
     812             :  */
     813             : static rtl_cache_type *
     814       61620 : rtl_cache_activate (
     815             :     rtl_cache_type * cache,
     816             :     const char *     name,
     817             :     size_t           objsize,
     818             :     size_t           objalign,
     819             :     int  (SAL_CALL * constructor)(void * obj, void * userarg),
     820             :     void (SAL_CALL * destructor) (void * obj, void * userarg),
     821             :     void (SAL_CALL * reclaim)    (void * userarg),
     822             :     void *           userarg,
     823             :     rtl_arena_type * source,
     824             :     int              flags
     825             : )
     826             : {
     827             :     assert(cache != 0);
     828       61620 :     if (cache != 0)
     829             :     {
     830             :         sal_Size slabsize;
     831             : 
     832       61620 :         snprintf (cache->m_name, sizeof(cache->m_name), "%s", name);
     833             : 
     834             :         /* ensure minimum size (embedded bufctl linkage) */
     835       61620 :         if(objsize < sizeof(rtl_cache_bufctl_type*))
     836             :         {
     837           0 :             objsize = sizeof(rtl_cache_bufctl_type*);
     838             :         }
     839             : 
     840       61620 :         if (objalign == 0)
     841             :         {
     842             :             /* determine default alignment */
     843       61620 :             if (objsize >= RTL_MEMORY_ALIGNMENT_8)
     844       61620 :                 objalign = RTL_MEMORY_ALIGNMENT_8;
     845             :             else
     846           0 :                 objalign = RTL_MEMORY_ALIGNMENT_4;
     847             :         }
     848             :         else
     849             :         {
     850             :             /* ensure minimum alignment */
     851           0 :             if(objalign < RTL_MEMORY_ALIGNMENT_4)
     852             :             {
     853           0 :                 objalign = RTL_MEMORY_ALIGNMENT_4;
     854             :             }
     855             :         }
     856             :         assert(RTL_MEMORY_ISP2(objalign));
     857             : 
     858       61620 :         cache->m_type_size  = objsize = RTL_MEMORY_P2ROUNDUP(objsize, objalign);
     859       61620 :         cache->m_type_align = objalign;
     860       61620 :         cache->m_type_shift = highbit(cache->m_type_size) - 1;
     861             : 
     862       61620 :         cache->m_constructor = constructor;
     863       61620 :         cache->m_destructor  = destructor;
     864       61620 :         cache->m_reclaim     = reclaim;
     865       61620 :         cache->m_userarg     = userarg;
     866             : 
     867             :         /* slab layer */
     868       61620 :         cache->m_source = source;
     869             : 
     870       61620 :         slabsize = source->m_quantum; /* minimum slab size */
     871       61620 :         if (flags & RTL_CACHE_FLAG_QUANTUMCACHE)
     872             :         {
     873             :             /* next power of 2 above 3 * qcache_max */
     874           0 :             if(slabsize < (1UL << highbit(3 * source->m_qcache_max)))
     875             :             {
     876           0 :                 slabsize = (1UL << highbit(3 * source->m_qcache_max));
     877             :             }
     878             :         }
     879             :         else
     880             :         {
     881             :             /* waste at most 1/8 of slab */
     882       61620 :             if(slabsize < cache->m_type_size * 8)
     883             :             {
     884       26651 :                 slabsize = cache->m_type_size * 8;
     885             :             }
     886             :         }
     887             : 
     888       61620 :         slabsize = RTL_MEMORY_P2ROUNDUP(slabsize, source->m_quantum);
     889       61620 :         if (!RTL_MEMORY_ISP2(slabsize))
     890       14030 :             slabsize = 1UL << highbit(slabsize);
     891       61620 :         cache->m_slab_size = slabsize;
     892             : 
     893       61620 :         if (cache->m_slab_size > source->m_quantum)
     894             :         {
     895             :             assert(gp_cache_slab_cache != 0);
     896             :             assert(gp_cache_bufctl_cache != 0);
     897             : 
     898       26651 :             cache->m_features  |= RTL_CACHE_FEATURE_HASH;
     899       26651 :             cache->m_ntypes     = cache->m_slab_size / cache->m_type_size;
     900       26651 :             cache->m_ncolor_max = cache->m_slab_size % cache->m_type_size;
     901             :         }
     902             :         else
     903             :         {
     904             :             /* embedded slab struct */
     905       34969 :             cache->m_ntypes     = (cache->m_slab_size - sizeof(rtl_cache_slab_type)) / cache->m_type_size;
     906       34969 :             cache->m_ncolor_max = (cache->m_slab_size - sizeof(rtl_cache_slab_type)) % cache->m_type_size;
     907             :         }
     908             : 
     909             :         assert(cache->m_ntypes > 0);
     910       61620 :         cache->m_ncolor = 0;
     911             : 
     912       61620 :         if (flags & RTL_CACHE_FLAG_BULKDESTROY)
     913             :         {
     914             :             /* allow bulk slab delete upon cache deactivation */
     915           0 :             cache->m_features |= RTL_CACHE_FEATURE_BULKDESTROY;
     916             :         }
     917             : 
     918             :         /* magazine layer */
     919       61620 :         if (!(flags & RTL_CACHE_FLAG_NOMAGAZINE))
     920             :         {
     921             :             assert(gp_cache_magazine_cache != 0);
     922       60345 :             cache->m_magazine_cache = gp_cache_magazine_cache;
     923             :         }
     924             : 
     925             :         /* insert into cache list */
     926       61620 :         RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock));
     927       61620 :         QUEUE_INSERT_TAIL_NAMED(&(g_cache_list.m_cache_head), cache, cache_);
     928       61620 :         RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock));
     929             :     }
     930       61620 :     return (cache);
     931             : }
     932             : 
     933             : /** rtl_cache_deactivate()
     934             :  */
     935             : static void
     936       61620 : rtl_cache_deactivate (
     937             :     rtl_cache_type * cache
     938             : )
     939             : {
     940       61620 :     int active = 1;
     941             : 
     942             :     /* remove from cache list */
     943       61620 :     RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock));
     944       61620 :     active = QUEUE_STARTED_NAMED(cache, cache_) == 0;
     945       61620 :     QUEUE_REMOVE_NAMED(cache, cache_);
     946       61620 :     RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock));
     947             : 
     948             :     assert(active); // orphaned cache
     949             :     (void)active;
     950             : 
     951             :     /* cleanup magazine layer */
     952       61620 :     if (cache->m_magazine_cache != 0)
     953             :     {
     954             :         rtl_cache_type *          mag_cache;
     955             :         rtl_cache_magazine_type * mag;
     956             : 
     957             :         /* prevent recursion */
     958       61620 :         mag_cache = cache->m_magazine_cache, cache->m_magazine_cache = 0;
     959             : 
     960             :         /* cleanup cpu layer */
     961       61620 :         if ((mag = cache->m_cpu_curr) != 0)
     962             :         {
     963       50972 :             cache->m_cpu_curr = 0;
     964       50972 :             rtl_cache_magazine_clear (cache, mag);
     965       50972 :             rtl_cache_free (mag_cache, mag);
     966             :         }
     967       61620 :         if ((mag = cache->m_cpu_prev) != 0)
     968             :         {
     969        5305 :             cache->m_cpu_prev = 0;
     970        5305 :             rtl_cache_magazine_clear (cache, mag);
     971        5305 :             rtl_cache_free (mag_cache, mag);
     972             :         }
     973             : 
     974             :         /* cleanup depot layer */
     975      181800 :         while ((mag = rtl_cache_depot_dequeue(&(cache->m_depot_full))) != 0)
     976             :         {
     977       58560 :             rtl_cache_magazine_clear (cache, mag);
     978       58560 :             rtl_cache_free (mag_cache, mag);
     979             :         }
     980      123280 :         while ((mag = rtl_cache_depot_dequeue(&(cache->m_depot_empty))) != 0)
     981             :         {
     982          40 :             rtl_cache_magazine_clear (cache, mag);
     983          40 :             rtl_cache_free (mag_cache, mag);
     984             :         }
     985             :     }
     986             : 
     987             :     // SAL_INFO(
     988             :     //  "sal.rtl",
     989             :     //  "rtl_cache_deactivate(" << cache->m_name << "): [slab]: allocs: "
     990             :     //      << cache->m_slab_stats.m_alloc << ", frees: "
     991             :     //      << cache->m_slab_stats.m_free << "; total: "
     992             :     //      << cache->m_slab_stats.m_mem_total << ", used: "
     993             :     //      << cache->m_slab_stats.m_mem_alloc << "; [cpu]: allocs: "
     994             :     //      << cache->m_cpu_stats.m_alloc << ", frees: "
     995             :     //      << cache->m_cpu_stats.m_free << "; [total]: allocs: "
     996             :     //      << (cache->m_slab_stats.m_alloc + cache->m_cpu_stats.m_alloc)
     997             :     //      << ", frees: "
     998             :     //      << (cache->m_slab_stats.m_free + cache->m_cpu_stats.m_free));
     999             : 
    1000             :     /* cleanup slab layer */
    1001       61620 :     if (cache->m_slab_stats.m_alloc > cache->m_slab_stats.m_free)
    1002             :     {
    1003             :         // SAL_INFO(
    1004             :         //  "sal.rtl",
    1005             :         //  "rtl_cache_deactivate(" << cache->m_name << "): cleaning up "
    1006             :         //      << (cache->m_slab_stats.m_alloc - cache->m_slab_stats.m_free)
    1007             :         //      << " leaked buffer(s) [" << cache->m_slab_stats.m_mem_alloc
    1008             :         //      << " bytes] [" << cache->m_slab_stats.m_mem_total << " total]");
    1009             : 
    1010       14010 :         if (cache->m_features & RTL_CACHE_FEATURE_HASH)
    1011             :         {
    1012             :             /* cleanup bufctl(s) for leaking buffer(s) */
    1013         858 :             sal_Size i, n = cache->m_hash_size;
    1014       12458 :             for (i = 0; i < n; i++)
    1015             :             {
    1016             :                 rtl_cache_bufctl_type * bufctl;
    1017       29133 :                 while ((bufctl = cache->m_hash_table[i]) != 0)
    1018             :                 {
    1019             :                     /* pop from hash table */
    1020        5933 :                     cache->m_hash_table[i] = bufctl->m_next, bufctl->m_next = 0;
    1021             : 
    1022             :                     /* return to bufctl cache */
    1023        5933 :                     rtl_cache_free (gp_cache_bufctl_cache, bufctl);
    1024             :                 }
    1025             :             }
    1026             :         }
    1027             :         {
    1028             :             /* force cleanup of remaining slabs */
    1029             :             rtl_cache_slab_type *head, *slab;
    1030             : 
    1031       14010 :             head = &(cache->m_used_head);
    1032       38565 :             for (slab = head->m_slab_next; slab != head; slab = head->m_slab_next)
    1033             :             {
    1034             :                 /* remove from 'used' queue */
    1035       24555 :                 QUEUE_REMOVE_NAMED(slab, slab_);
    1036             : 
    1037             :                 /* update stats */
    1038       24555 :                 cache->m_slab_stats.m_mem_total -= cache->m_slab_size;
    1039             : 
    1040             :                 /* free slab */
    1041       24555 :                 rtl_cache_slab_destroy (cache, slab);
    1042             :             }
    1043             : 
    1044       14010 :             head = &(cache->m_free_head);
    1045       50746 :             for (slab = head->m_slab_next; slab != head; slab = head->m_slab_next)
    1046             :             {
    1047             :                 /* remove from 'free' queue */
    1048       36736 :                 QUEUE_REMOVE_NAMED(slab, slab_);
    1049             : 
    1050             :                 /* update stats */
    1051       36736 :                 cache->m_slab_stats.m_mem_total -= cache->m_slab_size;
    1052             : 
    1053             :                 /* free slab */
    1054       36736 :                 rtl_cache_slab_destroy (cache, slab);
    1055             :             }
    1056             :         }
    1057             :     }
    1058             : 
    1059       61620 :     if (cache->m_hash_table != cache->m_hash_table_0)
    1060             :     {
    1061             :         rtl_arena_free (
    1062             :             gp_cache_arena,
    1063             :             cache->m_hash_table,
    1064          52 :             cache->m_hash_size * sizeof(rtl_cache_bufctl_type*));
    1065             : 
    1066          52 :         cache->m_hash_table = cache->m_hash_table_0;
    1067          52 :         cache->m_hash_size  = RTL_CACHE_HASH_SIZE;
    1068          52 :         cache->m_hash_shift = highbit(cache->m_hash_size) - 1;
    1069             :     }
    1070       61620 : }
    1071             : 
    1072             : /* ================================================================= *
    1073             :  *
    1074             :  * cache implementation.
    1075             :  *
    1076             :  * ================================================================= */
    1077             : 
    1078             : /** rtl_cache_create()
    1079             :  */
    1080             : rtl_cache_type *
    1081       57795 : SAL_CALL rtl_cache_create (
    1082             :     const char *     name,
    1083             :     sal_Size         objsize,
    1084             :     sal_Size         objalign,
    1085             :     int  (SAL_CALL * constructor)(void * obj, void * userarg),
    1086             :     void (SAL_CALL * destructor) (void * obj, void * userarg),
    1087             :     void (SAL_CALL * reclaim)    (void * userarg),
    1088             :     void *           userarg,
    1089             :     rtl_arena_type * source,
    1090             :     int              flags
    1091             : ) SAL_THROW_EXTERN_C()
    1092             : {
    1093       57795 :     rtl_cache_type * result = 0;
    1094       57795 :     sal_Size         size   = sizeof(rtl_cache_type);
    1095             : 
    1096             : try_alloc:
    1097       59070 :     result = (rtl_cache_type*)rtl_arena_alloc (gp_cache_arena, &size);
    1098       59070 :     if (result != 0)
    1099             :     {
    1100       57795 :         rtl_cache_type * cache = result;
    1101       57795 :         (void) rtl_cache_constructor (cache);
    1102             : 
    1103       57795 :         if (!source)
    1104             :         {
    1105             :             /* use default arena */
    1106             :             assert(gp_default_arena != 0);
    1107       57795 :             source = gp_default_arena;
    1108             :         }
    1109             : 
    1110             :         result = rtl_cache_activate (
    1111             :             cache,
    1112             :             name,
    1113             :             objsize,
    1114             :             objalign,
    1115             :             constructor,
    1116             :             destructor,
    1117             :             reclaim,
    1118             :             userarg,
    1119             :             source,
    1120             :             flags
    1121       57795 :         );
    1122             : 
    1123       57795 :         if (result == 0)
    1124             :         {
    1125             :             /* activation failed */
    1126           0 :             rtl_cache_deactivate (cache);
    1127           0 :             rtl_cache_destructor (cache);
    1128           0 :             rtl_arena_free (gp_cache_arena, cache, size);
    1129             :         }
    1130             :     }
    1131        1275 :     else if (gp_cache_arena == 0)
    1132             :     {
    1133        1275 :         ensureCacheSingleton();
    1134        1275 :         if (gp_cache_arena)
    1135             :         {
    1136             :             /* try again */
    1137        1275 :             goto try_alloc;
    1138             :         }
    1139             :     }
    1140       57795 :     return (result);
    1141             : }
    1142             : 
    1143             : /** rtl_cache_destroy()
    1144             :  */
    1145       57795 : void SAL_CALL rtl_cache_destroy (
    1146             :     rtl_cache_type * cache
    1147             : ) SAL_THROW_EXTERN_C()
    1148             : {
    1149       57795 :     if (cache != 0)
    1150             :     {
    1151       57795 :         rtl_cache_deactivate (cache);
    1152       57795 :         rtl_cache_destructor (cache);
    1153       57795 :         rtl_arena_free (gp_cache_arena, cache, sizeof(rtl_cache_type));
    1154             :     }
    1155       57795 : }
    1156             : 
    1157             : /** rtl_cache_alloc()
    1158             :  */
    1159             : void *
    1160    65333560 : SAL_CALL rtl_cache_alloc (
    1161             :     rtl_cache_type * cache
    1162             : ) SAL_THROW_EXTERN_C()
    1163             : {
    1164    65333560 :     void * obj = 0;
    1165             : 
    1166    65333560 :     if (cache == 0)
    1167        1275 :         return (0);
    1168             : 
    1169    65332285 :     if (alloc_mode == AMode_SYSTEM)
    1170             :     {
    1171           0 :         obj = rtl_allocateMemory(cache->m_type_size);
    1172           0 :         if ((obj != 0) && (cache->m_constructor != 0))
    1173             :         {
    1174           0 :             if (!((cache->m_constructor)(obj, cache->m_userarg)))
    1175             :             {
    1176             :                 /* construction failure */
    1177           0 :                 rtl_freeMemory(obj), obj = 0;
    1178             :             }
    1179             :         }
    1180           0 :         return obj;
    1181             :     }
    1182             : 
    1183    65332285 :     RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_depot_lock));
    1184    65332285 :     if (cache->m_cpu_curr != 0)
    1185             :     {
    1186       53782 :         for (;;)
    1187             :         {
    1188             :             /* take object from magazine layer */
    1189             :             rtl_cache_magazine_type *curr, *prev, *temp;
    1190             : 
    1191    64993089 :             curr = cache->m_cpu_curr;
    1192    64993089 :             if ((curr != 0) && (curr->m_mag_used > 0))
    1193             :             {
    1194    58251369 :                 obj = curr->m_objects[--curr->m_mag_used];
    1195    58251369 :                 cache->m_cpu_stats.m_alloc += 1;
    1196    58251369 :                 RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock));
    1197             : 
    1198    58251369 :                 return (obj);
    1199             :             }
    1200             : 
    1201     6741720 :             prev = cache->m_cpu_prev;
    1202     6741720 :             if ((prev != 0) && (prev->m_mag_used > 0))
    1203             :             {
    1204       42470 :                 temp = cache->m_cpu_curr;
    1205       42470 :                 cache->m_cpu_curr = cache->m_cpu_prev;
    1206       42470 :                 cache->m_cpu_prev = temp;
    1207             : 
    1208       42470 :                 continue;
    1209             :             }
    1210             : 
    1211     6699250 :             temp = rtl_cache_depot_exchange_alloc (cache, prev);
    1212     6699250 :             if (temp != 0)
    1213             :             {
    1214       11312 :                 cache->m_cpu_prev = cache->m_cpu_curr;
    1215       11312 :                 cache->m_cpu_curr = temp;
    1216             : 
    1217       11312 :                 continue;
    1218             :             }
    1219             : 
    1220             :             /* no full magazine: fall through to slab layer */
    1221     6687938 :             break;
    1222             :         }
    1223             :     }
    1224     7080916 :     RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock));
    1225             : 
    1226             :     /* alloc buffer from slab layer */
    1227     7080916 :     obj = rtl_cache_slab_alloc (cache);
    1228     7080916 :     if ((obj != 0) && (cache->m_constructor != 0))
    1229             :     {
    1230             :         /* construct object */
    1231      125642 :         if (!((cache->m_constructor)(obj, cache->m_userarg)))
    1232             :         {
    1233             :             /* construction failure */
    1234           0 :             rtl_cache_slab_free (cache, obj), obj = 0;
    1235             :         }
    1236             :     }
    1237     7080916 :     return (obj);
    1238             : }
    1239             : 
    1240             : /** rtl_cache_free()
    1241             :  */
    1242             : void
    1243    63144280 : SAL_CALL rtl_cache_free (
    1244             :     rtl_cache_type * cache,
    1245             :     void *           obj
    1246             : ) SAL_THROW_EXTERN_C()
    1247             : {
    1248    63144280 :     if ((obj != 0) && (cache != 0))
    1249             :     {
    1250    62730073 :         if (alloc_mode == AMode_SYSTEM)
    1251             :         {
    1252           0 :             if (cache->m_destructor != 0)
    1253             :             {
    1254             :                 /* destruct object */
    1255           0 :                 (cache->m_destructor)(obj, cache->m_userarg);
    1256             :             }
    1257           0 :             rtl_freeMemory(obj);
    1258           0 :             return;
    1259             :         }
    1260             : 
    1261    62730073 :         RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_depot_lock));
    1262             : 
    1263      283831 :         for (;;)
    1264             :         {
    1265             :             /* return object to magazine layer */
    1266             :             rtl_cache_magazine_type *curr, *prev, *temp;
    1267             : 
    1268    63013904 :             curr = cache->m_cpu_curr;
    1269    63013904 :             if ((curr != 0) && (curr->m_mag_used < curr->m_mag_size))
    1270             :             {
    1271    62727624 :                 curr->m_objects[curr->m_mag_used++] = obj;
    1272    62727624 :                 cache->m_cpu_stats.m_free += 1;
    1273    62727624 :                 RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock));
    1274             : 
    1275    62727624 :                 return;
    1276             :             }
    1277             : 
    1278      286280 :             prev = cache->m_cpu_prev;
    1279      286280 :             if ((prev != 0) && (prev->m_mag_used == 0))
    1280             :             {
    1281       42426 :                 temp = cache->m_cpu_curr;
    1282       42426 :                 cache->m_cpu_curr = cache->m_cpu_prev;
    1283       42426 :                 cache->m_cpu_prev = temp;
    1284             : 
    1285       42426 :                 continue;
    1286             :             }
    1287             : 
    1288      243854 :             temp = rtl_cache_depot_exchange_free (cache, prev);
    1289      243854 :             if (temp != 0)
    1290             :             {
    1291      126295 :                 cache->m_cpu_prev = cache->m_cpu_curr;
    1292      126295 :                 cache->m_cpu_curr = temp;
    1293             : 
    1294      126295 :                 continue;
    1295             :             }
    1296             : 
    1297      117559 :             if (rtl_cache_depot_populate(cache) != 0)
    1298             :             {
    1299      115110 :                 continue;
    1300             :             }
    1301             : 
    1302             :             /* no empty magazine: fall through to slab layer */
    1303        2449 :             break;
    1304             :         }
    1305             : 
    1306        2449 :         RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock));
    1307             : 
    1308             :         /* no space for constructed object in magazine layer */
    1309        2449 :         if (cache->m_destructor != 0)
    1310             :         {
    1311             :             /* destruct object */
    1312        2449 :             (cache->m_destructor)(obj, cache->m_userarg);
    1313             :         }
    1314             : 
    1315             :         /* return buffer to slab layer */
    1316        2449 :         rtl_cache_slab_free (cache, obj);
    1317             :     }
    1318             : }
    1319             : 
    1320             : /* ================================================================= *
    1321             :  *
    1322             :  * cache wsupdate (machdep) internals.
    1323             :  *
    1324             :  * ================================================================= */
    1325             : 
    1326             : /** rtl_cache_wsupdate_init()
    1327             :  *
    1328             :  *  @precond g_cache_list.m_lock initialized
    1329             :  */
    1330             : static void
    1331             : rtl_cache_wsupdate_init();
    1332             : 
    1333             : 
    1334             : /** rtl_cache_wsupdate_wait()
    1335             :  *
    1336             :  *  @precond g_cache_list.m_lock acquired
    1337             :  */
    1338             : static void
    1339             : rtl_cache_wsupdate_wait (
    1340             :     unsigned int seconds
    1341             : );
    1342             : 
    1343             : /** rtl_cache_wsupdate_fini()
    1344             :  *
    1345             :  */
    1346             : static void
    1347             : rtl_cache_wsupdate_fini();
    1348             : 
    1349             : /* ================================================================= */
    1350             : 
    1351             : #if defined(SAL_UNX)
    1352             : 
    1353             : #include <sys/time.h>
    1354             : 
    1355             : static void *
    1356             : rtl_cache_wsupdate_all (void * arg);
    1357             : 
    1358             : static void
    1359        1275 : rtl_cache_wsupdate_init()
    1360             : {
    1361        1275 :     RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock));
    1362        1275 :     g_cache_list.m_update_done = 0;
    1363        1275 :     (void) pthread_cond_init (&(g_cache_list.m_update_cond), NULL);
    1364        1275 :     if (pthread_create (
    1365        1275 :             &(g_cache_list.m_update_thread), NULL, rtl_cache_wsupdate_all, (void*)(10)) != 0)
    1366             :     {
    1367             :         /* failure */
    1368           0 :         g_cache_list.m_update_thread = (pthread_t)(0);
    1369             :     }
    1370        1275 :     RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock));
    1371        1275 : }
    1372             : 
    1373             : static void
    1374        1284 : rtl_cache_wsupdate_wait (unsigned int seconds)
    1375             : {
    1376        1284 :     if (seconds > 0)
    1377             :     {
    1378             :         timeval  now;
    1379             :         timespec wakeup;
    1380             : 
    1381        1284 :         gettimeofday(&now, 0);
    1382        1284 :         wakeup.tv_sec  = now.tv_sec + (seconds);
    1383        1284 :         wakeup.tv_nsec = now.tv_usec * 1000;
    1384             : 
    1385             :         (void) pthread_cond_timedwait (
    1386             :             &(g_cache_list.m_update_cond),
    1387             :             &(g_cache_list.m_lock),
    1388        1284 :             &wakeup);
    1389             :     }
    1390        1284 : }
    1391             : 
    1392             : static void
    1393        1275 : rtl_cache_wsupdate_fini()
    1394             : {
    1395        1275 :     RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock));
    1396        1275 :     g_cache_list.m_update_done = 1;
    1397        1275 :     pthread_cond_signal (&(g_cache_list.m_update_cond));
    1398        1275 :     RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock));
    1399             : 
    1400        1275 :     if (g_cache_list.m_update_thread != (pthread_t)(0))
    1401        1275 :         pthread_join (g_cache_list.m_update_thread, NULL);
    1402        1275 : }
    1403             : 
    1404             : /* ================================================================= */
    1405             : 
    1406             : #elif defined(SAL_W32)
    1407             : 
    1408             : static DWORD WINAPI
    1409             : rtl_cache_wsupdate_all (void * arg);
    1410             : 
    1411             : static void
    1412             : rtl_cache_wsupdate_init()
    1413             : {
    1414             :     DWORD dwThreadId;
    1415             : 
    1416             :     RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock));
    1417             :     g_cache_list.m_update_done = 0;
    1418             :     g_cache_list.m_update_cond = CreateEvent (0, TRUE, FALSE, 0);
    1419             : 
    1420             :     g_cache_list.m_update_thread =
    1421             :         CreateThread (NULL, 0, rtl_cache_wsupdate_all, (LPVOID)(10), 0, &dwThreadId);
    1422             :     RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock));
    1423             : }
    1424             : 
    1425             : static void
    1426             : rtl_cache_wsupdate_wait (unsigned int seconds)
    1427             : {
    1428             :     if (seconds > 0)
    1429             :     {
    1430             :         RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock));
    1431             :         WaitForSingleObject (g_cache_list.m_update_cond, (DWORD)(seconds * 1000));
    1432             :         RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock));
    1433             :     }
    1434             : }
    1435             : 
    1436             : static void
    1437             : rtl_cache_wsupdate_fini()
    1438             : {
    1439             :     RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock));
    1440             :     g_cache_list.m_update_done = 1;
    1441             :     SetEvent (g_cache_list.m_update_cond);
    1442             :     RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock));
    1443             : 
    1444             :     WaitForSingleObject (g_cache_list.m_update_thread, INFINITE);
    1445             : }
    1446             : 
    1447             : #endif /* SAL_UNX || SAL_W32 */
    1448             : 
    1449             : /* ================================================================= */
    1450             : 
    1451             : /** rtl_cache_depot_wsupdate()
    1452             :  *  update depot stats and purge excess magazines.
    1453             :  *
    1454             :  *  @precond cache->m_depot_lock acquired
    1455             :  */
    1456             : static void
    1457        4060 : rtl_cache_depot_wsupdate (
    1458             :     rtl_cache_type *       cache,
    1459             :     rtl_cache_depot_type * depot
    1460             : )
    1461             : {
    1462             :     sal_Size npurge;
    1463             : 
    1464        4060 :     depot->m_prev_min = depot->m_curr_min;
    1465        4060 :     depot->m_curr_min = depot->m_mag_count;
    1466             : 
    1467        4060 :     npurge = depot->m_curr_min < depot->m_prev_min ? depot->m_curr_min : depot->m_prev_min;
    1468        4287 :     for (; npurge > 0; npurge--)
    1469             :     {
    1470         227 :         rtl_cache_magazine_type * mag = rtl_cache_depot_dequeue (depot);
    1471         227 :         if (mag != 0)
    1472             :         {
    1473         227 :             RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock));
    1474         227 :             rtl_cache_magazine_clear (cache, mag);
    1475         227 :             rtl_cache_free (cache->m_magazine_cache, mag);
    1476         227 :             RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_depot_lock));
    1477             :         }
    1478             :     }
    1479        4060 : }
    1480             : 
    1481             : /** rtl_cache_wsupdate()
    1482             :  *
    1483             :  *  @precond cache->m_depot_lock released
    1484             :  */
    1485             : static void
    1486        2030 : rtl_cache_wsupdate (
    1487             :     rtl_cache_type * cache
    1488             : )
    1489             : {
    1490        2030 :     if (cache->m_magazine_cache != 0)
    1491             :     {
    1492        2030 :         RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_depot_lock));
    1493             : 
    1494             :         // SAL_INFO(
    1495             :         //  "sal.rtl",
    1496             :         //  "rtl_cache_wsupdate(" << cache->m_name
    1497             :         //      << ") [depot: count, curr_min, prev_min] full: "
    1498             :         //      << cache->m_depot_full.m_mag_count << ", "
    1499             :         //      << cache->m_depot_full.m_curr_min << ", "
    1500             :         //      << cache->m_depot_full.m_prev_min << "; empty: "
    1501             :         //      << cache->m_depot_empty.m_mag_count << ", "
    1502             :         //      << cache->m_depot_empty.m_curr_min << ", "
    1503             :         //      << cache->m_depot_empty.m_prev_min);
    1504             : 
    1505        2030 :         rtl_cache_depot_wsupdate (cache, &(cache->m_depot_full));
    1506        2030 :         rtl_cache_depot_wsupdate (cache, &(cache->m_depot_empty));
    1507             : 
    1508        2030 :         RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock));
    1509             :     }
    1510        2030 : }
    1511             : 
    1512             : /** rtl_cache_wsupdate_all()
    1513             :  *
    1514             :  */
    1515             : #if defined(SAL_UNX)
    1516             : static void *
    1517             : #elif defined(SAL_W32)
    1518             : static DWORD WINAPI
    1519             : #endif /* SAL_UNX || SAL_W32 */
    1520        1275 : rtl_cache_wsupdate_all (void * arg)
    1521             : {
    1522             :     unsigned int seconds = sal::static_int_cast< unsigned int >(
    1523        1275 :         reinterpret_cast< sal_uIntPtr >(arg));
    1524             : 
    1525        1275 :     RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock));
    1526        3834 :     while (!g_cache_list.m_update_done)
    1527             :     {
    1528        1284 :         rtl_cache_wsupdate_wait (seconds);
    1529        1284 :         if (!g_cache_list.m_update_done)
    1530             :         {
    1531             :             rtl_cache_type * head, * cache;
    1532             : 
    1533          30 :             head = &(g_cache_list.m_cache_head);
    1534        2060 :             for (cache  = head->m_cache_next;
    1535             :                  cache != head;
    1536             :                  cache  = cache->m_cache_next)
    1537             :             {
    1538        2030 :                 rtl_cache_wsupdate (cache);
    1539             :             }
    1540             :         }
    1541             :     }
    1542        1275 :     RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock));
    1543             : 
    1544        1275 :     return (0);
    1545             : }
    1546             : 
    1547             : /* ================================================================= *
    1548             :  *
    1549             :  * cache initialization.
    1550             :  *
    1551             :  * ================================================================= */
    1552             : 
    1553             : void
    1554        1275 : rtl_cache_init()
    1555             : {
    1556             :     {
    1557             :         /* list of caches */
    1558        1275 :         RTL_MEMORY_LOCK_INIT(&(g_cache_list.m_lock));
    1559        1275 :         (void) rtl_cache_constructor (&(g_cache_list.m_cache_head));
    1560             :     }
    1561             :     {
    1562             :         /* cache: internal arena */
    1563             :         assert(gp_cache_arena == 0);
    1564             : 
    1565             :         gp_cache_arena = rtl_arena_create (
    1566             :             "rtl_cache_internal_arena",
    1567             :             64,   /* quantum */
    1568             :             0,    /* no quantum caching */
    1569             :             NULL, /* default source */
    1570             :             rtl_arena_alloc,
    1571             :             rtl_arena_free,
    1572             :             0     /* flags */
    1573        1275 :         );
    1574             :         assert(gp_cache_arena != 0);
    1575             : 
    1576             :         /* check 'gp_default_arena' initialization */
    1577             :         assert(gp_default_arena != 0);
    1578             :     }
    1579             :     {
    1580             :         /* cache: magazine cache */
    1581             :         static rtl_cache_type g_cache_magazine_cache;
    1582             : 
    1583             :         assert(gp_cache_magazine_cache == 0);
    1584        1275 :         (void) rtl_cache_constructor (&g_cache_magazine_cache);
    1585             : 
    1586             :         gp_cache_magazine_cache = rtl_cache_activate (
    1587             :             &g_cache_magazine_cache,
    1588             :             "rtl_cache_magazine_cache",
    1589             :             sizeof(rtl_cache_magazine_type), /* objsize  */
    1590             :             0,                               /* objalign */
    1591             :             rtl_cache_magazine_constructor,
    1592             :             rtl_cache_magazine_destructor,
    1593             :             0, /* reclaim */
    1594             :             0, /* userarg: NYI */
    1595             :             gp_default_arena, /* source */
    1596             :             RTL_CACHE_FLAG_NOMAGAZINE /* during bootstrap; activated below */
    1597        1275 :         );
    1598             :         assert(gp_cache_magazine_cache != 0);
    1599             : 
    1600             :         /* activate magazine layer */
    1601        1275 :         g_cache_magazine_cache.m_magazine_cache = gp_cache_magazine_cache;
    1602             :     }
    1603             :     {
    1604             :         /* cache: slab (struct) cache */
    1605             :         static rtl_cache_type g_cache_slab_cache;
    1606             : 
    1607             :         assert(gp_cache_slab_cache == 0);
    1608        1275 :         (void) rtl_cache_constructor (&g_cache_slab_cache);
    1609             : 
    1610             :         gp_cache_slab_cache = rtl_cache_activate (
    1611             :             &g_cache_slab_cache,
    1612             :             "rtl_cache_slab_cache",
    1613             :             sizeof(rtl_cache_slab_type), /* objsize  */
    1614             :             0,                           /* objalign */
    1615             :             rtl_cache_slab_constructor,
    1616             :             rtl_cache_slab_destructor,
    1617             :             0,                           /* reclaim */
    1618             :             0,                           /* userarg: none */
    1619             :             gp_default_arena,            /* source */
    1620             :             0                            /* flags: none */
    1621        1275 :         );
    1622             :         assert(gp_cache_slab_cache != 0);
    1623             :     }
    1624             :     {
    1625             :         /* cache: bufctl cache */
    1626             :         static rtl_cache_type g_cache_bufctl_cache;
    1627             : 
    1628             :         assert(gp_cache_bufctl_cache == 0);
    1629        1275 :         (void) rtl_cache_constructor (&g_cache_bufctl_cache);
    1630             : 
    1631             :         gp_cache_bufctl_cache = rtl_cache_activate (
    1632             :             &g_cache_bufctl_cache,
    1633             :             "rtl_cache_bufctl_cache",
    1634             :             sizeof(rtl_cache_bufctl_type), /* objsize */
    1635             :             0,                             /* objalign  */
    1636             :             0,                /* constructor */
    1637             :             0,                /* destructor */
    1638             :             0,                /* reclaim */
    1639             :             0,                /* userarg */
    1640             :             gp_default_arena, /* source */
    1641             :             0                 /* flags: none */
    1642        1275 :         );
    1643             :         assert(gp_cache_bufctl_cache != 0);
    1644             :     }
    1645             : 
    1646        1275 :     rtl_cache_wsupdate_init();
    1647             :     // SAL_INFO("sal.rtl", "rtl_cache_init completed");
    1648        1275 : }
    1649             : 
    1650             : /* ================================================================= */
    1651             : 
    1652             : void
    1653        1275 : rtl_cache_fini()
    1654             : {
    1655        1275 :     if (gp_cache_arena != 0)
    1656             :     {
    1657             :         rtl_cache_type * cache, * head;
    1658             : 
    1659        1275 :         rtl_cache_wsupdate_fini();
    1660             : 
    1661        1275 :         if (gp_cache_bufctl_cache != 0)
    1662             :         {
    1663        1275 :             cache = gp_cache_bufctl_cache, gp_cache_bufctl_cache = 0;
    1664        1275 :             rtl_cache_deactivate (cache);
    1665        1275 :             rtl_cache_destructor (cache);
    1666             :         }
    1667        1275 :         if (gp_cache_slab_cache != 0)
    1668             :         {
    1669        1275 :             cache = gp_cache_slab_cache, gp_cache_slab_cache = 0;
    1670        1275 :             rtl_cache_deactivate (cache);
    1671        1275 :             rtl_cache_destructor (cache);
    1672             :         }
    1673        1275 :         if (gp_cache_magazine_cache != 0)
    1674             :         {
    1675        1275 :             cache = gp_cache_magazine_cache, gp_cache_magazine_cache = 0;
    1676        1275 :             rtl_cache_deactivate (cache);
    1677        1275 :             rtl_cache_destructor (cache);
    1678             :         }
    1679        1275 :         if (gp_cache_arena != 0)
    1680             :         {
    1681        1275 :             rtl_arena_destroy (gp_cache_arena);
    1682        1275 :             gp_cache_arena = 0;
    1683             :         }
    1684             : 
    1685        1275 :         RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock));
    1686        1275 :         head = &(g_cache_list.m_cache_head);
    1687        1275 :         for (cache = head->m_cache_next; cache != head; cache = cache->m_cache_next)
    1688             :         {
    1689             :             // SAL_INFO(
    1690             :             //  "sal.rtl",
    1691             :             //  "rtl_cache_fini(" << cache->m_name << ") [slab]: allocs: "
    1692             :             //      << cache->m_slab_stats.m_alloc << ", frees: "
    1693             :             //      << cache->m_slab_stats.m_free << "; total: "
    1694             :             //      << cache->m_slab_stats.m_mem_total << ", used: "
    1695             :             //      << cache->m_slab_stats.m_mem_alloc << "; [cpu]: allocs: "
    1696             :             //      << cache->m_cpu_stats.m_alloc << ", frees: "
    1697             :             //      << cache->m_cpu_stats.m_free  << "; [total]: allocs: "
    1698             :             //      << (cache->m_slab_stats.m_alloc
    1699             :             //          + cache->m_cpu_stats.m_alloc)
    1700             :             //      << ", frees: "
    1701             :             //      << (cache->m_slab_stats.m_free
    1702             :             //          + cache->m_cpu_stats.m_free));
    1703             :         }
    1704        1275 :         RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock));
    1705             :     }
    1706             :     // SAL_INFO("sal.rtl", "rtl_cache_fini completed");
    1707        1275 : }
    1708             : 
    1709             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10