LCOV - code coverage report
Current view: top level - sal/rtl - alloc_cache.cxx (source / functions) Hit Total Coverage
Test: commit e02a6cb2c3e2b23b203b422e4e0680877f232636 Lines: 190 494 38.5 %
Date: 2014-04-14 Functions: 17 34 50.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           0 : 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           0 :     new_bytes = new_size * sizeof(rtl_cache_bufctl_type*);
     105           0 :     new_table = (rtl_cache_bufctl_type**)rtl_arena_alloc(gp_cache_arena, &new_bytes);
     106             : 
     107           0 :     if (new_table != 0)
     108             :     {
     109             :         rtl_cache_bufctl_type ** old_table;
     110             :         sal_Size                 old_size, i;
     111             : 
     112           0 :         memset (new_table, 0, new_bytes);
     113             : 
     114           0 :         RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_slab_lock));
     115             : 
     116           0 :         old_table = cache->m_hash_table;
     117           0 :         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           0 :         cache->m_hash_table = new_table;
     130           0 :         cache->m_hash_size  = new_size;
     131           0 :         cache->m_hash_shift = highbit(cache->m_hash_size) - 1;
     132             : 
     133           0 :         for (i = 0; i < old_size; i++)
     134             :         {
     135           0 :             rtl_cache_bufctl_type * curr = old_table[i];
     136           0 :             while (curr != 0)
     137             :             {
     138           0 :                 rtl_cache_bufctl_type  * next = curr->m_next;
     139             :                 rtl_cache_bufctl_type ** head;
     140             : 
     141           0 :                 head = &(cache->m_hash_table[RTL_CACHE_HASH_INDEX(cache, curr->m_addr)]);
     142           0 :                 curr->m_next = (*head);
     143           0 :                 (*head) = curr;
     144             : 
     145           0 :                 curr = next;
     146             :             }
     147           0 :             old_table[i] = 0;
     148             :         }
     149             : 
     150           0 :         RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock));
     151             : 
     152           0 :         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           0 : }
     159             : 
     160             : inline sal_uIntPtr
     161           0 : 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           0 :     ppHead = &(cache->m_hash_table[RTL_CACHE_HASH_INDEX(cache, bufctl->m_addr)]);
     169             : 
     170           0 :     bufctl->m_next = (*ppHead);
     171           0 :     (*ppHead) = bufctl;
     172             : 
     173           0 :     return (bufctl->m_addr);
     174             : }
     175             : 
     176             : /** rtl_cache_hash_remove()
     177             :  */
     178             : rtl_cache_bufctl_type *
     179           0 : 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           0 :     sal_Size                 lookups = 0;
     187             : 
     188           0 :     ppHead = &(cache->m_hash_table[RTL_CACHE_HASH_INDEX(cache, addr)]);
     189           0 :     while ((bufctl = *ppHead) != 0)
     190             :     {
     191           0 :         if (bufctl->m_addr == addr)
     192             :         {
     193           0 :             *ppHead = bufctl->m_next, bufctl->m_next = 0;
     194           0 :             break;
     195             :         }
     196             : 
     197           0 :         lookups += 1;
     198           0 :         ppHead = &(bufctl->m_next);
     199             :     }
     200             : 
     201             :     assert(bufctl != 0); // bad free
     202             : 
     203           0 :     if (lookups > 1)
     204             :     {
     205           0 :         sal_Size nbuf = (sal_Size)(cache->m_slab_stats.m_alloc - cache->m_slab_stats.m_free);
     206           0 :         if (nbuf > 4 * cache->m_hash_size)
     207             :         {
     208           0 :             if (!(cache->m_features & RTL_CACHE_FEATURE_RESCALE))
     209             :             {
     210           0 :                 sal_Size ave = nbuf >> cache->m_hash_shift;
     211           0 :                 sal_Size new_size = cache->m_hash_size << (highbit(ave) - 1);
     212             : 
     213           0 :                 cache->m_features |= RTL_CACHE_FEATURE_RESCALE;
     214           0 :                 RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock));
     215           0 :                 rtl_cache_hash_rescale (cache, new_size);
     216           0 :                 RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_slab_lock));
     217           0 :                 cache->m_features &= ~RTL_CACHE_FEATURE_RESCALE;
     218             :             }
     219             :         }
     220             :     }
     221             : 
     222           0 :     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           0 : rtl_cache_slab_constructor (void * obj, SAL_UNUSED_PARAMETER void *)
     236             : {
     237           0 :     rtl_cache_slab_type * slab = (rtl_cache_slab_type*)(obj);
     238             : 
     239           0 :     QUEUE_START_NAMED(slab, slab_);
     240           0 :     slab->m_ntypes = 0;
     241             : 
     242           0 :     return (1);
     243             : }
     244             : 
     245             : /** rtl_cache_slab_destructor()
     246             :  */
     247             : void
     248           0 : rtl_cache_slab_destructor (void * obj, SAL_UNUSED_PARAMETER void *)
     249             : {
     250           0 :     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           0 : }
     255             : 
     256             : /** rtl_cache_slab_create()
     257             :  *
     258             :  *  @precond cache->m_slab_lock released.
     259             :  */
     260             : rtl_cache_slab_type *
     261           0 : rtl_cache_slab_create (
     262             :     rtl_cache_type * cache
     263             : )
     264             : {
     265           0 :     rtl_cache_slab_type * slab = 0;
     266             :     void *                addr;
     267             :     sal_Size              size;
     268             : 
     269           0 :     size = cache->m_slab_size;
     270           0 :     addr = rtl_arena_alloc (cache->m_source, &size);
     271           0 :     if (addr != 0)
     272             :     {
     273             :         assert(size >= cache->m_slab_size);
     274             : 
     275           0 :         if (cache->m_features & RTL_CACHE_FEATURE_HASH)
     276             :         {
     277             :             /* allocate slab struct from slab cache */
     278             :             assert(cache != gp_cache_slab_cache);
     279           0 :             slab = (rtl_cache_slab_type*)rtl_cache_alloc (gp_cache_slab_cache);
     280             :         }
     281             :         else
     282             :         {
     283             :             /* construct embedded slab struct */
     284           0 :             slab = RTL_CACHE_SLAB(addr, cache->m_slab_size);
     285           0 :             (void) rtl_cache_slab_constructor (slab, 0);
     286             :         }
     287           0 :         if (slab != 0)
     288             :         {
     289           0 :             slab->m_data = (sal_uIntPtr)(addr);
     290             : 
     291             :             /* dynamic freelist initialization */
     292           0 :             slab->m_bp = slab->m_data;
     293           0 :             slab->m_sp = 0;
     294             :         }
     295             :         else
     296             :         {
     297           0 :             rtl_arena_free (cache->m_source, addr, size);
     298             :         }
     299             :     }
     300           0 :     return (slab);
     301             : }
     302             : 
     303             : /** rtl_cache_slab_destroy()
     304             :  *
     305             :  *  @precond cache->m_slab_lock released.
     306             :  */
     307             : void
     308           0 : rtl_cache_slab_destroy (
     309             :     rtl_cache_type *      cache,
     310             :     rtl_cache_slab_type * slab
     311             : )
     312             : {
     313           0 :     void *   addr   = (void*)(slab->m_data);
     314           0 :     sal_Size refcnt = slab->m_ntypes; slab->m_ntypes = 0;
     315             : 
     316           0 :     if (cache->m_features & RTL_CACHE_FEATURE_HASH)
     317             :     {
     318             :         /* cleanup bufctl(s) for free buffer(s) */
     319           0 :         sal_Size ntypes = (slab->m_bp - slab->m_data) / cache->m_type_size;
     320           0 :         for (ntypes -= refcnt; slab->m_sp != 0; ntypes--)
     321             :         {
     322           0 :             rtl_cache_bufctl_type * bufctl = slab->m_sp;
     323             : 
     324             :             /* pop from freelist */
     325           0 :             slab->m_sp = bufctl->m_next, bufctl->m_next = 0;
     326             : 
     327             :             /* return bufctl struct to bufctl cache */
     328           0 :             rtl_cache_free (gp_cache_bufctl_cache, bufctl);
     329             :         }
     330             :         assert(ntypes == 0);
     331             : 
     332             :         /* return slab struct to slab cache */
     333           0 :         rtl_cache_free (gp_cache_slab_cache, slab);
     334             :     }
     335             :     else
     336             :     {
     337             :         /* destruct embedded slab struct */
     338           0 :         rtl_cache_slab_destructor (slab, 0);
     339             :     }
     340             : 
     341           0 :     if ((refcnt == 0) || (cache->m_features & RTL_CACHE_FEATURE_BULKDESTROY))
     342             :     {
     343             :         /* free memory */
     344           0 :         rtl_arena_free (cache->m_source, addr, cache->m_slab_size);
     345             :     }
     346           0 : }
     347             : 
     348             : /** rtl_cache_slab_populate()
     349             :  *
     350             :  *  @precond cache->m_slab_lock acquired.
     351             :  */
     352             : bool
     353           0 : rtl_cache_slab_populate (
     354             :     rtl_cache_type * cache
     355             : )
     356             : {
     357             :     rtl_cache_slab_type * slab;
     358             : 
     359           0 :     RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock));
     360           0 :     slab = rtl_cache_slab_create (cache);
     361           0 :     RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_slab_lock));
     362           0 :     if (slab != 0)
     363             :     {
     364             :         /* update buffer start addr w/ current color */
     365           0 :         slab->m_bp += cache->m_ncolor;
     366             : 
     367             :         /* update color for next slab */
     368           0 :         cache->m_ncolor += cache->m_type_align;
     369           0 :         if (cache->m_ncolor > cache->m_ncolor_max)
     370           0 :             cache->m_ncolor = 0;
     371             : 
     372             :         /* update stats */
     373           0 :         cache->m_slab_stats.m_mem_total += cache->m_slab_size;
     374             : 
     375             :         /* insert onto 'free' queue */
     376           0 :         QUEUE_INSERT_HEAD_NAMED(&(cache->m_free_head), slab, slab_);
     377             :     }
     378           0 :     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           0 : rtl_cache_slab_alloc (
     389             :     rtl_cache_type * cache
     390             : )
     391             : {
     392           0 :     void                * addr = 0;
     393             :     rtl_cache_slab_type * head;
     394             : 
     395           0 :     RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_slab_lock));
     396             : 
     397           0 :     head = &(cache->m_free_head);
     398           0 :     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           0 :         slab = head->m_slab_next;
     404             :         assert(slab->m_ntypes < cache->m_ntypes);
     405             : 
     406           0 :         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           0 :             if (cache->m_features & RTL_CACHE_FEATURE_HASH)
     411             :             {
     412             :                 /* allocate bufctl */
     413             :                 assert(cache != gp_cache_bufctl_cache);
     414           0 :                 bufctl = (rtl_cache_bufctl_type*)rtl_cache_alloc (gp_cache_bufctl_cache);
     415           0 :                 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           0 :                 bufctl->m_addr = slab->m_bp;
     423           0 :                 bufctl->m_slab = (sal_uIntPtr)(slab);
     424             :             }
     425             :             else
     426             :             {
     427             :                 /* embedded bufctl */
     428           0 :                 bufctl = (rtl_cache_bufctl_type*)(slab->m_bp);
     429             :             }
     430           0 :             bufctl->m_next = 0;
     431             : 
     432             :             /* update 'slab->m_bp' to next free buffer */
     433           0 :             slab->m_bp += cache->m_type_size;
     434             : 
     435             :             /* assign bufctl to freelist */
     436           0 :             slab->m_sp = bufctl;
     437             :         }
     438             : 
     439             :         /* pop front */
     440           0 :         bufctl = slab->m_sp;
     441           0 :         slab->m_sp = bufctl->m_next;
     442             : 
     443             :         /* increment usage, check for full slab */
     444           0 :         if ((slab->m_ntypes += 1) == cache->m_ntypes)
     445             :         {
     446             :             /* remove from 'free' queue */
     447           0 :             QUEUE_REMOVE_NAMED(slab, slab_);
     448             : 
     449             :             /* insert onto 'used' queue (tail) */
     450           0 :             QUEUE_INSERT_TAIL_NAMED(&(cache->m_used_head), slab, slab_);
     451             :         }
     452             : 
     453             :         /* update stats */
     454           0 :         cache->m_slab_stats.m_alloc     += 1;
     455           0 :         cache->m_slab_stats.m_mem_alloc += cache->m_type_size;
     456             : 
     457           0 :         if (cache->m_features & RTL_CACHE_FEATURE_HASH)
     458           0 :             addr = (void*)rtl_cache_hash_insert (cache, bufctl);
     459             :         else
     460           0 :             addr = bufctl;
     461             :     }
     462             : 
     463           0 :     RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock));
     464           0 :     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           0 : 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           0 :     RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_slab_lock));
     481             : 
     482             :     /* determine slab from addr */
     483           0 :     if (cache->m_features & RTL_CACHE_FEATURE_HASH)
     484             :     {
     485           0 :         bufctl = rtl_cache_hash_remove (cache, (sal_uIntPtr)(addr));
     486           0 :         slab = (bufctl != 0) ? (rtl_cache_slab_type*)(bufctl->m_slab) : 0;
     487             :     }
     488             :     else
     489             :     {
     490             :         /* embedded slab struct */
     491           0 :         bufctl = (rtl_cache_bufctl_type*)(addr);
     492           0 :         slab = RTL_CACHE_SLAB(addr, cache->m_slab_size);
     493             :     }
     494             : 
     495           0 :     if (slab != 0)
     496             :     {
     497             :         /* check for full slab */
     498           0 :         if (slab->m_ntypes == cache->m_ntypes)
     499             :         {
     500             :             /* remove from 'used' queue */
     501           0 :             QUEUE_REMOVE_NAMED(slab, slab_);
     502             : 
     503             :             /* insert onto 'free' queue (head) */
     504           0 :             QUEUE_INSERT_HEAD_NAMED(&(cache->m_free_head), slab, slab_);
     505             :         }
     506             : 
     507             :         /* push front */
     508           0 :         bufctl->m_next = slab->m_sp;
     509           0 :         slab->m_sp = bufctl;
     510             : 
     511             :         /* update stats */
     512           0 :         cache->m_slab_stats.m_free      += 1;
     513           0 :         cache->m_slab_stats.m_mem_alloc -= cache->m_type_size;
     514             : 
     515             :         /* decrement usage, check for empty slab */
     516           0 :         if ((slab->m_ntypes -= 1) == 0)
     517             :         {
     518             :             /* remove from 'free' queue */
     519           0 :             QUEUE_REMOVE_NAMED(slab, slab_);
     520             : 
     521             :             /* update stats */
     522           0 :             cache->m_slab_stats.m_mem_total -= cache->m_slab_size;
     523             : 
     524             :             /* free 'empty' slab */
     525           0 :             RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock));
     526           0 :             rtl_cache_slab_destroy (cache, slab);
     527           0 :             return;
     528             :         }
     529             :     }
     530             : 
     531           0 :     RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock));
     532             : }
     533             : 
     534             : /* ================================================================= */
     535             : 
     536             : /** rtl_cache_magazine_constructor()
     537             :  */
     538             : int
     539           0 : rtl_cache_magazine_constructor (void * obj, SAL_UNUSED_PARAMETER void *)
     540             : {
     541           0 :     rtl_cache_magazine_type * mag = (rtl_cache_magazine_type*)(obj);
     542             :     /* @@@ sal_Size size = (sal_Size)(arg); @@@ */
     543             : 
     544           0 :     mag->m_mag_next = 0;
     545           0 :     mag->m_mag_size = RTL_CACHE_MAGAZINE_SIZE;
     546           0 :     mag->m_mag_used = 0;
     547             : 
     548           0 :     return (1);
     549             : }
     550             : 
     551             : /** rtl_cache_magazine_destructor()
     552             :  */
     553             : void
     554           0 : rtl_cache_magazine_destructor (void * obj, SAL_UNUSED_PARAMETER void *)
     555             : {
     556             :     rtl_cache_magazine_type * mag = static_cast< rtl_cache_magazine_type * >(
     557           0 :         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           0 : }
     562             : 
     563             : /** rtl_cache_magazine_clear()
     564             :  */
     565             : void
     566           0 : rtl_cache_magazine_clear (
     567             :     rtl_cache_type *          cache,
     568             :     rtl_cache_magazine_type * mag
     569             : )
     570             : {
     571           0 :     for (; mag->m_mag_used > 0; --mag->m_mag_used)
     572             :     {
     573           0 :         void * obj = mag->m_objects[mag->m_mag_used - 1];
     574           0 :         mag->m_objects[mag->m_mag_used - 1] = 0;
     575             : 
     576           0 :         if (cache->m_destructor != 0)
     577             :         {
     578             :             /* destruct object */
     579           0 :             (cache->m_destructor)(obj, cache->m_userarg);
     580             :         }
     581             : 
     582             :         /* return buffer to slab layer */
     583           0 :         rtl_cache_slab_free (cache, obj);
     584             :     }
     585           0 : }
     586             : 
     587             : /* ================================================================= */
     588             : 
     589             : /** rtl_cache_depot_enqueue()
     590             :  *
     591             :  *  @precond cache->m_depot_lock acquired.
     592             :  */
     593             : inline void
     594           0 : rtl_cache_depot_enqueue (
     595             :     rtl_cache_depot_type *    depot,
     596             :     rtl_cache_magazine_type * mag
     597             : )
     598             : {
     599             :     /* enqueue empty magazine */
     600           0 :     mag->m_mag_next = depot->m_mag_next;
     601           0 :     depot->m_mag_next = mag;
     602             : 
     603             :     /* update depot stats */
     604           0 :     depot->m_mag_count++;
     605           0 : }
     606             : 
     607             : /** rtl_cache_depot_dequeue()
     608             :  *
     609             :  *  @precond cache->m_depot_lock acquired.
     610             :  */
     611             : inline rtl_cache_magazine_type *
     612      680088 : rtl_cache_depot_dequeue (
     613             :     rtl_cache_depot_type * depot
     614             : )
     615             : {
     616      680088 :     rtl_cache_magazine_type * mag = 0;
     617      680088 :     if (depot->m_mag_count > 0)
     618             :     {
     619             :         /* dequeue magazine */
     620             :         assert(depot->m_mag_next != 0);
     621             : 
     622           0 :         mag = depot->m_mag_next;
     623           0 :         depot->m_mag_next = mag->m_mag_next;
     624           0 :         mag->m_mag_next = 0;
     625             : 
     626             :         /* update depot stats */
     627           0 :         depot->m_mag_count--;
     628           0 :         if(depot->m_curr_min > depot->m_mag_count)
     629             :         {
     630           0 :             depot->m_curr_min = depot->m_mag_count;
     631             :         }
     632             :     }
     633      680088 :     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           0 : 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           0 :     full = rtl_cache_depot_dequeue (&(cache->m_depot_full));
     652           0 :     if ((full != 0) && (empty != 0))
     653             :     {
     654             :         /* enqueue empty magazine */
     655           0 :         rtl_cache_depot_enqueue (&(cache->m_depot_empty), empty);
     656             :     }
     657             : 
     658             :     assert((full == 0) || (full->m_mag_used > 0));
     659             : 
     660           0 :     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           0 : 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           0 :     empty = rtl_cache_depot_dequeue (&(cache->m_depot_empty));
     679           0 :     if ((empty != 0) && (full != 0))
     680             :     {
     681             :         /* enqueue full magazine */
     682           0 :         rtl_cache_depot_enqueue (&(cache->m_depot_full), full);
     683             :     }
     684             : 
     685             :     assert((empty == 0) || (empty->m_mag_used == 0));
     686             : 
     687           0 :     return (empty);
     688             : }
     689             : 
     690             : /** rtl_cache_depot_populate()
     691             :  *
     692             :  *  @precond cache->m_depot_lock acquired.
     693             :  */
     694             : bool
     695           0 : rtl_cache_depot_populate (
     696             :     rtl_cache_type * cache
     697             : )
     698             : {
     699           0 :     rtl_cache_magazine_type * empty = 0;
     700             : 
     701           0 :     if (cache->m_magazine_cache != 0)
     702             :     {
     703             :         /* allocate new empty magazine */
     704           0 :         RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock));
     705           0 :         empty = (rtl_cache_magazine_type*)rtl_cache_alloc (cache->m_magazine_cache);
     706           0 :         RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_depot_lock));
     707           0 :         if (empty != 0)
     708             :         {
     709             :             /* enqueue (new) empty magazine */
     710           0 :             rtl_cache_depot_enqueue (&(cache->m_depot_empty), empty);
     711             :         }
     712             :     }
     713           0 :     return (empty != 0);
     714             : }
     715             : 
     716             : /* ================================================================= */
     717             : 
     718             : /** rtl_cache_constructor()
     719             :  */
     720             : int
     721      425055 : rtl_cache_constructor (void * obj)
     722             : {
     723      425055 :     rtl_cache_type * cache = (rtl_cache_type*)(obj);
     724             : 
     725      425055 :     memset (cache, 0, sizeof(rtl_cache_type));
     726             : 
     727             :     /* linkage */
     728      425055 :     QUEUE_START_NAMED(cache, cache_);
     729             : 
     730             :     /* slab layer */
     731      425055 :     (void)RTL_MEMORY_LOCK_INIT(&(cache->m_slab_lock));
     732             : 
     733      425055 :     QUEUE_START_NAMED(&(cache->m_free_head), slab_);
     734      425055 :     QUEUE_START_NAMED(&(cache->m_used_head), slab_);
     735             : 
     736      425055 :     cache->m_hash_table = cache->m_hash_table_0;
     737      425055 :     cache->m_hash_size  = RTL_CACHE_HASH_SIZE;
     738      425055 :     cache->m_hash_shift = highbit(cache->m_hash_size) - 1;
     739             : 
     740             :     /* depot layer */
     741      425055 :     (void)RTL_MEMORY_LOCK_INIT(&(cache->m_depot_lock));
     742             : 
     743      425055 :     return (1);
     744             : }
     745             : 
     746             : /** rtl_cache_destructor()
     747             :  */
     748             : void
     749      340044 : rtl_cache_destructor (void * obj)
     750             : {
     751      340044 :     rtl_cache_type * cache = (rtl_cache_type*)(obj);
     752             : 
     753             :     /* linkage */
     754             :     assert(QUEUE_STARTED_NAMED(cache, cache_));
     755             : 
     756             :     /* slab layer */
     757      340044 :     (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      340044 :     (void)RTL_MEMORY_LOCK_DESTROY(&(cache->m_depot_lock));
     768      340044 : }
     769             : 
     770             : /* ================================================================= */
     771             : 
     772             : /** rtl_cache_activate()
     773             :  */
     774             : rtl_cache_type *
     775      340044 : 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      340044 :     if (cache != 0)
     790             :     {
     791             :         sal_Size slabsize;
     792             : 
     793      340044 :         snprintf (cache->m_name, sizeof(cache->m_name), "%s", name);
     794             : 
     795             :         /* ensure minimum size (embedded bufctl linkage) */
     796      340044 :         if(objsize < sizeof(rtl_cache_bufctl_type*))
     797             :         {
     798           0 :             objsize = sizeof(rtl_cache_bufctl_type*);
     799             :         }
     800             : 
     801      340044 :         if (objalign == 0)
     802             :         {
     803             :             /* determine default alignment */
     804      340044 :             if (objsize >= RTL_MEMORY_ALIGNMENT_8)
     805      340044 :                 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      340044 :         cache->m_type_size  = objsize = RTL_MEMORY_P2ROUNDUP(objsize, objalign);
     820      340044 :         cache->m_type_align = objalign;
     821      340044 :         cache->m_type_shift = highbit(cache->m_type_size) - 1;
     822             : 
     823      340044 :         cache->m_constructor = constructor;
     824      340044 :         cache->m_destructor  = destructor;
     825      340044 :         cache->m_reclaim     = reclaim;
     826      340044 :         cache->m_userarg     = userarg;
     827             : 
     828             :         /* slab layer */
     829      340044 :         cache->m_source = source;
     830             : 
     831      340044 :         slabsize = source->m_quantum; /* minimum slab size */
     832      340044 :         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      340044 :             if(slabsize < cache->m_type_size * 8)
     844             :             {
     845       85011 :                 slabsize = cache->m_type_size * 8;
     846             :             }
     847             :         }
     848             : 
     849      340044 :         slabsize = RTL_MEMORY_P2ROUNDUP(slabsize, source->m_quantum);
     850      340044 :         if (!RTL_MEMORY_ISP2(slabsize))
     851           0 :             slabsize = (((sal_Size)1) << highbit(slabsize));
     852      340044 :         cache->m_slab_size = slabsize;
     853             : 
     854      340044 :         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       85011 :             cache->m_features  |= RTL_CACHE_FEATURE_HASH;
     860       85011 :             cache->m_ntypes     = cache->m_slab_size / cache->m_type_size;
     861       85011 :             cache->m_ncolor_max = cache->m_slab_size % cache->m_type_size;
     862             :         }
     863             :         else
     864             :         {
     865             :             /* embedded slab struct */
     866      255033 :             cache->m_ntypes     = (cache->m_slab_size - sizeof(rtl_cache_slab_type)) / cache->m_type_size;
     867      255033 :             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      340044 :         cache->m_ncolor = 0;
     872             : 
     873      340044 :         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      340044 :         if (!(flags & RTL_CACHE_FLAG_NOMAGAZINE))
     881             :         {
     882             :             assert(gp_cache_magazine_cache != 0);
     883      255033 :             cache->m_magazine_cache = gp_cache_magazine_cache;
     884             :         }
     885             : 
     886             :         /* insert into cache list */
     887      340044 :         RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock));
     888      340044 :         QUEUE_INSERT_TAIL_NAMED(&(g_cache_list.m_cache_head), cache, cache_);
     889      340044 :         RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock));
     890             :     }
     891      340044 :     return (cache);
     892             : }
     893             : 
     894             : /** rtl_cache_deactivate()
     895             :  */
     896             : void
     897      340044 : rtl_cache_deactivate (
     898             :     rtl_cache_type * cache
     899             : )
     900             : {
     901             :     /* remove from cache list */
     902      340044 :     RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock));
     903      340044 :     bool active = !QUEUE_STARTED_NAMED(cache, cache_);
     904      340044 :     QUEUE_REMOVE_NAMED(cache, cache_);
     905      340044 :     RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock));
     906             : 
     907             :     assert(active); // orphaned cache
     908             :     (void)active;
     909             : 
     910             :     /* cleanup magazine layer */
     911      340044 :     if (cache->m_magazine_cache != 0)
     912             :     {
     913             :         rtl_cache_type *          mag_cache;
     914             :         rtl_cache_magazine_type * mag;
     915             : 
     916             :         /* prevent recursion */
     917      340044 :         mag_cache = cache->m_magazine_cache, cache->m_magazine_cache = 0;
     918             : 
     919             :         /* cleanup cpu layer */
     920      340044 :         if ((mag = cache->m_cpu_curr) != 0)
     921             :         {
     922           0 :             cache->m_cpu_curr = 0;
     923           0 :             rtl_cache_magazine_clear (cache, mag);
     924           0 :             rtl_cache_free (mag_cache, mag);
     925             :         }
     926      340044 :         if ((mag = cache->m_cpu_prev) != 0)
     927             :         {
     928           0 :             cache->m_cpu_prev = 0;
     929           0 :             rtl_cache_magazine_clear (cache, mag);
     930           0 :             rtl_cache_free (mag_cache, mag);
     931             :         }
     932             : 
     933             :         /* cleanup depot layer */
     934      680088 :         while ((mag = rtl_cache_depot_dequeue(&(cache->m_depot_full))) != 0)
     935             :         {
     936           0 :             rtl_cache_magazine_clear (cache, mag);
     937           0 :             rtl_cache_free (mag_cache, mag);
     938             :         }
     939      680088 :         while ((mag = rtl_cache_depot_dequeue(&(cache->m_depot_empty))) != 0)
     940             :         {
     941           0 :             rtl_cache_magazine_clear (cache, mag);
     942           0 :             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      340044 :     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           0 :         if (cache->m_features & RTL_CACHE_FEATURE_HASH)
     970             :         {
     971             :             /* cleanup bufctl(s) for leaking buffer(s) */
     972           0 :             sal_Size i, n = cache->m_hash_size;
     973           0 :             for (i = 0; i < n; i++)
     974             :             {
     975             :                 rtl_cache_bufctl_type * bufctl;
     976           0 :                 while ((bufctl = cache->m_hash_table[i]) != 0)
     977             :                 {
     978             :                     /* pop from hash table */
     979           0 :                     cache->m_hash_table[i] = bufctl->m_next, bufctl->m_next = 0;
     980             : 
     981             :                     /* return to bufctl cache */
     982           0 :                     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           0 :             head = &(cache->m_used_head);
     991           0 :             for (slab = head->m_slab_next; slab != head; slab = head->m_slab_next)
     992             :             {
     993             :                 /* remove from 'used' queue */
     994           0 :                 QUEUE_REMOVE_NAMED(slab, slab_);
     995             : 
     996             :                 /* update stats */
     997           0 :                 cache->m_slab_stats.m_mem_total -= cache->m_slab_size;
     998             : 
     999             :                 /* free slab */
    1000           0 :                 rtl_cache_slab_destroy (cache, slab);
    1001             :             }
    1002             : 
    1003           0 :             head = &(cache->m_free_head);
    1004           0 :             for (slab = head->m_slab_next; slab != head; slab = head->m_slab_next)
    1005             :             {
    1006             :                 /* remove from 'free' queue */
    1007           0 :                 QUEUE_REMOVE_NAMED(slab, slab_);
    1008             : 
    1009             :                 /* update stats */
    1010           0 :                 cache->m_slab_stats.m_mem_total -= cache->m_slab_size;
    1011             : 
    1012             :                 /* free slab */
    1013           0 :                 rtl_cache_slab_destroy (cache, slab);
    1014             :             }
    1015             :         }
    1016             :     }
    1017             : 
    1018      340044 :     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           0 :             cache->m_hash_size * sizeof(rtl_cache_bufctl_type*));
    1024             : 
    1025           0 :         cache->m_hash_table = cache->m_hash_table_0;
    1026           0 :         cache->m_hash_size  = RTL_CACHE_HASH_SIZE;
    1027           0 :         cache->m_hash_shift = highbit(cache->m_hash_size) - 1;
    1028             :     }
    1029      340044 : }
    1030             : 
    1031             : } //namespace
    1032             : 
    1033             : /* ================================================================= *
    1034             :  *
    1035             :  * cache implementation.
    1036             :  *
    1037             :  * ================================================================= */
    1038             : 
    1039             : /** rtl_cache_create()
    1040             :  */
    1041             : rtl_cache_type *
    1042       85011 : 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       85011 :     rtl_cache_type * result = 0;
    1055       85011 :     sal_Size         size   = sizeof(rtl_cache_type);
    1056             : 
    1057             : try_alloc:
    1058      170022 :     result = (rtl_cache_type*)rtl_arena_alloc (gp_cache_arena, &size);
    1059      170022 :     if (result != 0)
    1060             :     {
    1061       85011 :         rtl_cache_type * cache = result;
    1062       85011 :         (void) rtl_cache_constructor (cache);
    1063             : 
    1064       85011 :         if (!source)
    1065             :         {
    1066             :             /* use default arena */
    1067             :             assert(gp_default_arena != 0);
    1068       85011 :             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       85011 :         );
    1083             : 
    1084       85011 :         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       85011 :     else if (gp_cache_arena == 0)
    1093             :     {
    1094       85011 :         ensureCacheSingleton();
    1095       85011 :         if (gp_cache_arena)
    1096             :         {
    1097             :             /* try again */
    1098       85011 :             goto try_alloc;
    1099             :         }
    1100             :     }
    1101       85011 :     return (result);
    1102             : }
    1103             : 
    1104             : /** rtl_cache_destroy()
    1105             :  */
    1106       85011 : void SAL_CALL rtl_cache_destroy (
    1107             :     rtl_cache_type * cache
    1108             : ) SAL_THROW_EXTERN_C()
    1109             : {
    1110       85011 :     if (cache != 0)
    1111             :     {
    1112       85011 :         rtl_cache_deactivate (cache);
    1113       85011 :         rtl_cache_destructor (cache);
    1114       85011 :         rtl_arena_free (gp_cache_arena, cache, sizeof(rtl_cache_type));
    1115             :     }
    1116       85011 : }
    1117             : 
    1118             : /** rtl_cache_alloc()
    1119             :  */
    1120             : void *
    1121      297568 : SAL_CALL rtl_cache_alloc (
    1122             :     rtl_cache_type * cache
    1123             : ) SAL_THROW_EXTERN_C()
    1124             : {
    1125      297568 :     void * obj = 0;
    1126             : 
    1127      297568 :     if (cache == 0)
    1128           0 :         return (0);
    1129             : 
    1130      297568 :     if (alloc_mode == AMode_SYSTEM)
    1131             :     {
    1132      297568 :         obj = rtl_allocateMemory(cache->m_type_size);
    1133      297568 :         if ((obj != 0) && (cache->m_constructor != 0))
    1134             :         {
    1135           0 :             if (!((cache->m_constructor)(obj, cache->m_userarg)))
    1136             :             {
    1137             :                 /* construction failure */
    1138           0 :                 rtl_freeMemory(obj), obj = 0;
    1139             :             }
    1140             :         }
    1141      297568 :         return obj;
    1142             :     }
    1143             : 
    1144           0 :     RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_depot_lock));
    1145           0 :     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           0 :             curr = cache->m_cpu_curr;
    1153           0 :             if ((curr != 0) && (curr->m_mag_used > 0))
    1154             :             {
    1155           0 :                 obj = curr->m_objects[--curr->m_mag_used];
    1156           0 :                 cache->m_cpu_stats.m_alloc += 1;
    1157           0 :                 RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock));
    1158             : 
    1159           0 :                 return (obj);
    1160             :             }
    1161             : 
    1162           0 :             prev = cache->m_cpu_prev;
    1163           0 :             if ((prev != 0) && (prev->m_mag_used > 0))
    1164             :             {
    1165           0 :                 temp = cache->m_cpu_curr;
    1166           0 :                 cache->m_cpu_curr = cache->m_cpu_prev;
    1167           0 :                 cache->m_cpu_prev = temp;
    1168             : 
    1169           0 :                 continue;
    1170             :             }
    1171             : 
    1172           0 :             temp = rtl_cache_depot_exchange_alloc (cache, prev);
    1173           0 :             if (temp != 0)
    1174             :             {
    1175           0 :                 cache->m_cpu_prev = cache->m_cpu_curr;
    1176           0 :                 cache->m_cpu_curr = temp;
    1177             : 
    1178           0 :                 continue;
    1179             :             }
    1180             : 
    1181             :             /* no full magazine: fall through to slab layer */
    1182           0 :             break;
    1183           0 :         }
    1184             :     }
    1185           0 :     RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock));
    1186             : 
    1187             :     /* alloc buffer from slab layer */
    1188           0 :     obj = rtl_cache_slab_alloc (cache);
    1189           0 :     if ((obj != 0) && (cache->m_constructor != 0))
    1190             :     {
    1191             :         /* construct object */
    1192           0 :         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           0 :     return (obj);
    1199             : }
    1200             : 
    1201             : /** rtl_cache_free()
    1202             :  */
    1203             : void
    1204      297568 : SAL_CALL rtl_cache_free (
    1205             :     rtl_cache_type * cache,
    1206             :     void *           obj
    1207             : ) SAL_THROW_EXTERN_C()
    1208             : {
    1209      297568 :     if ((obj != 0) && (cache != 0))
    1210             :     {
    1211      297568 :         if (alloc_mode == AMode_SYSTEM)
    1212             :         {
    1213      297568 :             if (cache->m_destructor != 0)
    1214             :             {
    1215             :                 /* destruct object */
    1216           0 :                 (cache->m_destructor)(obj, cache->m_userarg);
    1217             :             }
    1218      297568 :             rtl_freeMemory(obj);
    1219      297568 :             return;
    1220             :         }
    1221             : 
    1222           0 :         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           0 :             curr = cache->m_cpu_curr;
    1230           0 :             if ((curr != 0) && (curr->m_mag_used < curr->m_mag_size))
    1231             :             {
    1232           0 :                 curr->m_objects[curr->m_mag_used++] = obj;
    1233           0 :                 cache->m_cpu_stats.m_free += 1;
    1234           0 :                 RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock));
    1235             : 
    1236           0 :                 return;
    1237             :             }
    1238             : 
    1239           0 :             prev = cache->m_cpu_prev;
    1240           0 :             if ((prev != 0) && (prev->m_mag_used == 0))
    1241             :             {
    1242           0 :                 temp = cache->m_cpu_curr;
    1243           0 :                 cache->m_cpu_curr = cache->m_cpu_prev;
    1244           0 :                 cache->m_cpu_prev = temp;
    1245             : 
    1246           0 :                 continue;
    1247             :             }
    1248             : 
    1249           0 :             temp = rtl_cache_depot_exchange_free (cache, prev);
    1250           0 :             if (temp != 0)
    1251             :             {
    1252           0 :                 cache->m_cpu_prev = cache->m_cpu_curr;
    1253           0 :                 cache->m_cpu_curr = temp;
    1254             : 
    1255           0 :                 continue;
    1256             :             }
    1257             : 
    1258           0 :             if (rtl_cache_depot_populate(cache))
    1259             :             {
    1260           0 :                 continue;
    1261             :             }
    1262             : 
    1263             :             /* no empty magazine: fall through to slab layer */
    1264           0 :             break;
    1265           0 :         }
    1266             : 
    1267           0 :         RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock));
    1268             : 
    1269             :         /* no space for constructed object in magazine layer */
    1270           0 :         if (cache->m_destructor != 0)
    1271             :         {
    1272             :             /* destruct object */
    1273           0 :             (cache->m_destructor)(obj, cache->m_userarg);
    1274             :         }
    1275             : 
    1276             :         /* return buffer to slab layer */
    1277           0 :         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       85011 : rtl_cache_wsupdate_init()
    1320             : {
    1321       85011 :     RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock));
    1322       85011 :     g_cache_list.m_update_done = 0;
    1323       85011 :     (void) pthread_cond_init (&(g_cache_list.m_update_cond), NULL);
    1324       85011 :     if (pthread_create (
    1325       85011 :             &(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       85011 :     RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock));
    1331       85011 : }
    1332             : 
    1333             : static void
    1334       84527 : rtl_cache_wsupdate_wait (unsigned int seconds)
    1335             : {
    1336       84527 :     if (seconds > 0)
    1337             :     {
    1338             :         timeval  now;
    1339             :         timespec wakeup;
    1340             : 
    1341       84527 :         gettimeofday(&now, 0);
    1342       84527 :         wakeup.tv_sec  = now.tv_sec + (seconds);
    1343       84527 :         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       84527 :             &wakeup);
    1349             :     }
    1350       84527 : }
    1351             : 
    1352             : static void
    1353       85011 : rtl_cache_wsupdate_fini()
    1354             : {
    1355       85011 :     RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock));
    1356       85011 :     g_cache_list.m_update_done = 1;
    1357       85011 :     pthread_cond_signal (&(g_cache_list.m_update_cond));
    1358       85011 :     RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock));
    1359             : 
    1360       85011 :     if (g_cache_list.m_update_thread != (pthread_t)(0))
    1361       85011 :         pthread_join (g_cache_list.m_update_thread, NULL);
    1362       85011 : }
    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           8 : rtl_cache_depot_wsupdate (
    1418             :     rtl_cache_type *       cache,
    1419             :     rtl_cache_depot_type * depot
    1420             : )
    1421             : {
    1422             :     sal_Size npurge;
    1423             : 
    1424           8 :     depot->m_prev_min = depot->m_curr_min;
    1425           8 :     depot->m_curr_min = depot->m_mag_count;
    1426             : 
    1427           8 :     npurge = depot->m_curr_min < depot->m_prev_min ? depot->m_curr_min : depot->m_prev_min;
    1428           8 :     for (; npurge > 0; npurge--)
    1429             :     {
    1430           0 :         rtl_cache_magazine_type * mag = rtl_cache_depot_dequeue (depot);
    1431           0 :         if (mag != 0)
    1432             :         {
    1433           0 :             RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock));
    1434           0 :             rtl_cache_magazine_clear (cache, mag);
    1435           0 :             rtl_cache_free (cache->m_magazine_cache, mag);
    1436           0 :             RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_depot_lock));
    1437             :         }
    1438             :     }
    1439           8 : }
    1440             : 
    1441             : /** rtl_cache_wsupdate()
    1442             :  *
    1443             :  *  @precond cache->m_depot_lock released
    1444             :  */
    1445             : static void
    1446           4 : rtl_cache_wsupdate (
    1447             :     rtl_cache_type * cache
    1448             : )
    1449             : {
    1450           4 :     if (cache->m_magazine_cache != 0)
    1451             :     {
    1452           4 :         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           4 :         rtl_cache_depot_wsupdate (cache, &(cache->m_depot_full));
    1466           4 :         rtl_cache_depot_wsupdate (cache, &(cache->m_depot_empty));
    1467             : 
    1468           4 :         RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock));
    1469             :     }
    1470           4 : }
    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       85011 : rtl_cache_wsupdate_all (void * arg)
    1481             : {
    1482       85011 :     osl::Thread::setName("rtl_cache_wsupdate_all");
    1483             :     unsigned int seconds = sal::static_int_cast< unsigned int >(
    1484       85011 :         reinterpret_cast< sal_uIntPtr >(arg));
    1485             : 
    1486       85011 :     RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock));
    1487      254549 :     while (!g_cache_list.m_update_done)
    1488             :     {
    1489       84527 :         rtl_cache_wsupdate_wait (seconds);
    1490       84527 :         if (!g_cache_list.m_update_done)
    1491             :         {
    1492             :             rtl_cache_type * head, * cache;
    1493             : 
    1494           1 :             head = &(g_cache_list.m_cache_head);
    1495           5 :             for (cache  = head->m_cache_next;
    1496             :                  cache != head;
    1497             :                  cache  = cache->m_cache_next)
    1498             :             {
    1499           4 :                 rtl_cache_wsupdate (cache);
    1500             :             }
    1501             :         }
    1502             :     }
    1503       85011 :     RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock));
    1504             : 
    1505       85011 :     return (0);
    1506             : }
    1507             : 
    1508             : /* ================================================================= *
    1509             :  *
    1510             :  * cache initialization.
    1511             :  *
    1512             :  * ================================================================= */
    1513             : 
    1514             : void
    1515       85011 : rtl_cache_init()
    1516             : {
    1517             :     {
    1518             :         /* list of caches */
    1519       85011 :         RTL_MEMORY_LOCK_INIT(&(g_cache_list.m_lock));
    1520       85011 :         (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       85011 :         );
    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       85011 :         (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       85011 :         );
    1559             :         assert(gp_cache_magazine_cache != 0);
    1560             : 
    1561             :         /* activate magazine layer */
    1562       85011 :         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       85011 :         (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       85011 :         );
    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       85011 :         (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       85011 :         );
    1604             :         assert(gp_cache_bufctl_cache != 0);
    1605             :     }
    1606             : 
    1607       85011 :     rtl_cache_wsupdate_init();
    1608             :     // SAL_INFO("sal.rtl", "rtl_cache_init completed");
    1609       85011 : }
    1610             : 
    1611             : /* ================================================================= */
    1612             : 
    1613             : void
    1614       85011 : rtl_cache_fini()
    1615             : {
    1616       85011 :     if (gp_cache_arena != 0)
    1617             :     {
    1618             :         rtl_cache_type * cache, * head;
    1619             : 
    1620       85011 :         rtl_cache_wsupdate_fini();
    1621             : 
    1622       85011 :         if (gp_cache_bufctl_cache != 0)
    1623             :         {
    1624       85011 :             cache = gp_cache_bufctl_cache, gp_cache_bufctl_cache = 0;
    1625       85011 :             rtl_cache_deactivate (cache);
    1626       85011 :             rtl_cache_destructor (cache);
    1627             :         }
    1628       85011 :         if (gp_cache_slab_cache != 0)
    1629             :         {
    1630       85011 :             cache = gp_cache_slab_cache, gp_cache_slab_cache = 0;
    1631       85011 :             rtl_cache_deactivate (cache);
    1632       85011 :             rtl_cache_destructor (cache);
    1633             :         }
    1634       85011 :         if (gp_cache_magazine_cache != 0)
    1635             :         {
    1636       85011 :             cache = gp_cache_magazine_cache, gp_cache_magazine_cache = 0;
    1637       85011 :             rtl_cache_deactivate (cache);
    1638       85011 :             rtl_cache_destructor (cache);
    1639             :         }
    1640       85011 :         if (gp_cache_arena != 0)
    1641             :         {
    1642       85011 :             rtl_arena_destroy (gp_cache_arena);
    1643       85011 :             gp_cache_arena = 0;
    1644             :         }
    1645             : 
    1646       85011 :         RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock));
    1647       85011 :         head = &(g_cache_list.m_cache_head);
    1648       85011 :         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       85011 :         RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock));
    1666             :     }
    1667             :     // SAL_INFO("sal.rtl", "rtl_cache_fini completed");
    1668       85011 : }
    1669             : 
    1670             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10