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