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