LCOV - code coverage report
Current view: top level - sal/rtl - alloc_cache.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 475 494 96.2 %
Date: 2014-11-03 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         545 : 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         545 :     new_bytes = new_size * sizeof(rtl_cache_bufctl_type*);
     105         545 :     new_table = (rtl_cache_bufctl_type**)rtl_arena_alloc(gp_cache_arena, &new_bytes);
     106             : 
     107         545 :     if (new_table != 0)
     108             :     {
     109             :         rtl_cache_bufctl_type ** old_table;
     110             :         sal_Size                 old_size, i;
     111             : 
     112         545 :         memset (new_table, 0, new_bytes);
     113             : 
     114         545 :         RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_slab_lock));
     115             : 
     116         545 :         old_table = cache->m_hash_table;
     117         545 :         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         545 :         cache->m_hash_table = new_table;
     130         545 :         cache->m_hash_size  = new_size;
     131         545 :         cache->m_hash_shift = highbit(cache->m_hash_size) - 1;
     132             : 
     133        4905 :         for (i = 0; i < old_size; i++)
     134             :         {
     135        4360 :             rtl_cache_bufctl_type * curr = old_table[i];
     136      144450 :             while (curr != 0)
     137             :             {
     138      135730 :                 rtl_cache_bufctl_type  * next = curr->m_next;
     139             :                 rtl_cache_bufctl_type ** head;
     140             : 
     141      135730 :                 head = &(cache->m_hash_table[RTL_CACHE_HASH_INDEX(cache, curr->m_addr)]);
     142      135730 :                 curr->m_next = (*head);
     143      135730 :                 (*head) = curr;
     144             : 
     145      135730 :                 curr = next;
     146             :             }
     147        4360 :             old_table[i] = 0;
     148             :         }
     149             : 
     150         545 :         RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock));
     151             : 
     152         545 :         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         545 : }
     159             : 
     160             : inline sal_uIntPtr
     161      186749 : 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      186749 :     ppHead = &(cache->m_hash_table[RTL_CACHE_HASH_INDEX(cache, bufctl->m_addr)]);
     169             : 
     170      186749 :     bufctl->m_next = (*ppHead);
     171      186749 :     (*ppHead) = bufctl;
     172             : 
     173      186749 :     return (bufctl->m_addr);
     174             : }
     175             : 
     176             : /** rtl_cache_hash_remove()
     177             :  */
     178             : rtl_cache_bufctl_type *
     179      167474 : 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      167474 :     sal_Size                 lookups = 0;
     187             : 
     188      167474 :     ppHead = &(cache->m_hash_table[RTL_CACHE_HASH_INDEX(cache, addr)]);
     189      389296 :     while ((bufctl = *ppHead) != 0)
     190             :     {
     191      221822 :         if (bufctl->m_addr == addr)
     192             :         {
     193      167474 :             *ppHead = bufctl->m_next, bufctl->m_next = 0;
     194      167474 :             break;
     195             :         }
     196             : 
     197       54348 :         lookups += 1;
     198       54348 :         ppHead = &(bufctl->m_next);
     199             :     }
     200             : 
     201             :     assert(bufctl != 0); // bad free
     202             : 
     203      167474 :     if (lookups > 1)
     204             :     {
     205        6965 :         sal_Size nbuf = (sal_Size)(cache->m_slab_stats.m_alloc - cache->m_slab_stats.m_free);
     206        6965 :         if (nbuf > 4 * cache->m_hash_size)
     207             :         {
     208         545 :             if (!(cache->m_features & RTL_CACHE_FEATURE_RESCALE))
     209             :             {
     210         545 :                 sal_Size ave = nbuf >> cache->m_hash_shift;
     211         545 :                 sal_Size new_size = cache->m_hash_size << (highbit(ave) - 1);
     212             : 
     213         545 :                 cache->m_features |= RTL_CACHE_FEATURE_RESCALE;
     214         545 :                 RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock));
     215         545 :                 rtl_cache_hash_rescale (cache, new_size);
     216         545 :                 RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_slab_lock));
     217         545 :                 cache->m_features &= ~RTL_CACHE_FEATURE_RESCALE;
     218             :             }
     219             :         }
     220             :     }
     221             : 
     222      167474 :     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      339652 : rtl_cache_slab_constructor (void * obj, SAL_UNUSED_PARAMETER void *)
     236             : {
     237      339652 :     rtl_cache_slab_type * slab = (rtl_cache_slab_type*)(obj);
     238             : 
     239      339652 :     QUEUE_START_NAMED(slab, slab_);
     240      339652 :     slab->m_ntypes = 0;
     241             : 
     242      339652 :     return (1);
     243             : }
     244             : 
     245             : /** rtl_cache_slab_destructor()
     246             :  */
     247             : void
     248      339654 : rtl_cache_slab_destructor (void * obj, SAL_UNUSED_PARAMETER void *)
     249             : {
     250      339654 :     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      339654 : }
     255             : 
     256             : /** rtl_cache_slab_create()
     257             :  *
     258             :  *  @precond cache->m_slab_lock released.
     259             :  */
     260             : rtl_cache_slab_type *
     261      340114 : rtl_cache_slab_create (
     262             :     rtl_cache_type * cache
     263             : )
     264             : {
     265      340114 :     rtl_cache_slab_type * slab = 0;
     266             :     void *                addr;
     267             :     sal_Size              size;
     268             : 
     269      340114 :     size = cache->m_slab_size;
     270      340114 :     addr = rtl_arena_alloc (cache->m_source, &size);
     271      340114 :     if (addr != 0)
     272             :     {
     273             :         assert(size >= cache->m_slab_size);
     274             : 
     275      340114 :         if (cache->m_features & RTL_CACHE_FEATURE_HASH)
     276             :         {
     277             :             /* allocate slab struct from slab cache */
     278             :             assert(cache != gp_cache_slab_cache);
     279       28266 :             slab = (rtl_cache_slab_type*)rtl_cache_alloc (gp_cache_slab_cache);
     280             :         }
     281             :         else
     282             :         {
     283             :             /* construct embedded slab struct */
     284      311848 :             slab = RTL_CACHE_SLAB(addr, cache->m_slab_size);
     285      311848 :             (void) rtl_cache_slab_constructor (slab, 0);
     286             :         }
     287      340114 :         if (slab != 0)
     288             :         {
     289      340114 :             slab->m_data = (sal_uIntPtr)(addr);
     290             : 
     291             :             /* dynamic freelist initialization */
     292      340114 :             slab->m_bp = slab->m_data;
     293      340114 :             slab->m_sp = 0;
     294             :         }
     295             :         else
     296             :         {
     297           0 :             rtl_arena_free (cache->m_source, addr, size);
     298             :         }
     299             :     }
     300      340114 :     return (slab);
     301             : }
     302             : 
     303             : /** rtl_cache_slab_destroy()
     304             :  *
     305             :  *  @precond cache->m_slab_lock released.
     306             :  */
     307             : void
     308      340116 : rtl_cache_slab_destroy (
     309             :     rtl_cache_type *      cache,
     310             :     rtl_cache_slab_type * slab
     311             : )
     312             : {
     313      340116 :     void *   addr   = (void*)(slab->m_data);
     314      340116 :     sal_Size refcnt = slab->m_ntypes; slab->m_ntypes = 0;
     315             : 
     316      340116 :     if (cache->m_features & RTL_CACHE_FEATURE_HASH)
     317             :     {
     318             :         /* cleanup bufctl(s) for free buffer(s) */
     319       28268 :         sal_Size ntypes = (slab->m_bp - slab->m_data) / cache->m_type_size;
     320      194736 :         for (ntypes -= refcnt; slab->m_sp != 0; ntypes--)
     321             :         {
     322      166468 :             rtl_cache_bufctl_type * bufctl = slab->m_sp;
     323             : 
     324             :             /* pop from freelist */
     325      166468 :             slab->m_sp = bufctl->m_next, bufctl->m_next = 0;
     326             : 
     327             :             /* return bufctl struct to bufctl cache */
     328      166468 :             rtl_cache_free (gp_cache_bufctl_cache, bufctl);
     329             :         }
     330             :         assert(ntypes == 0);
     331             : 
     332             :         /* return slab struct to slab cache */
     333       28268 :         rtl_cache_free (gp_cache_slab_cache, slab);
     334             :     }
     335             :     else
     336             :     {
     337             :         /* destruct embedded slab struct */
     338      311848 :         rtl_cache_slab_destructor (slab, 0);
     339             :     }
     340             : 
     341      340116 :     if ((refcnt == 0) || (cache->m_features & RTL_CACHE_FEATURE_BULKDESTROY))
     342             :     {
     343             :         /* free memory */
     344      243294 :         rtl_arena_free (cache->m_source, addr, cache->m_slab_size);
     345             :     }
     346      340116 : }
     347             : 
     348             : /** rtl_cache_slab_populate()
     349             :  *
     350             :  *  @precond cache->m_slab_lock acquired.
     351             :  */
     352             : bool
     353      340114 : rtl_cache_slab_populate (
     354             :     rtl_cache_type * cache
     355             : )
     356             : {
     357             :     rtl_cache_slab_type * slab;
     358             : 
     359      340114 :     RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock));
     360      340114 :     slab = rtl_cache_slab_create (cache);
     361      340114 :     RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_slab_lock));
     362      340114 :     if (slab != 0)
     363             :     {
     364             :         /* update buffer start addr w/ current color */
     365      340114 :         slab->m_bp += cache->m_ncolor;
     366             : 
     367             :         /* update color for next slab */
     368      340114 :         cache->m_ncolor += cache->m_type_align;
     369      340114 :         if (cache->m_ncolor > cache->m_ncolor_max)
     370       72961 :             cache->m_ncolor = 0;
     371             : 
     372             :         /* update stats */
     373      340114 :         cache->m_slab_stats.m_mem_total += cache->m_slab_size;
     374             : 
     375             :         /* insert onto 'free' queue */
     376      340114 :         QUEUE_INSERT_HEAD_NAMED(&(cache->m_free_head), slab, slab_);
     377             :     }
     378      340114 :     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    16038205 : rtl_cache_slab_alloc (
     389             :     rtl_cache_type * cache
     390             : )
     391             : {
     392    16038205 :     void                * addr = 0;
     393             :     rtl_cache_slab_type * head;
     394             : 
     395    16038205 :     RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_slab_lock));
     396             : 
     397    16038205 :     head = &(cache->m_free_head);
     398    16038205 :     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    16038203 :         slab = head->m_slab_next;
     404             :         assert(slab->m_ntypes < cache->m_ntypes);
     405             : 
     406    16038203 :         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    15971821 :             if (cache->m_features & RTL_CACHE_FEATURE_HASH)
     411             :             {
     412             :                 /* allocate bufctl */
     413             :                 assert(cache != gp_cache_bufctl_cache);
     414      185743 :                 bufctl = (rtl_cache_bufctl_type*)rtl_cache_alloc (gp_cache_bufctl_cache);
     415      185743 :                 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      185743 :                 bufctl->m_addr = slab->m_bp;
     423      185743 :                 bufctl->m_slab = (sal_uIntPtr)(slab);
     424             :             }
     425             :             else
     426             :             {
     427             :                 /* embedded bufctl */
     428    15786078 :                 bufctl = (rtl_cache_bufctl_type*)(slab->m_bp);
     429             :             }
     430    15971821 :             bufctl->m_next = 0;
     431             : 
     432             :             /* update 'slab->m_bp' to next free buffer */
     433    15971821 :             slab->m_bp += cache->m_type_size;
     434             : 
     435             :             /* assign bufctl to freelist */
     436    15971821 :             slab->m_sp = bufctl;
     437             :         }
     438             : 
     439             :         /* pop front */
     440    16038203 :         bufctl = slab->m_sp;
     441    16038203 :         slab->m_sp = bufctl->m_next;
     442             : 
     443             :         /* increment usage, check for full slab */
     444    16038203 :         if ((slab->m_ntypes += 1) == cache->m_ntypes)
     445             :         {
     446             :             /* remove from 'free' queue */
     447      282115 :             QUEUE_REMOVE_NAMED(slab, slab_);
     448             : 
     449             :             /* insert onto 'used' queue (tail) */
     450      282115 :             QUEUE_INSERT_TAIL_NAMED(&(cache->m_used_head), slab, slab_);
     451             :         }
     452             : 
     453             :         /* update stats */
     454    16038203 :         cache->m_slab_stats.m_alloc     += 1;
     455    16038203 :         cache->m_slab_stats.m_mem_alloc += cache->m_type_size;
     456             : 
     457    16038203 :         if (cache->m_features & RTL_CACHE_FEATURE_HASH)
     458      186749 :             addr = (void*)rtl_cache_hash_insert (cache, bufctl);
     459             :         else
     460    15851454 :             addr = bufctl;
     461             :     }
     462             : 
     463    16038205 :     RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock));
     464    16038204 :     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    14857818 : 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    14857818 :     RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_slab_lock));
     481             : 
     482             :     /* determine slab from addr */
     483    14857818 :     if (cache->m_features & RTL_CACHE_FEATURE_HASH)
     484             :     {
     485      167474 :         bufctl = rtl_cache_hash_remove (cache, (sal_uIntPtr)(addr));
     486      167474 :         slab = (bufctl != 0) ? (rtl_cache_slab_type*)(bufctl->m_slab) : 0;
     487             :     }
     488             :     else
     489             :     {
     490             :         /* embedded slab struct */
     491    14690344 :         bufctl = (rtl_cache_bufctl_type*)(addr);
     492    14690344 :         slab = RTL_CACHE_SLAB(addr, cache->m_slab_size);
     493             :     }
     494             : 
     495    14857818 :     if (slab != 0)
     496             :     {
     497             :         /* check for full slab */
     498    14857818 :         if (slab->m_ntypes == cache->m_ntypes)
     499             :         {
     500             :             /* remove from 'used' queue */
     501      279483 :             QUEUE_REMOVE_NAMED(slab, slab_);
     502             : 
     503             :             /* insert onto 'free' queue (head) */
     504      279483 :             QUEUE_INSERT_HEAD_NAMED(&(cache->m_free_head), slab, slab_);
     505             :         }
     506             : 
     507             :         /* push front */
     508    14857818 :         bufctl->m_next = slab->m_sp;
     509    14857818 :         slab->m_sp = bufctl;
     510             : 
     511             :         /* update stats */
     512    14857818 :         cache->m_slab_stats.m_free      += 1;
     513    14857818 :         cache->m_slab_stats.m_mem_alloc -= cache->m_type_size;
     514             : 
     515             :         /* decrement usage, check for empty slab */
     516    14857818 :         if ((slab->m_ntypes -= 1) == 0)
     517             :         {
     518             :             /* remove from 'free' queue */
     519      243294 :             QUEUE_REMOVE_NAMED(slab, slab_);
     520             : 
     521             :             /* update stats */
     522      243294 :             cache->m_slab_stats.m_mem_total -= cache->m_slab_size;
     523             : 
     524             :             /* free 'empty' slab */
     525      243294 :             RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock));
     526      243294 :             rtl_cache_slab_destroy (cache, slab);
     527    15101112 :             return;
     528             :         }
     529             :     }
     530             : 
     531    14614524 :     RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock));
     532             : }
     533             : 
     534             : /* ================================================================= */
     535             : 
     536             : /** rtl_cache_magazine_constructor()
     537             :  */
     538             : int
     539      274951 : rtl_cache_magazine_constructor (void * obj, SAL_UNUSED_PARAMETER void *)
     540             : {
     541      274951 :     rtl_cache_magazine_type * mag = (rtl_cache_magazine_type*)(obj);
     542             :     /* @@@ sal_Size size = (sal_Size)(arg); @@@ */
     543             : 
     544      274951 :     mag->m_mag_next = 0;
     545      274951 :     mag->m_mag_size = RTL_CACHE_MAGAZINE_SIZE;
     546      274951 :     mag->m_mag_used = 0;
     547             : 
     548      274951 :     return (1);
     549             : }
     550             : 
     551             : /** rtl_cache_magazine_destructor()
     552             :  */
     553             : void
     554      274893 : rtl_cache_magazine_destructor (void * obj, SAL_UNUSED_PARAMETER void *)
     555             : {
     556             :     rtl_cache_magazine_type * mag = static_cast< rtl_cache_magazine_type * >(
     557      274893 :         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      274893 : }
     562             : 
     563             : /** rtl_cache_magazine_clear()
     564             :  */
     565             : void
     566      295917 : rtl_cache_magazine_clear (
     567             :     rtl_cache_type *          cache,
     568             :     rtl_cache_magazine_type * mag
     569             : )
     570             : {
     571    15147860 :     for (; mag->m_mag_used > 0; --mag->m_mag_used)
     572             :     {
     573    14851943 :         void * obj = mag->m_objects[mag->m_mag_used - 1];
     574    14851943 :         mag->m_objects[mag->m_mag_used - 1] = 0;
     575             : 
     576    14851943 :         if (cache->m_destructor != 0)
     577             :         {
     578             :             /* destruct object */
     579      296824 :             (cache->m_destructor)(obj, cache->m_userarg);
     580             :         }
     581             : 
     582             :         /* return buffer to slab layer */
     583    14851943 :         rtl_cache_slab_free (cache, obj);
     584             :     }
     585      295917 : }
     586             : 
     587             : /* ================================================================= */
     588             : 
     589             : /** rtl_cache_depot_enqueue()
     590             :  *
     591             :  *  @precond cache->m_depot_lock acquired.
     592             :  */
     593             : inline void
     594     1216065 : rtl_cache_depot_enqueue (
     595             :     rtl_cache_depot_type *    depot,
     596             :     rtl_cache_magazine_type * mag
     597             : )
     598             : {
     599             :     /* enqueue empty magazine */
     600     1216065 :     mag->m_mag_next = depot->m_mag_next;
     601     1216065 :     depot->m_mag_next = mag;
     602             : 
     603             :     /* update depot stats */
     604     1216065 :     depot->m_mag_count++;
     605     1216065 : }
     606             : 
     607             : /** rtl_cache_depot_dequeue()
     608             :  *
     609             :  *  @precond cache->m_depot_lock acquired.
     610             :  */
     611             : inline rtl_cache_magazine_type *
     612    17162181 : rtl_cache_depot_dequeue (
     613             :     rtl_cache_depot_type * depot
     614             : )
     615             : {
     616    17162181 :     rtl_cache_magazine_type * mag = 0;
     617    17162181 :     if (depot->m_mag_count > 0)
     618             :     {
     619             :         /* dequeue magazine */
     620             :         assert(depot->m_mag_next != 0);
     621             : 
     622     1216066 :         mag = depot->m_mag_next;
     623     1216066 :         depot->m_mag_next = mag->m_mag_next;
     624     1216066 :         mag->m_mag_next = 0;
     625             : 
     626             :         /* update depot stats */
     627     1216066 :         depot->m_mag_count--;
     628     1216066 :         if(depot->m_curr_min > depot->m_mag_count)
     629             :         {
     630       32800 :             depot->m_curr_min = depot->m_mag_count;
     631             :         }
     632             :     }
     633    17162181 :     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    15766044 : 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    15766044 :     full = rtl_cache_depot_dequeue (&(cache->m_depot_full));
     652    15766043 :     if ((full != 0) && (empty != 0))
     653             :     {
     654             :         /* enqueue empty magazine */
     655      348159 :         rtl_cache_depot_enqueue (&(cache->m_depot_empty), empty);
     656             :     }
     657             : 
     658             :     assert((full == 0) || (full->m_mag_used > 0));
     659             : 
     660    15766043 :     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      944742 : 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      944742 :     empty = rtl_cache_depot_dequeue (&(cache->m_depot_empty));
     679      944742 :     if ((empty != 0) && (full != 0))
     680             :     {
     681             :         /* enqueue full magazine */
     682      571986 :         rtl_cache_depot_enqueue (&(cache->m_depot_full), full);
     683             :     }
     684             : 
     685             :     assert((empty == 0) || (empty->m_mag_used == 0));
     686             : 
     687      944742 :     return (empty);
     688             : }
     689             : 
     690             : /** rtl_cache_depot_populate()
     691             :  *
     692             :  *  @precond cache->m_depot_lock acquired.
     693             :  */
     694             : bool
     695      301795 : rtl_cache_depot_populate (
     696             :     rtl_cache_type * cache
     697             : )
     698             : {
     699      301795 :     rtl_cache_magazine_type * empty = 0;
     700             : 
     701      301795 :     if (cache->m_magazine_cache != 0)
     702             :     {
     703             :         /* allocate new empty magazine */
     704      295920 :         RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock));
     705      295920 :         empty = (rtl_cache_magazine_type*)rtl_cache_alloc (cache->m_magazine_cache);
     706      295920 :         RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_depot_lock));
     707      295920 :         if (empty != 0)
     708             :         {
     709             :             /* enqueue (new) empty magazine */
     710      295920 :             rtl_cache_depot_enqueue (&(cache->m_depot_empty), empty);
     711             :         }
     712             :     }
     713      301795 :     return (empty != 0);
     714             : }
     715             : 
     716             : /* ================================================================= */
     717             : 
     718             : /** rtl_cache_constructor()
     719             :  */
     720             : int
     721      116060 : rtl_cache_constructor (void * obj)
     722             : {
     723      116060 :     rtl_cache_type * cache = (rtl_cache_type*)(obj);
     724             : 
     725      116060 :     memset (cache, 0, sizeof(rtl_cache_type));
     726             : 
     727             :     /* linkage */
     728      116060 :     QUEUE_START_NAMED(cache, cache_);
     729             : 
     730             :     /* slab layer */
     731      116060 :     (void)RTL_MEMORY_LOCK_INIT(&(cache->m_slab_lock));
     732             : 
     733      116060 :     QUEUE_START_NAMED(&(cache->m_free_head), slab_);
     734      116060 :     QUEUE_START_NAMED(&(cache->m_used_head), slab_);
     735             : 
     736      116060 :     cache->m_hash_table = cache->m_hash_table_0;
     737      116060 :     cache->m_hash_size  = RTL_CACHE_HASH_SIZE;
     738      116060 :     cache->m_hash_shift = highbit(cache->m_hash_size) - 1;
     739             : 
     740             :     /* depot layer */
     741      116060 :     (void)RTL_MEMORY_LOCK_INIT(&(cache->m_depot_lock));
     742             : 
     743      116060 :     return (1);
     744             : }
     745             : 
     746             : /** rtl_cache_destructor()
     747             :  */
     748             : void
     749      113218 : rtl_cache_destructor (void * obj)
     750             : {
     751      113218 :     rtl_cache_type * cache = (rtl_cache_type*)(obj);
     752             : 
     753             :     /* linkage */
     754             :     assert(QUEUE_STARTED_NAMED(cache, cache_));
     755             : 
     756             :     /* slab layer */
     757      113218 :     (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      113218 :     (void)RTL_MEMORY_LOCK_DESTROY(&(cache->m_depot_lock));
     768      113218 : }
     769             : 
     770             : /* ================================================================= */
     771             : 
     772             : /** rtl_cache_activate()
     773             :  */
     774             : rtl_cache_type *
     775      113222 : 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      113222 :     if (cache != 0)
     790             :     {
     791             :         sal_Size slabsize;
     792             : 
     793      113222 :         snprintf (cache->m_name, sizeof(cache->m_name), "%s", name);
     794             : 
     795             :         /* ensure minimum size (embedded bufctl linkage) */
     796      113222 :         if(objsize < sizeof(rtl_cache_bufctl_type*))
     797             :         {
     798           0 :             objsize = sizeof(rtl_cache_bufctl_type*);
     799             :         }
     800             : 
     801      113222 :         if (objalign == 0)
     802             :         {
     803             :             /* determine default alignment */
     804      113222 :             if (objsize >= RTL_MEMORY_ALIGNMENT_8)
     805      113222 :                 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      113222 :         cache->m_type_size  = objsize = RTL_MEMORY_P2ROUNDUP(objsize, objalign);
     820      113222 :         cache->m_type_align = objalign;
     821      113222 :         cache->m_type_shift = highbit(cache->m_type_size) - 1;
     822             : 
     823      113222 :         cache->m_constructor = constructor;
     824      113222 :         cache->m_destructor  = destructor;
     825      113222 :         cache->m_reclaim     = reclaim;
     826      113222 :         cache->m_userarg     = userarg;
     827             : 
     828             :         /* slab layer */
     829      113222 :         cache->m_source = source;
     830             : 
     831      113222 :         slabsize = source->m_quantum; /* minimum slab size */
     832      113222 :         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      113222 :             if(slabsize < cache->m_type_size * 8)
     844             :             {
     845       52214 :                 slabsize = cache->m_type_size * 8;
     846             :             }
     847             :         }
     848             : 
     849      113222 :         slabsize = RTL_MEMORY_P2ROUNDUP(slabsize, source->m_quantum);
     850      113222 :         if (!RTL_MEMORY_ISP2(slabsize))
     851       27466 :             slabsize = (((sal_Size)1) << highbit(slabsize));
     852      113222 :         cache->m_slab_size = slabsize;
     853             : 
     854      113222 :         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       52214 :             cache->m_features  |= RTL_CACHE_FEATURE_HASH;
     860       52214 :             cache->m_ntypes     = cache->m_slab_size / cache->m_type_size;
     861       52214 :             cache->m_ncolor_max = cache->m_slab_size % cache->m_type_size;
     862             :         }
     863             :         else
     864             :         {
     865             :             /* embedded slab struct */
     866       61008 :             cache->m_ntypes     = (cache->m_slab_size - sizeof(rtl_cache_slab_type)) / cache->m_type_size;
     867       61008 :             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      113222 :         cache->m_ncolor = 0;
     872             : 
     873      113222 :         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      113222 :         if (!(flags & RTL_CACHE_FLAG_NOMAGAZINE))
     881             :         {
     882             :             assert(gp_cache_magazine_cache != 0);
     883      110384 :             cache->m_magazine_cache = gp_cache_magazine_cache;
     884             :         }
     885             : 
     886             :         /* insert into cache list */
     887      113222 :         RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock));
     888      113222 :         QUEUE_INSERT_TAIL_NAMED(&(g_cache_list.m_cache_head), cache, cache_);
     889      113222 :         RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock));
     890             :     }
     891      113222 :     return (cache);
     892             : }
     893             : 
     894             : /** rtl_cache_deactivate()
     895             :  */
     896             : void
     897      113218 : rtl_cache_deactivate (
     898             :     rtl_cache_type * cache
     899             : )
     900             : {
     901             :     /* remove from cache list */
     902      113218 :     RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock));
     903      113218 :     bool active = !QUEUE_STARTED_NAMED(cache, cache_);
     904      113218 :     QUEUE_REMOVE_NAMED(cache, cache_);
     905      113218 :     RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock));
     906             : 
     907             :     assert(active); // orphaned cache
     908             :     (void)active;
     909             : 
     910             :     /* cleanup magazine layer */
     911      113218 :     if (cache->m_magazine_cache != 0)
     912             :     {
     913             :         rtl_cache_type *          mag_cache;
     914             :         rtl_cache_magazine_type * mag;
     915             : 
     916             :         /* prevent recursion */
     917      113218 :         mag_cache = cache->m_magazine_cache, cache->m_magazine_cache = 0;
     918             : 
     919             :         /* cleanup cpu layer */
     920      113218 :         if ((mag = cache->m_cpu_curr) != 0)
     921             :         {
     922             :             // coverity[missing_lock]
     923       61518 :             cache->m_cpu_curr = 0;
     924       61518 :             rtl_cache_magazine_clear (cache, mag);
     925       61518 :             rtl_cache_free (mag_cache, mag);
     926             :         }
     927      113218 :         if ((mag = cache->m_cpu_prev) != 0)
     928             :         {
     929             :             // coverity[missing_lock]
     930        9439 :             cache->m_cpu_prev = 0;
     931        9439 :             rtl_cache_magazine_clear (cache, mag);
     932        9439 :             rtl_cache_free (mag_cache, mag);
     933             :         }
     934             : 
     935             :         /* cleanup depot layer */
     936      442404 :         while ((mag = rtl_cache_depot_dequeue(&(cache->m_depot_full))) != 0)
     937             :         {
     938      215968 :             rtl_cache_magazine_clear (cache, mag);
     939      215968 :             rtl_cache_free (mag_cache, mag);
     940             :         }
     941      226444 :         while ((mag = rtl_cache_depot_dequeue(&(cache->m_depot_empty))) != 0)
     942             :         {
     943           8 :             rtl_cache_magazine_clear (cache, mag);
     944           8 :             rtl_cache_free (mag_cache, mag);
     945             :         }
     946             :     }
     947             : 
     948             :     // SAL_INFO(
     949             :     //  "sal.rtl",
     950             :     //  "rtl_cache_deactivate(" << cache->m_name << "): [slab]: allocs: "
     951             :     //      << cache->m_slab_stats.m_alloc << ", frees: "
     952             :     //      << cache->m_slab_stats.m_free << "; total: "
     953             :     //      << cache->m_slab_stats.m_mem_total << ", used: "
     954             :     //      << cache->m_slab_stats.m_mem_alloc << "; [cpu]: allocs: "
     955             :     //      << cache->m_cpu_stats.m_alloc << ", frees: "
     956             :     //      << cache->m_cpu_stats.m_free << "; [total]: allocs: "
     957             :     //      << (cache->m_slab_stats.m_alloc + cache->m_cpu_stats.m_alloc)
     958             :     //      << ", frees: "
     959             :     //      << (cache->m_slab_stats.m_free + cache->m_cpu_stats.m_free));
     960             : 
     961             :     /* cleanup slab layer */
     962      113218 :     if (cache->m_slab_stats.m_alloc > cache->m_slab_stats.m_free)
     963             :     {
     964             :         // SAL_INFO(
     965             :         //  "sal.rtl",
     966             :         //  "rtl_cache_deactivate(" << cache->m_name << "): cleaning up "
     967             :         //      << (cache->m_slab_stats.m_alloc - cache->m_slab_stats.m_free)
     968             :         //      << " leaked buffer(s) [" << cache->m_slab_stats.m_mem_alloc
     969             :         //      << " bytes] [" << cache->m_slab_stats.m_mem_total << " total]");
     970             : 
     971       25690 :         if (cache->m_features & RTL_CACHE_FEATURE_HASH)
     972             :         {
     973             :             /* cleanup bufctl(s) for leaking buffer(s) */
     974        2417 :             sal_Size i, n = cache->m_hash_size;
     975       80817 :             for (i = 0; i < n; i++)
     976             :             {
     977             :                 rtl_cache_bufctl_type * bufctl;
     978      176080 :                 while ((bufctl = cache->m_hash_table[i]) != 0)
     979             :                 {
     980             :                     /* pop from hash table */
     981       19280 :                     cache->m_hash_table[i] = bufctl->m_next, bufctl->m_next = 0;
     982             : 
     983             :                     /* return to bufctl cache */
     984       19280 :                     rtl_cache_free (gp_cache_bufctl_cache, bufctl);
     985             :                 }
     986             :             }
     987             :         }
     988             :         {
     989             :             /* force cleanup of remaining slabs */
     990             :             rtl_cache_slab_type *head, *slab;
     991             : 
     992       25690 :             head = &(cache->m_used_head);
     993       28322 :             for (slab = head->m_slab_next; slab != head; slab = head->m_slab_next)
     994             :             {
     995             :                 /* remove from 'used' queue */
     996        2632 :                 QUEUE_REMOVE_NAMED(slab, slab_);
     997             : 
     998             :                 /* update stats */
     999        2632 :                 cache->m_slab_stats.m_mem_total -= cache->m_slab_size;
    1000             : 
    1001             :                 /* free slab */
    1002        2632 :                 rtl_cache_slab_destroy (cache, slab);
    1003             :             }
    1004             : 
    1005       25690 :             head = &(cache->m_free_head);
    1006      119880 :             for (slab = head->m_slab_next; slab != head; slab = head->m_slab_next)
    1007             :             {
    1008             :                 /* remove from 'free' queue */
    1009       94190 :                 QUEUE_REMOVE_NAMED(slab, slab_);
    1010             : 
    1011             :                 /* update stats */
    1012       94190 :                 cache->m_slab_stats.m_mem_total -= cache->m_slab_size;
    1013             : 
    1014             :                 /* free slab */
    1015       94190 :                 rtl_cache_slab_destroy (cache, slab);
    1016             :             }
    1017             :         }
    1018             :     }
    1019             : 
    1020      113218 :     if (cache->m_hash_table != cache->m_hash_table_0)
    1021             :     {
    1022             :         rtl_arena_free (
    1023             :             gp_cache_arena,
    1024             :             cache->m_hash_table,
    1025         545 :             cache->m_hash_size * sizeof(rtl_cache_bufctl_type*));
    1026             : 
    1027         545 :         cache->m_hash_table = cache->m_hash_table_0;
    1028         545 :         cache->m_hash_size  = RTL_CACHE_HASH_SIZE;
    1029         545 :         cache->m_hash_shift = highbit(cache->m_hash_size) - 1;
    1030             :     }
    1031      113218 : }
    1032             : 
    1033             : } //namespace
    1034             : 
    1035             : /* ================================================================= *
    1036             :  *
    1037             :  * cache implementation.
    1038             :  *
    1039             :  * ================================================================= */
    1040             : 
    1041             : /** rtl_cache_create()
    1042             :  */
    1043             : rtl_cache_type *
    1044      104708 : SAL_CALL rtl_cache_create (
    1045             :     const char *     name,
    1046             :     sal_Size         objsize,
    1047             :     sal_Size         objalign,
    1048             :     int  (SAL_CALL * constructor)(void * obj, void * userarg),
    1049             :     void (SAL_CALL * destructor) (void * obj, void * userarg),
    1050             :     void (SAL_CALL * reclaim)    (void * userarg),
    1051             :     void *           userarg,
    1052             :     rtl_arena_type * source,
    1053             :     int              flags
    1054             : ) SAL_THROW_EXTERN_C()
    1055             : {
    1056      104708 :     rtl_cache_type * result = 0;
    1057      104708 :     sal_Size         size   = sizeof(rtl_cache_type);
    1058             : 
    1059             : try_alloc:
    1060      107546 :     result = (rtl_cache_type*)rtl_arena_alloc (gp_cache_arena, &size);
    1061      107546 :     if (result != 0)
    1062             :     {
    1063      104708 :         rtl_cache_type * cache = result;
    1064      104708 :         (void) rtl_cache_constructor (cache);
    1065             : 
    1066      104708 :         if (!source)
    1067             :         {
    1068             :             /* use default arena */
    1069             :             assert(gp_default_arena != 0);
    1070      104708 :             source = gp_default_arena;
    1071             :         }
    1072             : 
    1073             :         result = rtl_cache_activate (
    1074             :             cache,
    1075             :             name,
    1076             :             objsize,
    1077             :             objalign,
    1078             :             constructor,
    1079             :             destructor,
    1080             :             reclaim,
    1081             :             userarg,
    1082             :             source,
    1083             :             flags
    1084      104708 :         );
    1085             : 
    1086      104708 :         if (result == 0)
    1087             :         {
    1088             :             /* activation failed */
    1089           0 :             rtl_cache_deactivate (cache);
    1090           0 :             rtl_cache_destructor (cache);
    1091           0 :             rtl_arena_free (gp_cache_arena, cache, size);
    1092             :         }
    1093             :     }
    1094        2838 :     else if (gp_cache_arena == 0)
    1095             :     {
    1096        2838 :         ensureCacheSingleton();
    1097        2838 :         if (gp_cache_arena)
    1098             :         {
    1099             :             /* try again */
    1100        2838 :             goto try_alloc;
    1101             :         }
    1102             :     }
    1103      104708 :     return (result);
    1104             : }
    1105             : 
    1106             : /** rtl_cache_destroy()
    1107             :  */
    1108      104704 : void SAL_CALL rtl_cache_destroy (
    1109             :     rtl_cache_type * cache
    1110             : ) SAL_THROW_EXTERN_C()
    1111             : {
    1112      104704 :     if (cache != 0)
    1113             :     {
    1114      104704 :         rtl_cache_deactivate (cache);
    1115      104704 :         rtl_cache_destructor (cache);
    1116      104704 :         rtl_arena_free (gp_cache_arena, cache, sizeof(rtl_cache_type));
    1117             :     }
    1118      104704 : }
    1119             : 
    1120             : /** rtl_cache_alloc()
    1121             :  */
    1122             : void *
    1123   316617041 : SAL_CALL rtl_cache_alloc (
    1124             :     rtl_cache_type * cache
    1125             : ) SAL_THROW_EXTERN_C()
    1126             : {
    1127   316617041 :     void * obj = 0;
    1128             : 
    1129   316617041 :     if (cache == 0)
    1130        2482 :         return (0);
    1131             : 
    1132   316614559 :     if (alloc_mode == AMode_SYSTEM)
    1133             :     {
    1134      324278 :         obj = rtl_allocateMemory(cache->m_type_size);
    1135      324278 :         if ((obj != 0) && (cache->m_constructor != 0))
    1136             :         {
    1137         280 :             if (!((cache->m_constructor)(obj, cache->m_userarg)))
    1138             :             {
    1139             :                 /* construction failure */
    1140           0 :                 rtl_freeMemory(obj), obj = 0;
    1141             :             }
    1142             :         }
    1143      324278 :         return obj;
    1144             :     }
    1145             : 
    1146   316290281 :     RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_depot_lock));
    1147   316292113 :     if (cache->m_cpu_curr != 0)
    1148             :     {
    1149             :         for (;;)
    1150             :         {
    1151             :             /* take object from magazine layer */
    1152             :             rtl_cache_magazine_type *curr, *prev, *temp;
    1153             : 
    1154   317101778 :             curr = cache->m_cpu_curr;
    1155   317101778 :             if ((curr != 0) && (curr->m_mag_used > 0))
    1156             :             {
    1157   300253997 :                 obj = curr->m_objects[--curr->m_mag_used];
    1158   300253997 :                 cache->m_cpu_stats.m_alloc += 1;
    1159   300253997 :                 RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock));
    1160             : 
    1161   300253876 :                 return (obj);
    1162             :             }
    1163             : 
    1164    16847781 :             prev = cache->m_cpu_prev;
    1165    16847781 :             if ((prev != 0) && (prev->m_mag_used > 0))
    1166             :             {
    1167     1081735 :                 temp = cache->m_cpu_curr;
    1168     1081735 :                 cache->m_cpu_curr = cache->m_cpu_prev;
    1169     1081735 :                 cache->m_cpu_prev = temp;
    1170             : 
    1171     1081735 :                 continue;
    1172             :             }
    1173             : 
    1174    15766046 :             temp = rtl_cache_depot_exchange_alloc (cache, prev);
    1175    15766044 :             if (temp != 0)
    1176             :             {
    1177      348159 :                 cache->m_cpu_prev = cache->m_cpu_curr;
    1178      348159 :                 cache->m_cpu_curr = temp;
    1179             : 
    1180      348159 :                 continue;
    1181             :             }
    1182             : 
    1183             :             /* no full magazine: fall through to slab layer */
    1184    15417885 :             break;
    1185     1429894 :         }
    1186             :     }
    1187    16038114 :     RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock));
    1188             : 
    1189             :     /* alloc buffer from slab layer */
    1190    16038205 :     obj = rtl_cache_slab_alloc (cache);
    1191    16038202 :     if ((obj != 0) && (cache->m_constructor != 0))
    1192             :     {
    1193             :         /* construct object */
    1194      303043 :         if (!((cache->m_constructor)(obj, cache->m_userarg)))
    1195             :         {
    1196             :             /* construction failure */
    1197           0 :             rtl_cache_slab_free (cache, obj), obj = 0;
    1198             :         }
    1199             :     }
    1200    16038202 :     return (obj);
    1201             : }
    1202             : 
    1203             : /** rtl_cache_free()
    1204             :  */
    1205             : void
    1206   315749300 : SAL_CALL rtl_cache_free (
    1207             :     rtl_cache_type * cache,
    1208             :     void *           obj
    1209             : ) SAL_THROW_EXTERN_C()
    1210             : {
    1211   315749300 :     if ((obj != 0) && (cache != 0))
    1212             :     {
    1213   315435105 :         if (alloc_mode == AMode_SYSTEM)
    1214             :         {
    1215      324085 :             if (cache->m_destructor != 0)
    1216             :             {
    1217             :                 /* destruct object */
    1218           0 :                 (cache->m_destructor)(obj, cache->m_userarg);
    1219             :             }
    1220      324085 :             rtl_freeMemory(obj);
    1221      324085 :             return;
    1222             :         }
    1223             : 
    1224   315111020 :         RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_depot_lock));
    1225             : 
    1226             :         for (;;)
    1227             :         {
    1228             :             /* return object to magazine layer */
    1229             :             rtl_cache_magazine_type *curr, *prev, *temp;
    1230             : 
    1231   317132346 :             curr = cache->m_cpu_curr;
    1232   317132346 :             if ((curr != 0) && (curr->m_mag_used < curr->m_mag_size))
    1233             :             {
    1234   315105871 :                 curr->m_objects[curr->m_mag_used++] = obj;
    1235   315105871 :                 cache->m_cpu_stats.m_free += 1;
    1236   315105871 :                 RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock));
    1237             : 
    1238   315105874 :                 return;
    1239             :             }
    1240             : 
    1241     2026475 :             prev = cache->m_cpu_prev;
    1242     2026475 :             if ((prev != 0) && (prev->m_mag_used == 0))
    1243             :             {
    1244     1081733 :                 temp = cache->m_cpu_curr;
    1245     1081733 :                 cache->m_cpu_curr = cache->m_cpu_prev;
    1246     1081733 :                 cache->m_cpu_prev = temp;
    1247             : 
    1248     1081733 :                 continue;
    1249             :             }
    1250             : 
    1251      944742 :             temp = rtl_cache_depot_exchange_free (cache, prev);
    1252      944742 :             if (temp != 0)
    1253             :             {
    1254      642947 :                 cache->m_cpu_prev = cache->m_cpu_curr;
    1255      642947 :                 cache->m_cpu_curr = temp;
    1256             : 
    1257      642947 :                 continue;
    1258             :             }
    1259             : 
    1260      301795 :             if (rtl_cache_depot_populate(cache))
    1261             :             {
    1262      295920 :                 continue;
    1263             :             }
    1264             : 
    1265             :             /* no empty magazine: fall through to slab layer */
    1266        5875 :             break;
    1267     2020600 :         }
    1268             : 
    1269        5875 :         RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock));
    1270             : 
    1271             :         /* no space for constructed object in magazine layer */
    1272        5875 :         if (cache->m_destructor != 0)
    1273             :         {
    1274             :             /* destruct object */
    1275        5875 :             (cache->m_destructor)(obj, cache->m_userarg);
    1276             :         }
    1277             : 
    1278             :         /* return buffer to slab layer */
    1279        5875 :         rtl_cache_slab_free (cache, obj);
    1280             :     }
    1281             : }
    1282             : 
    1283             : /* ================================================================= *
    1284             :  *
    1285             :  * cache wsupdate (machdep) internals.
    1286             :  *
    1287             :  * ================================================================= */
    1288             : 
    1289             : /** rtl_cache_wsupdate_init()
    1290             :  *
    1291             :  *  @precond g_cache_list.m_lock initialized
    1292             :  */
    1293             : static void
    1294             : rtl_cache_wsupdate_init();
    1295             : 
    1296             : /** rtl_cache_wsupdate_wait()
    1297             :  *
    1298             :  *  @precond g_cache_list.m_lock acquired
    1299             :  */
    1300             : static void
    1301             : rtl_cache_wsupdate_wait (
    1302             :     unsigned int seconds
    1303             : );
    1304             : 
    1305             : /** rtl_cache_wsupdate_fini()
    1306             :  *
    1307             :  */
    1308             : static void
    1309             : rtl_cache_wsupdate_fini();
    1310             : 
    1311             : /* ================================================================= */
    1312             : 
    1313             : #if defined(SAL_UNX)
    1314             : 
    1315             : #include <sys/time.h>
    1316             : 
    1317             : static void *
    1318             : rtl_cache_wsupdate_all (void * arg);
    1319             : 
    1320             : static void
    1321        2838 : rtl_cache_wsupdate_init()
    1322             : {
    1323        2838 :     RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock));
    1324        2838 :     g_cache_list.m_update_done = 0;
    1325        2838 :     (void) pthread_cond_init (&(g_cache_list.m_update_cond), NULL);
    1326        2838 :     if (pthread_create (
    1327        2838 :             &(g_cache_list.m_update_thread), NULL, rtl_cache_wsupdate_all, (void*)(10)) != 0)
    1328             :     {
    1329             :         /* failure */
    1330           0 :         g_cache_list.m_update_thread = (pthread_t)(0);
    1331             :     }
    1332        2838 :     RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock));
    1333        2838 : }
    1334             : 
    1335             : static void
    1336        3392 : rtl_cache_wsupdate_wait (unsigned int seconds)
    1337             : {
    1338        3392 :     if (seconds > 0)
    1339             :     {
    1340             :         timeval  now;
    1341             :         timespec wakeup;
    1342             : 
    1343        3392 :         gettimeofday(&now, 0);
    1344        3392 :         wakeup.tv_sec  = now.tv_sec + (seconds);
    1345        3392 :         wakeup.tv_nsec = now.tv_usec * 1000;
    1346             : 
    1347             :         (void) pthread_cond_timedwait (
    1348             :             &(g_cache_list.m_update_cond),
    1349             :             &(g_cache_list.m_lock),
    1350        3392 :             &wakeup);
    1351             :     }
    1352        3393 : }
    1353             : 
    1354             : static void
    1355        2838 : rtl_cache_wsupdate_fini()
    1356             : {
    1357        2838 :     RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock));
    1358        2838 :     g_cache_list.m_update_done = 1;
    1359        2838 :     pthread_cond_signal (&(g_cache_list.m_update_cond));
    1360        2838 :     RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock));
    1361             : 
    1362        2838 :     if (g_cache_list.m_update_thread != (pthread_t)(0))
    1363        2838 :         pthread_join (g_cache_list.m_update_thread, NULL);
    1364        2838 : }
    1365             : 
    1366             : /* ================================================================= */
    1367             : 
    1368             : #elif defined(SAL_W32)
    1369             : 
    1370             : static DWORD WINAPI
    1371             : rtl_cache_wsupdate_all (void * arg);
    1372             : 
    1373             : static void
    1374             : rtl_cache_wsupdate_init()
    1375             : {
    1376             :     DWORD dwThreadId;
    1377             : 
    1378             :     RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock));
    1379             :     g_cache_list.m_update_done = 0;
    1380             :     g_cache_list.m_update_cond = CreateEvent (0, TRUE, FALSE, 0);
    1381             : 
    1382             :     g_cache_list.m_update_thread =
    1383             :         CreateThread (NULL, 0, rtl_cache_wsupdate_all, (LPVOID)(10), 0, &dwThreadId);
    1384             :     RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock));
    1385             : }
    1386             : 
    1387             : static void
    1388             : rtl_cache_wsupdate_wait (unsigned int seconds)
    1389             : {
    1390             :     if (seconds > 0)
    1391             :     {
    1392             :         RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock));
    1393             :         WaitForSingleObject (g_cache_list.m_update_cond, (DWORD)(seconds * 1000));
    1394             :         RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock));
    1395             :     }
    1396             : }
    1397             : 
    1398             : static void
    1399             : rtl_cache_wsupdate_fini()
    1400             : {
    1401             :     RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock));
    1402             :     g_cache_list.m_update_done = 1;
    1403             :     SetEvent (g_cache_list.m_update_cond);
    1404             :     RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock));
    1405             : 
    1406             :     WaitForSingleObject (g_cache_list.m_update_thread, INFINITE);
    1407             : }
    1408             : 
    1409             : #endif /* SAL_UNX || SAL_W32 */
    1410             : 
    1411             : /* ================================================================= */
    1412             : 
    1413             : /** rtl_cache_depot_wsupdate()
    1414             :  *  update depot stats and purge excess magazines.
    1415             :  *
    1416             :  *  @precond cache->m_depot_lock acquired
    1417             :  */
    1418             : static void
    1419       69822 : rtl_cache_depot_wsupdate (
    1420             :     rtl_cache_type *       cache,
    1421             :     rtl_cache_depot_type * depot
    1422             : )
    1423             : {
    1424             :     sal_Size npurge;
    1425             : 
    1426       69822 :     depot->m_prev_min = depot->m_curr_min;
    1427       69822 :     depot->m_curr_min = depot->m_mag_count;
    1428             : 
    1429       69822 :     npurge = depot->m_curr_min < depot->m_prev_min ? depot->m_curr_min : depot->m_prev_min;
    1430       78806 :     for (; npurge > 0; npurge--)
    1431             :     {
    1432        8984 :         rtl_cache_magazine_type * mag = rtl_cache_depot_dequeue (depot);
    1433        8984 :         if (mag != 0)
    1434             :         {
    1435        8984 :             RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock));
    1436        8984 :             rtl_cache_magazine_clear (cache, mag);
    1437        8984 :             rtl_cache_free (cache->m_magazine_cache, mag);
    1438        8984 :             RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_depot_lock));
    1439             :         }
    1440             :     }
    1441       69822 : }
    1442             : 
    1443             : /** rtl_cache_wsupdate()
    1444             :  *
    1445             :  *  @precond cache->m_depot_lock released
    1446             :  */
    1447             : static void
    1448       34911 : rtl_cache_wsupdate (
    1449             :     rtl_cache_type * cache
    1450             : )
    1451             : {
    1452       34911 :     if (cache->m_magazine_cache != 0)
    1453             :     {
    1454       34911 :         RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_depot_lock));
    1455             : 
    1456             :         // SAL_INFO(
    1457             :         //  "sal.rtl",
    1458             :         //  "rtl_cache_wsupdate(" << cache->m_name
    1459             :         //      << ") [depot: count, curr_min, prev_min] full: "
    1460             :         //      << cache->m_depot_full.m_mag_count << ", "
    1461             :         //      << cache->m_depot_full.m_curr_min << ", "
    1462             :         //      << cache->m_depot_full.m_prev_min << "; empty: "
    1463             :         //      << cache->m_depot_empty.m_mag_count << ", "
    1464             :         //      << cache->m_depot_empty.m_curr_min << ", "
    1465             :         //      << cache->m_depot_empty.m_prev_min);
    1466             : 
    1467       34911 :         rtl_cache_depot_wsupdate (cache, &(cache->m_depot_full));
    1468       34911 :         rtl_cache_depot_wsupdate (cache, &(cache->m_depot_empty));
    1469             : 
    1470       34911 :         RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock));
    1471             :     }
    1472       34911 : }
    1473             : 
    1474             : /** rtl_cache_wsupdate_all()
    1475             :  *
    1476             :  */
    1477             : #if defined(SAL_UNX)
    1478             : static void *
    1479             : #elif defined(SAL_W32)
    1480             : static DWORD WINAPI
    1481             : #endif /* SAL_UNX || SAL_W32 */
    1482        2837 : rtl_cache_wsupdate_all (void * arg)
    1483             : {
    1484        2837 :     osl::Thread::setName("rtl_cache_wsupdate_all");
    1485             :     unsigned int seconds = sal::static_int_cast< unsigned int >(
    1486        2837 :         reinterpret_cast< sal_uIntPtr >(arg));
    1487             : 
    1488        2837 :     RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock));
    1489        9067 :     while (!g_cache_list.m_update_done)
    1490             :     {
    1491        3392 :         rtl_cache_wsupdate_wait (seconds);
    1492        3393 :         if (!g_cache_list.m_update_done)
    1493             :         {
    1494             :             rtl_cache_type * head, * cache;
    1495             : 
    1496        1034 :             head = &(g_cache_list.m_cache_head);
    1497       35945 :             for (cache  = head->m_cache_next;
    1498             :                  cache != head;
    1499             :                  cache  = cache->m_cache_next)
    1500             :             {
    1501       34911 :                 rtl_cache_wsupdate (cache);
    1502             :             }
    1503             :         }
    1504             :     }
    1505        2838 :     RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock));
    1506             : 
    1507        2838 :     return (0);
    1508             : }
    1509             : 
    1510             : /* ================================================================= *
    1511             :  *
    1512             :  * cache initialization.
    1513             :  *
    1514             :  * ================================================================= */
    1515             : 
    1516             : void
    1517        2838 : rtl_cache_init()
    1518             : {
    1519             :     {
    1520             :         /* list of caches */
    1521        2838 :         RTL_MEMORY_LOCK_INIT(&(g_cache_list.m_lock));
    1522        2838 :         (void) rtl_cache_constructor (&(g_cache_list.m_cache_head));
    1523             :     }
    1524             :     {
    1525             :         /* cache: internal arena */
    1526             :         assert(gp_cache_arena == 0);
    1527             : 
    1528             :         gp_cache_arena = rtl_arena_create (
    1529             :             "rtl_cache_internal_arena",
    1530             :             64,   /* quantum */
    1531             :             0,    /* no quantum caching */
    1532             :             NULL, /* default source */
    1533             :             rtl_arena_alloc,
    1534             :             rtl_arena_free,
    1535             :             0     /* flags */
    1536        2838 :         );
    1537             :         assert(gp_cache_arena != 0);
    1538             : 
    1539             :         /* check 'gp_default_arena' initialization */
    1540             :         assert(gp_default_arena != 0);
    1541             :     }
    1542             :     {
    1543             :         /* cache: magazine cache */
    1544             :         static rtl_cache_type g_cache_magazine_cache;
    1545             : 
    1546             :         assert(gp_cache_magazine_cache == 0);
    1547        2838 :         (void) rtl_cache_constructor (&g_cache_magazine_cache);
    1548             : 
    1549             :         gp_cache_magazine_cache = rtl_cache_activate (
    1550             :             &g_cache_magazine_cache,
    1551             :             "rtl_cache_magazine_cache",
    1552             :             sizeof(rtl_cache_magazine_type), /* objsize  */
    1553             :             0,                               /* objalign */
    1554             :             rtl_cache_magazine_constructor,
    1555             :             rtl_cache_magazine_destructor,
    1556             :             0, /* reclaim */
    1557             :             0, /* userarg: NYI */
    1558             :             gp_default_arena, /* source */
    1559             :             RTL_CACHE_FLAG_NOMAGAZINE /* during bootstrap; activated below */
    1560        2838 :         );
    1561             :         assert(gp_cache_magazine_cache != 0);
    1562             : 
    1563             :         /* activate magazine layer */
    1564        2838 :         g_cache_magazine_cache.m_magazine_cache = gp_cache_magazine_cache;
    1565             :     }
    1566             :     {
    1567             :         /* cache: slab (struct) cache */
    1568             :         static rtl_cache_type g_cache_slab_cache;
    1569             : 
    1570             :         assert(gp_cache_slab_cache == 0);
    1571        2838 :         (void) rtl_cache_constructor (&g_cache_slab_cache);
    1572             : 
    1573             :         gp_cache_slab_cache = rtl_cache_activate (
    1574             :             &g_cache_slab_cache,
    1575             :             "rtl_cache_slab_cache",
    1576             :             sizeof(rtl_cache_slab_type), /* objsize  */
    1577             :             0,                           /* objalign */
    1578             :             rtl_cache_slab_constructor,
    1579             :             rtl_cache_slab_destructor,
    1580             :             0,                           /* reclaim */
    1581             :             0,                           /* userarg: none */
    1582             :             gp_default_arena,            /* source */
    1583             :             0                            /* flags: none */
    1584        2838 :         );
    1585             :         assert(gp_cache_slab_cache != 0);
    1586             :     }
    1587             :     {
    1588             :         /* cache: bufctl cache */
    1589             :         static rtl_cache_type g_cache_bufctl_cache;
    1590             : 
    1591             :         assert(gp_cache_bufctl_cache == 0);
    1592        2838 :         (void) rtl_cache_constructor (&g_cache_bufctl_cache);
    1593             : 
    1594             :         gp_cache_bufctl_cache = rtl_cache_activate (
    1595             :             &g_cache_bufctl_cache,
    1596             :             "rtl_cache_bufctl_cache",
    1597             :             sizeof(rtl_cache_bufctl_type), /* objsize */
    1598             :             0,                             /* objalign  */
    1599             :             0,                /* constructor */
    1600             :             0,                /* destructor */
    1601             :             0,                /* reclaim */
    1602             :             0,                /* userarg */
    1603             :             gp_default_arena, /* source */
    1604             :             0                 /* flags: none */
    1605        2838 :         );
    1606             :         assert(gp_cache_bufctl_cache != 0);
    1607             :     }
    1608             : 
    1609        2838 :     rtl_cache_wsupdate_init();
    1610             :     // SAL_INFO("sal.rtl", "rtl_cache_init completed");
    1611        2838 : }
    1612             : 
    1613             : /* ================================================================= */
    1614             : 
    1615             : void
    1616        2838 : rtl_cache_fini()
    1617             : {
    1618        2838 :     if (gp_cache_arena != 0)
    1619             :     {
    1620             :         rtl_cache_type * cache, * head;
    1621             : 
    1622        2838 :         rtl_cache_wsupdate_fini();
    1623             : 
    1624        2838 :         if (gp_cache_bufctl_cache != 0)
    1625             :         {
    1626        2838 :             cache = gp_cache_bufctl_cache, gp_cache_bufctl_cache = 0;
    1627        2838 :             rtl_cache_deactivate (cache);
    1628        2838 :             rtl_cache_destructor (cache);
    1629             :         }
    1630        2838 :         if (gp_cache_slab_cache != 0)
    1631             :         {
    1632        2838 :             cache = gp_cache_slab_cache, gp_cache_slab_cache = 0;
    1633        2838 :             rtl_cache_deactivate (cache);
    1634        2838 :             rtl_cache_destructor (cache);
    1635             :         }
    1636        2838 :         if (gp_cache_magazine_cache != 0)
    1637             :         {
    1638        2838 :             cache = gp_cache_magazine_cache, gp_cache_magazine_cache = 0;
    1639        2838 :             rtl_cache_deactivate (cache);
    1640        2838 :             rtl_cache_destructor (cache);
    1641             :         }
    1642        2838 :         if (gp_cache_arena != 0)
    1643             :         {
    1644        2838 :             rtl_arena_destroy (gp_cache_arena);
    1645        2838 :             gp_cache_arena = 0;
    1646             :         }
    1647             : 
    1648        2838 :         RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock));
    1649        2838 :         head = &(g_cache_list.m_cache_head);
    1650        2838 :         for (cache = head->m_cache_next; cache != head; cache = cache->m_cache_next)
    1651             :         {
    1652             :             // SAL_INFO(
    1653             :             //  "sal.rtl",
    1654             :             //  "rtl_cache_fini(" << cache->m_name << ") [slab]: allocs: "
    1655             :             //      << cache->m_slab_stats.m_alloc << ", frees: "
    1656             :             //      << cache->m_slab_stats.m_free << "; total: "
    1657             :             //      << cache->m_slab_stats.m_mem_total << ", used: "
    1658             :             //      << cache->m_slab_stats.m_mem_alloc << "; [cpu]: allocs: "
    1659             :             //      << cache->m_cpu_stats.m_alloc << ", frees: "
    1660             :             //      << cache->m_cpu_stats.m_free  << "; [total]: allocs: "
    1661             :             //      << (cache->m_slab_stats.m_alloc
    1662             :             //          + cache->m_cpu_stats.m_alloc)
    1663             :             //      << ", frees: "
    1664             :             //      << (cache->m_slab_stats.m_free
    1665             :             //          + cache->m_cpu_stats.m_free));
    1666             :         }
    1667        2838 :         RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock));
    1668             :     }
    1669             :     // SAL_INFO("sal.rtl", "rtl_cache_fini completed");
    1670        2838 : }
    1671             : 
    1672             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10