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

Generated by: LCOV version 1.10