xref: /AOO41X/main/sal/rtl/source/alloc_arena.c (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1*cdf0e10cSrcweir /*************************************************************************
2*cdf0e10cSrcweir  *
3*cdf0e10cSrcweir  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4*cdf0e10cSrcweir  *
5*cdf0e10cSrcweir  * Copyright 2000, 2010 Oracle and/or its affiliates.
6*cdf0e10cSrcweir  *
7*cdf0e10cSrcweir  * OpenOffice.org - a multi-platform office productivity suite
8*cdf0e10cSrcweir  *
9*cdf0e10cSrcweir  * This file is part of OpenOffice.org.
10*cdf0e10cSrcweir  *
11*cdf0e10cSrcweir  * OpenOffice.org is free software: you can redistribute it and/or modify
12*cdf0e10cSrcweir  * it under the terms of the GNU Lesser General Public License version 3
13*cdf0e10cSrcweir  * only, as published by the Free Software Foundation.
14*cdf0e10cSrcweir  *
15*cdf0e10cSrcweir  * OpenOffice.org is distributed in the hope that it will be useful,
16*cdf0e10cSrcweir  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17*cdf0e10cSrcweir  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18*cdf0e10cSrcweir  * GNU Lesser General Public License version 3 for more details
19*cdf0e10cSrcweir  * (a copy is included in the LICENSE file that accompanied this code).
20*cdf0e10cSrcweir  *
21*cdf0e10cSrcweir  * You should have received a copy of the GNU Lesser General Public License
22*cdf0e10cSrcweir  * version 3 along with OpenOffice.org.  If not, see
23*cdf0e10cSrcweir  * <http://www.openoffice.org/license.html>
24*cdf0e10cSrcweir  * for a copy of the LGPLv3 License.
25*cdf0e10cSrcweir  *
26*cdf0e10cSrcweir  ************************************************************************/
27*cdf0e10cSrcweir 
28*cdf0e10cSrcweir #define _BSD_SOURCE /* sys/mman.h: MAP_ANON */
29*cdf0e10cSrcweir #include "alloc_arena.h"
30*cdf0e10cSrcweir 
31*cdf0e10cSrcweir #include "alloc_impl.h"
32*cdf0e10cSrcweir #include "internal/once.h"
33*cdf0e10cSrcweir #include "sal/macros.h"
34*cdf0e10cSrcweir #include "osl/diagnose.h"
35*cdf0e10cSrcweir 
36*cdf0e10cSrcweir #include <string.h>
37*cdf0e10cSrcweir #include <stdio.h>
38*cdf0e10cSrcweir 
39*cdf0e10cSrcweir #ifdef OS2
40*cdf0e10cSrcweir #undef OSL_TRACE
41*cdf0e10cSrcweir #define OSL_TRACE                  1 ? ((void)0) : _OSL_GLOBAL osl_trace
42*cdf0e10cSrcweir #define INCL_DOS
43*cdf0e10cSrcweir #include <os2.h>
44*cdf0e10cSrcweir #endif
45*cdf0e10cSrcweir 
46*cdf0e10cSrcweir /* ================================================================= *
47*cdf0e10cSrcweir  *
48*cdf0e10cSrcweir  * arena internals.
49*cdf0e10cSrcweir  *
50*cdf0e10cSrcweir  * ================================================================= */
51*cdf0e10cSrcweir 
52*cdf0e10cSrcweir /** g_arena_list
53*cdf0e10cSrcweir  *  @internal
54*cdf0e10cSrcweir  */
55*cdf0e10cSrcweir struct rtl_arena_list_st
56*cdf0e10cSrcweir {
57*cdf0e10cSrcweir 	rtl_memory_lock_type m_lock;
58*cdf0e10cSrcweir 	rtl_arena_type       m_arena_head;
59*cdf0e10cSrcweir };
60*cdf0e10cSrcweir 
61*cdf0e10cSrcweir static struct rtl_arena_list_st g_arena_list;
62*cdf0e10cSrcweir 
63*cdf0e10cSrcweir 
64*cdf0e10cSrcweir /** gp_arena_arena
65*cdf0e10cSrcweir  *  provided for arena_type allocations, and hash_table resizing.
66*cdf0e10cSrcweir  *
67*cdf0e10cSrcweir  *  @internal
68*cdf0e10cSrcweir  */
69*cdf0e10cSrcweir static rtl_arena_type * gp_arena_arena = 0;
70*cdf0e10cSrcweir 
71*cdf0e10cSrcweir 
72*cdf0e10cSrcweir /** gp_machdep_arena
73*cdf0e10cSrcweir  *
74*cdf0e10cSrcweir  *  Low level virtual memory (pseudo) arena
75*cdf0e10cSrcweir  *  (platform dependent implementation)
76*cdf0e10cSrcweir  *
77*cdf0e10cSrcweir  *  @internal
78*cdf0e10cSrcweir  */
79*cdf0e10cSrcweir static rtl_arena_type * gp_machdep_arena = 0;
80*cdf0e10cSrcweir 
81*cdf0e10cSrcweir 
82*cdf0e10cSrcweir static void *
83*cdf0e10cSrcweir SAL_CALL rtl_machdep_alloc (
84*cdf0e10cSrcweir 	rtl_arena_type * pArena,
85*cdf0e10cSrcweir 	sal_Size *       pSize
86*cdf0e10cSrcweir );
87*cdf0e10cSrcweir 
88*cdf0e10cSrcweir static void
89*cdf0e10cSrcweir SAL_CALL rtl_machdep_free (
90*cdf0e10cSrcweir 	rtl_arena_type * pArena,
91*cdf0e10cSrcweir 	void *           pAddr,
92*cdf0e10cSrcweir 	sal_Size         nSize
93*cdf0e10cSrcweir );
94*cdf0e10cSrcweir 
95*cdf0e10cSrcweir static sal_Size
96*cdf0e10cSrcweir rtl_machdep_pagesize (void);
97*cdf0e10cSrcweir 
98*cdf0e10cSrcweir 
99*cdf0e10cSrcweir /** gp_default_arena
100*cdf0e10cSrcweir  */
101*cdf0e10cSrcweir rtl_arena_type * gp_default_arena = 0;
102*cdf0e10cSrcweir 
103*cdf0e10cSrcweir 
104*cdf0e10cSrcweir /** rtl_arena_init()
105*cdf0e10cSrcweir  *  @internal
106*cdf0e10cSrcweir  */
107*cdf0e10cSrcweir static int
108*cdf0e10cSrcweir rtl_arena_init (void);
109*cdf0e10cSrcweir 
110*cdf0e10cSrcweir 
111*cdf0e10cSrcweir /* ================================================================= */
112*cdf0e10cSrcweir 
113*cdf0e10cSrcweir /** rtl_arena_segment_constructor()
114*cdf0e10cSrcweir  */
115*cdf0e10cSrcweir static int
116*cdf0e10cSrcweir rtl_arena_segment_constructor (void * obj)
117*cdf0e10cSrcweir {
118*cdf0e10cSrcweir 	rtl_arena_segment_type * segment = (rtl_arena_segment_type*)(obj);
119*cdf0e10cSrcweir 
120*cdf0e10cSrcweir 	QUEUE_START_NAMED(segment, s);
121*cdf0e10cSrcweir 	QUEUE_START_NAMED(segment, f);
122*cdf0e10cSrcweir 
123*cdf0e10cSrcweir 	return (1);
124*cdf0e10cSrcweir }
125*cdf0e10cSrcweir 
126*cdf0e10cSrcweir 
127*cdf0e10cSrcweir /** rtl_arena_segment_destructor()
128*cdf0e10cSrcweir  */
129*cdf0e10cSrcweir static void
130*cdf0e10cSrcweir rtl_arena_segment_destructor (void * obj)
131*cdf0e10cSrcweir {
132*cdf0e10cSrcweir #if OSL_DEBUG_LEVEL == 0
133*cdf0e10cSrcweir     (void) obj; /* unused */
134*cdf0e10cSrcweir #else /* OSL_DEBUG_LEVEL */
135*cdf0e10cSrcweir 	rtl_arena_segment_type * segment = (rtl_arena_segment_type*)(obj);
136*cdf0e10cSrcweir 
137*cdf0e10cSrcweir 	OSL_ASSERT(QUEUE_STARTED_NAMED(segment, s));
138*cdf0e10cSrcweir 	OSL_ASSERT(QUEUE_STARTED_NAMED(segment, f));
139*cdf0e10cSrcweir #endif /* OSL_DEBUG_LEVEL */
140*cdf0e10cSrcweir }
141*cdf0e10cSrcweir 
142*cdf0e10cSrcweir /* ================================================================= */
143*cdf0e10cSrcweir 
144*cdf0e10cSrcweir /** rtl_arena_segment_populate()
145*cdf0e10cSrcweir  *
146*cdf0e10cSrcweir  *  @precond  arena->m_lock acquired.
147*cdf0e10cSrcweir  */
148*cdf0e10cSrcweir static int
149*cdf0e10cSrcweir rtl_arena_segment_populate (
150*cdf0e10cSrcweir 	rtl_arena_type * arena
151*cdf0e10cSrcweir )
152*cdf0e10cSrcweir {
153*cdf0e10cSrcweir     rtl_arena_segment_type *span;
154*cdf0e10cSrcweir 	sal_Size                size = rtl_machdep_pagesize();
155*cdf0e10cSrcweir 
156*cdf0e10cSrcweir     span = rtl_machdep_alloc(gp_machdep_arena, &size);
157*cdf0e10cSrcweir 	if (span != 0)
158*cdf0e10cSrcweir 	{
159*cdf0e10cSrcweir         rtl_arena_segment_type *first, *last, *head;
160*cdf0e10cSrcweir 		sal_Size                count = size / sizeof(rtl_arena_segment_type);
161*cdf0e10cSrcweir 
162*cdf0e10cSrcweir 		/* insert onto reserve span list */
163*cdf0e10cSrcweir 		QUEUE_INSERT_TAIL_NAMED(&(arena->m_segment_reserve_span_head), span, s);
164*cdf0e10cSrcweir 		QUEUE_START_NAMED(span, f);
165*cdf0e10cSrcweir 		span->m_addr = (sal_uIntPtr)(span);
166*cdf0e10cSrcweir 		span->m_size = size;
167*cdf0e10cSrcweir 		span->m_type = RTL_ARENA_SEGMENT_TYPE_SPAN;
168*cdf0e10cSrcweir 
169*cdf0e10cSrcweir 		/* insert onto reserve list */
170*cdf0e10cSrcweir 		head  = &(arena->m_segment_reserve_head);
171*cdf0e10cSrcweir 		for (first = span + 1, last = span + count; first < last; ++first)
172*cdf0e10cSrcweir 		{
173*cdf0e10cSrcweir 		    QUEUE_INSERT_TAIL_NAMED(head, first, s);
174*cdf0e10cSrcweir 			QUEUE_START_NAMED(first, f);
175*cdf0e10cSrcweir 			first->m_addr = 0;
176*cdf0e10cSrcweir 			first->m_size = 0;
177*cdf0e10cSrcweir 			first->m_type = 0;
178*cdf0e10cSrcweir 		}
179*cdf0e10cSrcweir 	}
180*cdf0e10cSrcweir 	return (span != 0);
181*cdf0e10cSrcweir }
182*cdf0e10cSrcweir 
183*cdf0e10cSrcweir 
184*cdf0e10cSrcweir /** rtl_arena_segment_get()
185*cdf0e10cSrcweir  *
186*cdf0e10cSrcweir  *  @precond  arena->m_lock acquired.
187*cdf0e10cSrcweir  *  @precond  (*ppSegment == 0)
188*cdf0e10cSrcweir  */
189*cdf0e10cSrcweir static RTL_MEMORY_INLINE void
190*cdf0e10cSrcweir rtl_arena_segment_get (
191*cdf0e10cSrcweir 	rtl_arena_type *          arena,
192*cdf0e10cSrcweir 	rtl_arena_segment_type ** ppSegment
193*cdf0e10cSrcweir )
194*cdf0e10cSrcweir {
195*cdf0e10cSrcweir     rtl_arena_segment_type * head;
196*cdf0e10cSrcweir 
197*cdf0e10cSrcweir     OSL_ASSERT(*ppSegment == 0);
198*cdf0e10cSrcweir 
199*cdf0e10cSrcweir     head = &(arena->m_segment_reserve_head);
200*cdf0e10cSrcweir     if ((head->m_snext != head) || rtl_arena_segment_populate (arena))
201*cdf0e10cSrcweir     {
202*cdf0e10cSrcweir 		(*ppSegment) = head->m_snext;
203*cdf0e10cSrcweir 		QUEUE_REMOVE_NAMED((*ppSegment), s);
204*cdf0e10cSrcweir     }
205*cdf0e10cSrcweir }
206*cdf0e10cSrcweir 
207*cdf0e10cSrcweir #if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
208*cdf0e10cSrcweir #pragma inline(rtl_arena_segment_get)
209*cdf0e10cSrcweir #endif
210*cdf0e10cSrcweir 
211*cdf0e10cSrcweir 
212*cdf0e10cSrcweir /** rtl_arena_segment_put()
213*cdf0e10cSrcweir  *
214*cdf0e10cSrcweir  *  @precond  arena->m_lock acquired.
215*cdf0e10cSrcweir  *  @postcond (*ppSegment == 0)
216*cdf0e10cSrcweir  */
217*cdf0e10cSrcweir static RTL_MEMORY_INLINE void
218*cdf0e10cSrcweir rtl_arena_segment_put (
219*cdf0e10cSrcweir 	rtl_arena_type *          arena,
220*cdf0e10cSrcweir 	rtl_arena_segment_type ** ppSegment
221*cdf0e10cSrcweir )
222*cdf0e10cSrcweir {
223*cdf0e10cSrcweir 	rtl_arena_segment_type * head;
224*cdf0e10cSrcweir 
225*cdf0e10cSrcweir 	OSL_ASSERT(QUEUE_STARTED_NAMED((*ppSegment), s));
226*cdf0e10cSrcweir 	OSL_ASSERT(QUEUE_STARTED_NAMED((*ppSegment), f));
227*cdf0e10cSrcweir 
228*cdf0e10cSrcweir 	(*ppSegment)->m_addr = 0;
229*cdf0e10cSrcweir 	(*ppSegment)->m_size = 0;
230*cdf0e10cSrcweir 
231*cdf0e10cSrcweir 	OSL_ASSERT((*ppSegment)->m_type != RTL_ARENA_SEGMENT_TYPE_HEAD);
232*cdf0e10cSrcweir 	(*ppSegment)->m_type = 0;
233*cdf0e10cSrcweir 
234*cdf0e10cSrcweir 	/* keep as reserve */
235*cdf0e10cSrcweir 	head = &(arena->m_segment_reserve_head);
236*cdf0e10cSrcweir 	QUEUE_INSERT_HEAD_NAMED(head, (*ppSegment), s);
237*cdf0e10cSrcweir 
238*cdf0e10cSrcweir 	/* clear */
239*cdf0e10cSrcweir 	(*ppSegment) = 0;
240*cdf0e10cSrcweir }
241*cdf0e10cSrcweir 
242*cdf0e10cSrcweir #if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
243*cdf0e10cSrcweir #pragma inline(rtl_arena_segment_put)
244*cdf0e10cSrcweir #endif
245*cdf0e10cSrcweir 
246*cdf0e10cSrcweir /* ================================================================= */
247*cdf0e10cSrcweir 
248*cdf0e10cSrcweir /** rtl_arena_freelist_insert()
249*cdf0e10cSrcweir  *
250*cdf0e10cSrcweir  *  @precond arena->m_lock acquired.
251*cdf0e10cSrcweir  */
252*cdf0e10cSrcweir static RTL_MEMORY_INLINE void
253*cdf0e10cSrcweir rtl_arena_freelist_insert (
254*cdf0e10cSrcweir 	rtl_arena_type *         arena,
255*cdf0e10cSrcweir 	rtl_arena_segment_type * segment
256*cdf0e10cSrcweir )
257*cdf0e10cSrcweir {
258*cdf0e10cSrcweir 	rtl_arena_segment_type * head;
259*cdf0e10cSrcweir 
260*cdf0e10cSrcweir 	head = &(arena->m_freelist_head[highbit(segment->m_size) - 1]);
261*cdf0e10cSrcweir 	QUEUE_INSERT_TAIL_NAMED(head, segment, f);
262*cdf0e10cSrcweir 
263*cdf0e10cSrcweir 	arena->m_freelist_bitmap |= head->m_size;
264*cdf0e10cSrcweir }
265*cdf0e10cSrcweir 
266*cdf0e10cSrcweir #if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
267*cdf0e10cSrcweir #pragma inline(rtl_arena_freelist_insert)
268*cdf0e10cSrcweir #endif /* __SUNPRO_C */
269*cdf0e10cSrcweir 
270*cdf0e10cSrcweir 
271*cdf0e10cSrcweir /** rtl_arena_freelist_remove()
272*cdf0e10cSrcweir  *
273*cdf0e10cSrcweir  *  @precond arena->m_lock acquired.
274*cdf0e10cSrcweir  */
275*cdf0e10cSrcweir static RTL_MEMORY_INLINE void
276*cdf0e10cSrcweir rtl_arena_freelist_remove (
277*cdf0e10cSrcweir 	rtl_arena_type *         arena,
278*cdf0e10cSrcweir 	rtl_arena_segment_type * segment
279*cdf0e10cSrcweir )
280*cdf0e10cSrcweir {
281*cdf0e10cSrcweir 	if ((segment->m_fnext->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD) &&
282*cdf0e10cSrcweir 		(segment->m_fprev->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD)    )
283*cdf0e10cSrcweir 	{
284*cdf0e10cSrcweir 		rtl_arena_segment_type * head;
285*cdf0e10cSrcweir 
286*cdf0e10cSrcweir 		head = segment->m_fprev;
287*cdf0e10cSrcweir 		OSL_ASSERT(arena->m_freelist_bitmap & head->m_size);
288*cdf0e10cSrcweir 		arena->m_freelist_bitmap ^= head->m_size;
289*cdf0e10cSrcweir 	}
290*cdf0e10cSrcweir 	QUEUE_REMOVE_NAMED(segment, f);
291*cdf0e10cSrcweir }
292*cdf0e10cSrcweir 
293*cdf0e10cSrcweir #if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
294*cdf0e10cSrcweir #pragma inline(rtl_arena_freelist_remove)
295*cdf0e10cSrcweir #endif /* __SUNPRO_C */
296*cdf0e10cSrcweir 
297*cdf0e10cSrcweir 
298*cdf0e10cSrcweir /* ================================================================= */
299*cdf0e10cSrcweir 
300*cdf0e10cSrcweir /** RTL_ARENA_HASH_INDEX()
301*cdf0e10cSrcweir  */
302*cdf0e10cSrcweir #define	RTL_ARENA_HASH_INDEX_IMPL(a, s, q, m) \
303*cdf0e10cSrcweir  	((((a) + ((a) >> (s)) + ((a) >> ((s) << 1))) >> (q)) & (m))
304*cdf0e10cSrcweir 
305*cdf0e10cSrcweir #define	RTL_ARENA_HASH_INDEX(arena, addr) \
306*cdf0e10cSrcweir     RTL_ARENA_HASH_INDEX_IMPL((addr), (arena)->m_hash_shift, (arena)->m_quantum_shift, ((arena)->m_hash_size - 1))
307*cdf0e10cSrcweir 
308*cdf0e10cSrcweir /** rtl_arena_hash_rescale()
309*cdf0e10cSrcweir  *
310*cdf0e10cSrcweir  * @precond arena->m_lock released.
311*cdf0e10cSrcweir  */
312*cdf0e10cSrcweir static void
313*cdf0e10cSrcweir rtl_arena_hash_rescale (
314*cdf0e10cSrcweir 	rtl_arena_type * arena,
315*cdf0e10cSrcweir 	sal_Size         new_size
316*cdf0e10cSrcweir )
317*cdf0e10cSrcweir {
318*cdf0e10cSrcweir 	rtl_arena_segment_type ** new_table;
319*cdf0e10cSrcweir 	sal_Size                  new_bytes;
320*cdf0e10cSrcweir 
321*cdf0e10cSrcweir 	new_bytes = new_size * sizeof(rtl_arena_segment_type*);
322*cdf0e10cSrcweir 	new_table = (rtl_arena_segment_type **)rtl_arena_alloc (gp_arena_arena, &new_bytes);
323*cdf0e10cSrcweir 
324*cdf0e10cSrcweir 	if (new_table != 0)
325*cdf0e10cSrcweir 	{
326*cdf0e10cSrcweir 		rtl_arena_segment_type ** old_table;
327*cdf0e10cSrcweir 		sal_Size                  old_size, i;
328*cdf0e10cSrcweir 
329*cdf0e10cSrcweir 		memset (new_table, 0, new_bytes);
330*cdf0e10cSrcweir 
331*cdf0e10cSrcweir 		RTL_MEMORY_LOCK_ACQUIRE(&(arena->m_lock));
332*cdf0e10cSrcweir 
333*cdf0e10cSrcweir 		old_table = arena->m_hash_table;
334*cdf0e10cSrcweir 		old_size  = arena->m_hash_size;
335*cdf0e10cSrcweir 
336*cdf0e10cSrcweir 		OSL_TRACE(
337*cdf0e10cSrcweir 			"rtl_arena_hash_rescale(\"%s\"): "
338*cdf0e10cSrcweir 			"nseg: %"PRIu64" (ave: %"PRIu64"), frees: %"PRIu64" "
339*cdf0e10cSrcweir 			"[old_size: %lu, new_size: %lu]",
340*cdf0e10cSrcweir 			arena->m_name,
341*cdf0e10cSrcweir 			arena->m_stats.m_alloc - arena->m_stats.m_free,
342*cdf0e10cSrcweir 			(arena->m_stats.m_alloc - arena->m_stats.m_free) >> arena->m_hash_shift,
343*cdf0e10cSrcweir 			arena->m_stats.m_free,
344*cdf0e10cSrcweir 			old_size, new_size
345*cdf0e10cSrcweir 		);
346*cdf0e10cSrcweir 
347*cdf0e10cSrcweir #if 0  /* DBG */
348*cdf0e10cSrcweir 		for (i = 0; i < arena->m_hash_size; i++)
349*cdf0e10cSrcweir 		{
350*cdf0e10cSrcweir 			sal_Size k = 0; rtl_arena_segment_type ** segpp = &(arena->m_hash_table[i]);
351*cdf0e10cSrcweir 			while (*segpp)
352*cdf0e10cSrcweir 			{
353*cdf0e10cSrcweir 				k += 1;
354*cdf0e10cSrcweir 				segpp = &((*segpp)->m_fnext);
355*cdf0e10cSrcweir 			}
356*cdf0e10cSrcweir 			fprintf(stdout, "%d, ", k);
357*cdf0e10cSrcweir 		}
358*cdf0e10cSrcweir 		fprintf(stdout, "\n");
359*cdf0e10cSrcweir #endif /* DBG */
360*cdf0e10cSrcweir 
361*cdf0e10cSrcweir 		arena->m_hash_table = new_table;
362*cdf0e10cSrcweir 		arena->m_hash_size  = new_size;
363*cdf0e10cSrcweir 		arena->m_hash_shift = highbit(arena->m_hash_size) - 1;
364*cdf0e10cSrcweir 
365*cdf0e10cSrcweir 		for (i = 0; i < old_size; i++)
366*cdf0e10cSrcweir 		{
367*cdf0e10cSrcweir 			rtl_arena_segment_type * curr = old_table[i];
368*cdf0e10cSrcweir 			while (curr != 0)
369*cdf0e10cSrcweir 			{
370*cdf0e10cSrcweir 				rtl_arena_segment_type  * next = curr->m_fnext;
371*cdf0e10cSrcweir 				rtl_arena_segment_type ** head;
372*cdf0e10cSrcweir 
373*cdf0e10cSrcweir 				head = &(arena->m_hash_table[RTL_ARENA_HASH_INDEX(arena, curr->m_addr)]);
374*cdf0e10cSrcweir 				curr->m_fnext = (*head);
375*cdf0e10cSrcweir 				(*head) = curr;
376*cdf0e10cSrcweir 
377*cdf0e10cSrcweir 				curr = next;
378*cdf0e10cSrcweir 			}
379*cdf0e10cSrcweir 			old_table[i] = 0;
380*cdf0e10cSrcweir 		}
381*cdf0e10cSrcweir 
382*cdf0e10cSrcweir 		RTL_MEMORY_LOCK_RELEASE(&(arena->m_lock));
383*cdf0e10cSrcweir 
384*cdf0e10cSrcweir 		if (old_table != arena->m_hash_table_0)
385*cdf0e10cSrcweir 		{
386*cdf0e10cSrcweir 			sal_Size old_bytes = old_size * sizeof(rtl_arena_segment_type*);
387*cdf0e10cSrcweir 			rtl_arena_free (gp_arena_arena, old_table, old_bytes);
388*cdf0e10cSrcweir 		}
389*cdf0e10cSrcweir 	}
390*cdf0e10cSrcweir }
391*cdf0e10cSrcweir 
392*cdf0e10cSrcweir 
393*cdf0e10cSrcweir /** rtl_arena_hash_insert()
394*cdf0e10cSrcweir  *  ...and update stats.
395*cdf0e10cSrcweir  */
396*cdf0e10cSrcweir static RTL_MEMORY_INLINE void
397*cdf0e10cSrcweir rtl_arena_hash_insert (
398*cdf0e10cSrcweir 	rtl_arena_type *         arena,
399*cdf0e10cSrcweir 	rtl_arena_segment_type * segment
400*cdf0e10cSrcweir )
401*cdf0e10cSrcweir {
402*cdf0e10cSrcweir 	rtl_arena_segment_type ** ppSegment;
403*cdf0e10cSrcweir 
404*cdf0e10cSrcweir 	ppSegment = &(arena->m_hash_table[RTL_ARENA_HASH_INDEX(arena, segment->m_addr)]);
405*cdf0e10cSrcweir 
406*cdf0e10cSrcweir 	segment->m_fnext = (*ppSegment);
407*cdf0e10cSrcweir 	(*ppSegment) = segment;
408*cdf0e10cSrcweir 
409*cdf0e10cSrcweir 	arena->m_stats.m_alloc     += 1;
410*cdf0e10cSrcweir 	arena->m_stats.m_mem_alloc += segment->m_size;
411*cdf0e10cSrcweir }
412*cdf0e10cSrcweir 
413*cdf0e10cSrcweir #if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
414*cdf0e10cSrcweir #pragma inline(rtl_arena_hash_insert)
415*cdf0e10cSrcweir #endif /* __SUNPRO_C */
416*cdf0e10cSrcweir 
417*cdf0e10cSrcweir 
418*cdf0e10cSrcweir /** rtl_arena_hash_remove()
419*cdf0e10cSrcweir  *  ...and update stats.
420*cdf0e10cSrcweir  */
421*cdf0e10cSrcweir static rtl_arena_segment_type *
422*cdf0e10cSrcweir rtl_arena_hash_remove (
423*cdf0e10cSrcweir 	rtl_arena_type * arena,
424*cdf0e10cSrcweir 	sal_uIntPtr      addr,
425*cdf0e10cSrcweir 	sal_Size         size
426*cdf0e10cSrcweir )
427*cdf0e10cSrcweir {
428*cdf0e10cSrcweir 	rtl_arena_segment_type *segment, **segpp;
429*cdf0e10cSrcweir 	sal_Size lookups = 0;
430*cdf0e10cSrcweir 
431*cdf0e10cSrcweir #if OSL_DEBUG_LEVEL == 0
432*cdf0e10cSrcweir     (void) size; /* unused */
433*cdf0e10cSrcweir #endif /* OSL_DEBUG_LEVEL */
434*cdf0e10cSrcweir 
435*cdf0e10cSrcweir 	segpp = &(arena->m_hash_table[RTL_ARENA_HASH_INDEX(arena, addr)]);
436*cdf0e10cSrcweir 	while ((segment = *segpp) != 0)
437*cdf0e10cSrcweir 	{
438*cdf0e10cSrcweir 		if (segment->m_addr == addr)
439*cdf0e10cSrcweir 		{
440*cdf0e10cSrcweir 			*segpp = segment->m_fnext, segment->m_fnext = segment->m_fprev = segment;
441*cdf0e10cSrcweir 			break;
442*cdf0e10cSrcweir 		}
443*cdf0e10cSrcweir 
444*cdf0e10cSrcweir 		/* update lookup miss stats */
445*cdf0e10cSrcweir 		lookups += 1;
446*cdf0e10cSrcweir 		segpp = &(segment->m_fnext);
447*cdf0e10cSrcweir 	}
448*cdf0e10cSrcweir 
449*cdf0e10cSrcweir 	OSL_POSTCOND(segment != 0, "rtl_arena_hash_remove(): bad free.");
450*cdf0e10cSrcweir 	if (segment != 0)
451*cdf0e10cSrcweir 	{
452*cdf0e10cSrcweir 		OSL_POSTCOND(segment->m_size == size, "rtl_arena_hash_remove(): wrong size.");
453*cdf0e10cSrcweir 
454*cdf0e10cSrcweir 		arena->m_stats.m_free      += 1;
455*cdf0e10cSrcweir 		arena->m_stats.m_mem_alloc -= segment->m_size;
456*cdf0e10cSrcweir 
457*cdf0e10cSrcweir 		if (lookups > 1)
458*cdf0e10cSrcweir 		{
459*cdf0e10cSrcweir 			sal_Size nseg = (sal_Size)(arena->m_stats.m_alloc - arena->m_stats.m_free);
460*cdf0e10cSrcweir 			if (nseg > 4 * arena->m_hash_size)
461*cdf0e10cSrcweir 			{
462*cdf0e10cSrcweir 				if (!(arena->m_flags & RTL_ARENA_FLAG_RESCALE))
463*cdf0e10cSrcweir 				{
464*cdf0e10cSrcweir 					sal_Size ave = nseg >> arena->m_hash_shift;
465*cdf0e10cSrcweir 					sal_Size new_size = arena->m_hash_size << (highbit(ave) - 1);
466*cdf0e10cSrcweir 
467*cdf0e10cSrcweir 					arena->m_flags |= RTL_ARENA_FLAG_RESCALE;
468*cdf0e10cSrcweir 					RTL_MEMORY_LOCK_RELEASE(&(arena->m_lock));
469*cdf0e10cSrcweir 					rtl_arena_hash_rescale (arena, new_size);
470*cdf0e10cSrcweir 					RTL_MEMORY_LOCK_ACQUIRE(&(arena->m_lock));
471*cdf0e10cSrcweir 					arena->m_flags &= ~RTL_ARENA_FLAG_RESCALE;
472*cdf0e10cSrcweir 				}
473*cdf0e10cSrcweir 			}
474*cdf0e10cSrcweir 		}
475*cdf0e10cSrcweir 	}
476*cdf0e10cSrcweir 
477*cdf0e10cSrcweir 	return (segment);
478*cdf0e10cSrcweir }
479*cdf0e10cSrcweir 
480*cdf0e10cSrcweir /* ================================================================= */
481*cdf0e10cSrcweir 
482*cdf0e10cSrcweir /** rtl_arena_segment_alloc()
483*cdf0e10cSrcweir  *  allocate (and remove) segment from freelist
484*cdf0e10cSrcweir  *
485*cdf0e10cSrcweir  *  @precond arena->m_lock acquired
486*cdf0e10cSrcweir  *  @precond (*ppSegment == 0)
487*cdf0e10cSrcweir  */
488*cdf0e10cSrcweir static int
489*cdf0e10cSrcweir rtl_arena_segment_alloc (
490*cdf0e10cSrcweir 	rtl_arena_type *          arena,
491*cdf0e10cSrcweir 	sal_Size                  size,
492*cdf0e10cSrcweir 	rtl_arena_segment_type ** ppSegment
493*cdf0e10cSrcweir )
494*cdf0e10cSrcweir {
495*cdf0e10cSrcweir 	int index = 0;
496*cdf0e10cSrcweir 
497*cdf0e10cSrcweir 	OSL_ASSERT(*ppSegment == 0);
498*cdf0e10cSrcweir 	if (!RTL_MEMORY_ISP2(size))
499*cdf0e10cSrcweir 	{
500*cdf0e10cSrcweir 		int msb = highbit(size);
501*cdf0e10cSrcweir 		if (RTL_ARENA_FREELIST_SIZE == SAL_INT_CAST(size_t, msb))
502*cdf0e10cSrcweir 		{
503*cdf0e10cSrcweir 			/* highest possible freelist: fall back to first fit */
504*cdf0e10cSrcweir 			rtl_arena_segment_type *head, *segment;
505*cdf0e10cSrcweir 
506*cdf0e10cSrcweir 			head = &(arena->m_freelist_head[msb - 1]);
507*cdf0e10cSrcweir 			for (segment = head->m_fnext; segment != head; segment = segment->m_fnext)
508*cdf0e10cSrcweir 			{
509*cdf0e10cSrcweir 				if (segment->m_size >= size)
510*cdf0e10cSrcweir 				{
511*cdf0e10cSrcweir 					/* allocate first fit segment */
512*cdf0e10cSrcweir 					(*ppSegment) = segment;
513*cdf0e10cSrcweir 					break;
514*cdf0e10cSrcweir 				}
515*cdf0e10cSrcweir 			}
516*cdf0e10cSrcweir 			goto dequeue_and_leave;
517*cdf0e10cSrcweir 		}
518*cdf0e10cSrcweir 
519*cdf0e10cSrcweir 		/* roundup to next power of 2 */
520*cdf0e10cSrcweir 		size = (1UL << msb);
521*cdf0e10cSrcweir 	}
522*cdf0e10cSrcweir 
523*cdf0e10cSrcweir 	index = lowbit(RTL_MEMORY_P2ALIGN(arena->m_freelist_bitmap, size));
524*cdf0e10cSrcweir 	if (index > 0)
525*cdf0e10cSrcweir 	{
526*cdf0e10cSrcweir 		/* instant fit: allocate first free segment */
527*cdf0e10cSrcweir 		rtl_arena_segment_type *head;
528*cdf0e10cSrcweir 
529*cdf0e10cSrcweir 		head = &(arena->m_freelist_head[index - 1]);
530*cdf0e10cSrcweir 		(*ppSegment) = head->m_fnext;
531*cdf0e10cSrcweir 		OSL_ASSERT((*ppSegment) != head);
532*cdf0e10cSrcweir 	}
533*cdf0e10cSrcweir 
534*cdf0e10cSrcweir dequeue_and_leave:
535*cdf0e10cSrcweir 	if (*ppSegment != 0)
536*cdf0e10cSrcweir 	{
537*cdf0e10cSrcweir 		/* remove from freelist */
538*cdf0e10cSrcweir 		rtl_arena_freelist_remove (arena, (*ppSegment));
539*cdf0e10cSrcweir 	}
540*cdf0e10cSrcweir 	return (*ppSegment != 0);
541*cdf0e10cSrcweir }
542*cdf0e10cSrcweir 
543*cdf0e10cSrcweir 
544*cdf0e10cSrcweir /** rtl_arena_segment_create()
545*cdf0e10cSrcweir  *  import new (span) segment from source arena
546*cdf0e10cSrcweir  *
547*cdf0e10cSrcweir  *  @precond arena->m_lock acquired
548*cdf0e10cSrcweir  *  @precond (*ppSegment == 0)
549*cdf0e10cSrcweir  */
550*cdf0e10cSrcweir static int
551*cdf0e10cSrcweir rtl_arena_segment_create (
552*cdf0e10cSrcweir 	rtl_arena_type *          arena,
553*cdf0e10cSrcweir 	sal_Size                  size,
554*cdf0e10cSrcweir 	rtl_arena_segment_type ** ppSegment
555*cdf0e10cSrcweir )
556*cdf0e10cSrcweir {
557*cdf0e10cSrcweir 	OSL_ASSERT((*ppSegment) == 0);
558*cdf0e10cSrcweir 	if (arena->m_source_alloc != 0)
559*cdf0e10cSrcweir 	{
560*cdf0e10cSrcweir 		rtl_arena_segment_get (arena, ppSegment);
561*cdf0e10cSrcweir 		if (*ppSegment != 0)
562*cdf0e10cSrcweir 		{
563*cdf0e10cSrcweir 			rtl_arena_segment_type * span = 0;
564*cdf0e10cSrcweir 			rtl_arena_segment_get (arena, &span);
565*cdf0e10cSrcweir 			if (span != 0)
566*cdf0e10cSrcweir 			{
567*cdf0e10cSrcweir 				/* import new span from source arena */
568*cdf0e10cSrcweir 				RTL_MEMORY_LOCK_RELEASE(&(arena->m_lock));
569*cdf0e10cSrcweir 
570*cdf0e10cSrcweir 				span->m_size = size;
571*cdf0e10cSrcweir 				span->m_addr = (sal_uIntPtr)(arena->m_source_alloc)(
572*cdf0e10cSrcweir 					arena->m_source_arena, &(span->m_size));
573*cdf0e10cSrcweir 
574*cdf0e10cSrcweir 				RTL_MEMORY_LOCK_ACQUIRE(&(arena->m_lock));
575*cdf0e10cSrcweir 				if (span->m_addr != 0)
576*cdf0e10cSrcweir 				{
577*cdf0e10cSrcweir 					/* insert onto segment list, update stats */
578*cdf0e10cSrcweir 					span->m_type = RTL_ARENA_SEGMENT_TYPE_SPAN;
579*cdf0e10cSrcweir 					QUEUE_INSERT_HEAD_NAMED(&(arena->m_segment_head), span, s);
580*cdf0e10cSrcweir 					arena->m_stats.m_mem_total += span->m_size;
581*cdf0e10cSrcweir 
582*cdf0e10cSrcweir 					(*ppSegment)->m_addr = span->m_addr;
583*cdf0e10cSrcweir 					(*ppSegment)->m_size = span->m_size;
584*cdf0e10cSrcweir 					(*ppSegment)->m_type = RTL_ARENA_SEGMENT_TYPE_FREE;
585*cdf0e10cSrcweir 					QUEUE_INSERT_HEAD_NAMED(span, (*ppSegment), s);
586*cdf0e10cSrcweir 
587*cdf0e10cSrcweir 					/* report success */
588*cdf0e10cSrcweir 					return (1);
589*cdf0e10cSrcweir 				}
590*cdf0e10cSrcweir 				rtl_arena_segment_put (arena, &span);
591*cdf0e10cSrcweir 			}
592*cdf0e10cSrcweir 			rtl_arena_segment_put (arena, ppSegment);
593*cdf0e10cSrcweir 		}
594*cdf0e10cSrcweir 	}
595*cdf0e10cSrcweir 	return (0);
596*cdf0e10cSrcweir }
597*cdf0e10cSrcweir 
598*cdf0e10cSrcweir 
599*cdf0e10cSrcweir /** rtl_arena_segment_coalesce()
600*cdf0e10cSrcweir  *  mark as free and join with adjacent free segment(s)
601*cdf0e10cSrcweir  *
602*cdf0e10cSrcweir  *  @precond arena->m_lock acquired
603*cdf0e10cSrcweir  *  @precond segment marked 'used'
604*cdf0e10cSrcweir  */
605*cdf0e10cSrcweir static void
606*cdf0e10cSrcweir rtl_arena_segment_coalesce (
607*cdf0e10cSrcweir 	rtl_arena_type *         arena,
608*cdf0e10cSrcweir 	rtl_arena_segment_type * segment
609*cdf0e10cSrcweir )
610*cdf0e10cSrcweir {
611*cdf0e10cSrcweir 	rtl_arena_segment_type *next, *prev;
612*cdf0e10cSrcweir 
613*cdf0e10cSrcweir 	/* mark segment free */
614*cdf0e10cSrcweir 	OSL_ASSERT(segment->m_type == RTL_ARENA_SEGMENT_TYPE_USED);
615*cdf0e10cSrcweir 	segment->m_type = RTL_ARENA_SEGMENT_TYPE_FREE;
616*cdf0e10cSrcweir 
617*cdf0e10cSrcweir 	/* try to merge w/ next segment */
618*cdf0e10cSrcweir 	next = segment->m_snext;
619*cdf0e10cSrcweir 	if (next->m_type == RTL_ARENA_SEGMENT_TYPE_FREE)
620*cdf0e10cSrcweir 	{
621*cdf0e10cSrcweir 		OSL_ASSERT(segment->m_addr + segment->m_size == next->m_addr);
622*cdf0e10cSrcweir 		segment->m_size += next->m_size;
623*cdf0e10cSrcweir 
624*cdf0e10cSrcweir 		/* remove from freelist */
625*cdf0e10cSrcweir 		rtl_arena_freelist_remove (arena, next);
626*cdf0e10cSrcweir 
627*cdf0e10cSrcweir 		/* remove from segment list */
628*cdf0e10cSrcweir 		QUEUE_REMOVE_NAMED(next, s);
629*cdf0e10cSrcweir 
630*cdf0e10cSrcweir 		/* release segment descriptor */
631*cdf0e10cSrcweir 		rtl_arena_segment_put (arena, &next);
632*cdf0e10cSrcweir 	}
633*cdf0e10cSrcweir 
634*cdf0e10cSrcweir 	/* try to merge w/ prev segment */
635*cdf0e10cSrcweir 	prev = segment->m_sprev;
636*cdf0e10cSrcweir 	if (prev->m_type == RTL_ARENA_SEGMENT_TYPE_FREE)
637*cdf0e10cSrcweir 	{
638*cdf0e10cSrcweir 		OSL_ASSERT(prev->m_addr + prev->m_size == segment->m_addr);
639*cdf0e10cSrcweir 		segment->m_addr  = prev->m_addr;
640*cdf0e10cSrcweir 		segment->m_size += prev->m_size;
641*cdf0e10cSrcweir 
642*cdf0e10cSrcweir 		/* remove from freelist */
643*cdf0e10cSrcweir 		rtl_arena_freelist_remove (arena, prev);
644*cdf0e10cSrcweir 
645*cdf0e10cSrcweir 		/* remove from segment list */
646*cdf0e10cSrcweir 		QUEUE_REMOVE_NAMED(prev, s);
647*cdf0e10cSrcweir 
648*cdf0e10cSrcweir 		/* release segment descriptor */
649*cdf0e10cSrcweir 		rtl_arena_segment_put (arena, &prev);
650*cdf0e10cSrcweir 	}
651*cdf0e10cSrcweir }
652*cdf0e10cSrcweir 
653*cdf0e10cSrcweir /* ================================================================= */
654*cdf0e10cSrcweir 
655*cdf0e10cSrcweir /** rtl_arena_constructor()
656*cdf0e10cSrcweir  */
657*cdf0e10cSrcweir static void
658*cdf0e10cSrcweir rtl_arena_constructor (void * obj)
659*cdf0e10cSrcweir {
660*cdf0e10cSrcweir 	rtl_arena_type * arena = (rtl_arena_type*)(obj);
661*cdf0e10cSrcweir 	rtl_arena_segment_type * head;
662*cdf0e10cSrcweir 	size_t i;
663*cdf0e10cSrcweir 
664*cdf0e10cSrcweir 	memset (arena, 0, sizeof(rtl_arena_type));
665*cdf0e10cSrcweir 
666*cdf0e10cSrcweir 	QUEUE_START_NAMED(arena, arena_);
667*cdf0e10cSrcweir 
668*cdf0e10cSrcweir 	(void) RTL_MEMORY_LOCK_INIT(&(arena->m_lock));
669*cdf0e10cSrcweir 
670*cdf0e10cSrcweir 	head = &(arena->m_segment_reserve_span_head);
671*cdf0e10cSrcweir 	rtl_arena_segment_constructor (head);
672*cdf0e10cSrcweir 	head->m_type = RTL_ARENA_SEGMENT_TYPE_HEAD;
673*cdf0e10cSrcweir 
674*cdf0e10cSrcweir 	head = &(arena->m_segment_reserve_head);
675*cdf0e10cSrcweir 	rtl_arena_segment_constructor (head);
676*cdf0e10cSrcweir 	head->m_type = RTL_ARENA_SEGMENT_TYPE_HEAD;
677*cdf0e10cSrcweir 
678*cdf0e10cSrcweir 	head = &(arena->m_segment_head);
679*cdf0e10cSrcweir 	rtl_arena_segment_constructor (head);
680*cdf0e10cSrcweir 	head->m_type = RTL_ARENA_SEGMENT_TYPE_HEAD;
681*cdf0e10cSrcweir 
682*cdf0e10cSrcweir 	for (i = 0; i < RTL_ARENA_FREELIST_SIZE; i++)
683*cdf0e10cSrcweir 	{
684*cdf0e10cSrcweir 		head = &(arena->m_freelist_head[i]);
685*cdf0e10cSrcweir 		rtl_arena_segment_constructor (head);
686*cdf0e10cSrcweir 
687*cdf0e10cSrcweir 		head->m_size = (1UL << i);
688*cdf0e10cSrcweir 		head->m_type = RTL_ARENA_SEGMENT_TYPE_HEAD;
689*cdf0e10cSrcweir 	}
690*cdf0e10cSrcweir 
691*cdf0e10cSrcweir 	arena->m_hash_table = arena->m_hash_table_0;
692*cdf0e10cSrcweir 	arena->m_hash_size  = RTL_ARENA_HASH_SIZE;
693*cdf0e10cSrcweir 	arena->m_hash_shift = highbit(arena->m_hash_size) - 1;
694*cdf0e10cSrcweir }
695*cdf0e10cSrcweir 
696*cdf0e10cSrcweir 
697*cdf0e10cSrcweir /** rtl_arena_destructor()
698*cdf0e10cSrcweir  */
699*cdf0e10cSrcweir static void
700*cdf0e10cSrcweir rtl_arena_destructor (void * obj)
701*cdf0e10cSrcweir {
702*cdf0e10cSrcweir 	rtl_arena_type * arena = (rtl_arena_type*)(obj);
703*cdf0e10cSrcweir 	rtl_arena_segment_type * head;
704*cdf0e10cSrcweir 	size_t i;
705*cdf0e10cSrcweir 
706*cdf0e10cSrcweir 	OSL_ASSERT(QUEUE_STARTED_NAMED(arena, arena_));
707*cdf0e10cSrcweir 
708*cdf0e10cSrcweir 	RTL_MEMORY_LOCK_DESTROY(&(arena->m_lock));
709*cdf0e10cSrcweir 
710*cdf0e10cSrcweir 	head = &(arena->m_segment_reserve_span_head);
711*cdf0e10cSrcweir 	OSL_ASSERT(head->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD);
712*cdf0e10cSrcweir 	rtl_arena_segment_destructor (head);
713*cdf0e10cSrcweir 
714*cdf0e10cSrcweir 	head = &(arena->m_segment_reserve_head);
715*cdf0e10cSrcweir 	OSL_ASSERT(head->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD);
716*cdf0e10cSrcweir 	rtl_arena_segment_destructor (head);
717*cdf0e10cSrcweir 
718*cdf0e10cSrcweir 	head = &(arena->m_segment_head);
719*cdf0e10cSrcweir 	OSL_ASSERT(head->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD);
720*cdf0e10cSrcweir 	rtl_arena_segment_destructor (head);
721*cdf0e10cSrcweir 
722*cdf0e10cSrcweir 	for (i = 0; i < RTL_ARENA_FREELIST_SIZE; i++)
723*cdf0e10cSrcweir 	{
724*cdf0e10cSrcweir 		head = &(arena->m_freelist_head[i]);
725*cdf0e10cSrcweir 
726*cdf0e10cSrcweir 		OSL_ASSERT(head->m_size == (1UL << i));
727*cdf0e10cSrcweir 		OSL_ASSERT(head->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD);
728*cdf0e10cSrcweir 
729*cdf0e10cSrcweir 		rtl_arena_segment_destructor (head);
730*cdf0e10cSrcweir 	}
731*cdf0e10cSrcweir 
732*cdf0e10cSrcweir 	OSL_ASSERT(arena->m_hash_table == arena->m_hash_table_0);
733*cdf0e10cSrcweir 	OSL_ASSERT(arena->m_hash_size  == RTL_ARENA_HASH_SIZE);
734*cdf0e10cSrcweir 	OSL_ASSERT(
735*cdf0e10cSrcweir         arena->m_hash_shift ==
736*cdf0e10cSrcweir         SAL_INT_CAST(unsigned, highbit(arena->m_hash_size) - 1));
737*cdf0e10cSrcweir }
738*cdf0e10cSrcweir 
739*cdf0e10cSrcweir /* ================================================================= */
740*cdf0e10cSrcweir 
741*cdf0e10cSrcweir /** rtl_arena_activate()
742*cdf0e10cSrcweir  */
743*cdf0e10cSrcweir static rtl_arena_type *
744*cdf0e10cSrcweir rtl_arena_activate (
745*cdf0e10cSrcweir 	rtl_arena_type *   arena,
746*cdf0e10cSrcweir 	const char *       name,
747*cdf0e10cSrcweir 	sal_Size           quantum,
748*cdf0e10cSrcweir 	sal_Size           quantum_cache_max,
749*cdf0e10cSrcweir 	rtl_arena_type *   source_arena,
750*cdf0e10cSrcweir 	void * (SAL_CALL * source_alloc)(rtl_arena_type *, sal_Size *),
751*cdf0e10cSrcweir 	void   (SAL_CALL * source_free) (rtl_arena_type *, void *, sal_Size)
752*cdf0e10cSrcweir )
753*cdf0e10cSrcweir {
754*cdf0e10cSrcweir 	OSL_ASSERT(arena != 0);
755*cdf0e10cSrcweir 	if (arena != 0)
756*cdf0e10cSrcweir 	{
757*cdf0e10cSrcweir 		(void) snprintf (arena->m_name, sizeof(arena->m_name), "%s", name);
758*cdf0e10cSrcweir 
759*cdf0e10cSrcweir 		if (!RTL_MEMORY_ISP2(quantum))
760*cdf0e10cSrcweir 		{
761*cdf0e10cSrcweir 			/* roundup to next power of 2 */
762*cdf0e10cSrcweir 			quantum = (1UL << highbit(quantum));
763*cdf0e10cSrcweir 		}
764*cdf0e10cSrcweir 		quantum_cache_max = RTL_MEMORY_P2ROUNDUP(quantum_cache_max, quantum);
765*cdf0e10cSrcweir 
766*cdf0e10cSrcweir 		arena->m_quantum = quantum;
767*cdf0e10cSrcweir 		arena->m_quantum_shift = highbit(arena->m_quantum) - 1;
768*cdf0e10cSrcweir 		arena->m_qcache_max = quantum_cache_max;
769*cdf0e10cSrcweir 
770*cdf0e10cSrcweir 		arena->m_source_arena = source_arena;
771*cdf0e10cSrcweir 		arena->m_source_alloc = source_alloc;
772*cdf0e10cSrcweir 		arena->m_source_free  = source_free;
773*cdf0e10cSrcweir 
774*cdf0e10cSrcweir 		if (arena->m_qcache_max > 0)
775*cdf0e10cSrcweir 		{
776*cdf0e10cSrcweir 			char name[RTL_ARENA_NAME_LENGTH + 1];
777*cdf0e10cSrcweir 			int  i, n = (arena->m_qcache_max >> arena->m_quantum_shift);
778*cdf0e10cSrcweir 
779*cdf0e10cSrcweir 			sal_Size size = n * sizeof(rtl_cache_type*);
780*cdf0e10cSrcweir 			arena->m_qcache_ptr = (rtl_cache_type**)rtl_arena_alloc (gp_arena_arena, &size);
781*cdf0e10cSrcweir 			if (!(arena->m_qcache_ptr))
782*cdf0e10cSrcweir 			{
783*cdf0e10cSrcweir 				/* out of memory */
784*cdf0e10cSrcweir 				return (0);
785*cdf0e10cSrcweir 			}
786*cdf0e10cSrcweir 			for (i = 1; i <= n; i++)
787*cdf0e10cSrcweir 			{
788*cdf0e10cSrcweir 				size = i * arena->m_quantum;
789*cdf0e10cSrcweir 				(void) snprintf (name, sizeof(name), "%s_%lu", arena->m_name, size);
790*cdf0e10cSrcweir 				arena->m_qcache_ptr[i - 1] = rtl_cache_create(name, size, 0, NULL, NULL, NULL, NULL, arena, RTL_CACHE_FLAG_QUANTUMCACHE);
791*cdf0e10cSrcweir 			}
792*cdf0e10cSrcweir 		}
793*cdf0e10cSrcweir 
794*cdf0e10cSrcweir 		/* insert into arena list */
795*cdf0e10cSrcweir 		RTL_MEMORY_LOCK_ACQUIRE(&(g_arena_list.m_lock));
796*cdf0e10cSrcweir 		QUEUE_INSERT_TAIL_NAMED(&(g_arena_list.m_arena_head), arena, arena_);
797*cdf0e10cSrcweir 		RTL_MEMORY_LOCK_RELEASE(&(g_arena_list.m_lock));
798*cdf0e10cSrcweir 	}
799*cdf0e10cSrcweir 	return (arena);
800*cdf0e10cSrcweir }
801*cdf0e10cSrcweir 
802*cdf0e10cSrcweir /** rtl_arena_deactivate()
803*cdf0e10cSrcweir  */
804*cdf0e10cSrcweir static void
805*cdf0e10cSrcweir rtl_arena_deactivate (
806*cdf0e10cSrcweir 	rtl_arena_type * arena
807*cdf0e10cSrcweir )
808*cdf0e10cSrcweir {
809*cdf0e10cSrcweir 	rtl_arena_segment_type * head, * segment;
810*cdf0e10cSrcweir 
811*cdf0e10cSrcweir 	/* remove from arena list */
812*cdf0e10cSrcweir 	RTL_MEMORY_LOCK_ACQUIRE(&(g_arena_list.m_lock));
813*cdf0e10cSrcweir 	QUEUE_REMOVE_NAMED(arena, arena_);
814*cdf0e10cSrcweir 	RTL_MEMORY_LOCK_RELEASE(&(g_arena_list.m_lock));
815*cdf0e10cSrcweir 
816*cdf0e10cSrcweir 	/* cleanup quantum cache(s) */
817*cdf0e10cSrcweir 	if ((arena->m_qcache_max > 0) && (arena->m_qcache_ptr != 0))
818*cdf0e10cSrcweir 	{
819*cdf0e10cSrcweir 		int  i, n = (arena->m_qcache_max >> arena->m_quantum_shift);
820*cdf0e10cSrcweir 		for (i = 1; i <= n; i++)
821*cdf0e10cSrcweir 		{
822*cdf0e10cSrcweir 			if (arena->m_qcache_ptr[i - 1] != 0)
823*cdf0e10cSrcweir 			{
824*cdf0e10cSrcweir 				rtl_cache_destroy (arena->m_qcache_ptr[i - 1]);
825*cdf0e10cSrcweir 				arena->m_qcache_ptr[i - 1] = 0;
826*cdf0e10cSrcweir 			}
827*cdf0e10cSrcweir 		}
828*cdf0e10cSrcweir 		rtl_arena_free (
829*cdf0e10cSrcweir 			gp_arena_arena,
830*cdf0e10cSrcweir 			arena->m_qcache_ptr,
831*cdf0e10cSrcweir 			n * sizeof(rtl_cache_type*));
832*cdf0e10cSrcweir 
833*cdf0e10cSrcweir 		arena->m_qcache_ptr = 0;
834*cdf0e10cSrcweir 	}
835*cdf0e10cSrcweir 
836*cdf0e10cSrcweir 	/* check for leaked segments */
837*cdf0e10cSrcweir 	OSL_TRACE(
838*cdf0e10cSrcweir 		"rtl_arena_deactivate(\"%s\"): "
839*cdf0e10cSrcweir 		"allocs: %"PRIu64", frees: %"PRIu64"; total: %lu, used: %lu",
840*cdf0e10cSrcweir 		arena->m_name,
841*cdf0e10cSrcweir 		arena->m_stats.m_alloc, arena->m_stats.m_free,
842*cdf0e10cSrcweir 		arena->m_stats.m_mem_total, arena->m_stats.m_mem_alloc
843*cdf0e10cSrcweir 	);
844*cdf0e10cSrcweir 	if (arena->m_stats.m_alloc > arena->m_stats.m_free)
845*cdf0e10cSrcweir 	{
846*cdf0e10cSrcweir 		sal_Size i, n;
847*cdf0e10cSrcweir 
848*cdf0e10cSrcweir 		OSL_TRACE(
849*cdf0e10cSrcweir 			"rtl_arena_deactivate(\"%s\"): "
850*cdf0e10cSrcweir 			"cleaning up %"PRIu64" leaked segment(s) [%lu bytes]",
851*cdf0e10cSrcweir 			arena->m_name,
852*cdf0e10cSrcweir 			arena->m_stats.m_alloc - arena->m_stats.m_free,
853*cdf0e10cSrcweir 			arena->m_stats.m_mem_alloc
854*cdf0e10cSrcweir 		);
855*cdf0e10cSrcweir 
856*cdf0e10cSrcweir 		/* cleanup still used segment(s) */
857*cdf0e10cSrcweir 		for (i = 0, n = arena->m_hash_size; i < n; i++)
858*cdf0e10cSrcweir 		{
859*cdf0e10cSrcweir 			while ((segment = arena->m_hash_table[i]) != 0)
860*cdf0e10cSrcweir 			{
861*cdf0e10cSrcweir 				/* pop from hash table */
862*cdf0e10cSrcweir 				arena->m_hash_table[i] = segment->m_fnext, segment->m_fnext = segment->m_fprev = segment;
863*cdf0e10cSrcweir 
864*cdf0e10cSrcweir 				/* coalesce w/ adjacent free segment(s) */
865*cdf0e10cSrcweir 				rtl_arena_segment_coalesce (arena, segment);
866*cdf0e10cSrcweir 
867*cdf0e10cSrcweir 				/* insert onto freelist */
868*cdf0e10cSrcweir 				rtl_arena_freelist_insert (arena, segment);
869*cdf0e10cSrcweir 			}
870*cdf0e10cSrcweir 		}
871*cdf0e10cSrcweir 	}
872*cdf0e10cSrcweir 
873*cdf0e10cSrcweir 	/* cleanup hash table */
874*cdf0e10cSrcweir 	if (arena->m_hash_table != arena->m_hash_table_0)
875*cdf0e10cSrcweir 	{
876*cdf0e10cSrcweir 		rtl_arena_free (
877*cdf0e10cSrcweir 			gp_arena_arena,
878*cdf0e10cSrcweir 			arena->m_hash_table,
879*cdf0e10cSrcweir 			arena->m_hash_size * sizeof(rtl_arena_segment_type*));
880*cdf0e10cSrcweir 
881*cdf0e10cSrcweir 		arena->m_hash_table = arena->m_hash_table_0;
882*cdf0e10cSrcweir 		arena->m_hash_size  = RTL_ARENA_HASH_SIZE;
883*cdf0e10cSrcweir 		arena->m_hash_shift = highbit(arena->m_hash_size) - 1;
884*cdf0e10cSrcweir 	}
885*cdf0e10cSrcweir 
886*cdf0e10cSrcweir 	/* cleanup segment list */
887*cdf0e10cSrcweir 	head = &(arena->m_segment_head);
888*cdf0e10cSrcweir 	for (segment = head->m_snext; segment != head; segment = head->m_snext)
889*cdf0e10cSrcweir 	{
890*cdf0e10cSrcweir 		if (segment->m_type == RTL_ARENA_SEGMENT_TYPE_FREE)
891*cdf0e10cSrcweir 		{
892*cdf0e10cSrcweir 			/* remove from freelist */
893*cdf0e10cSrcweir 			rtl_arena_freelist_remove (arena, segment);
894*cdf0e10cSrcweir 		}
895*cdf0e10cSrcweir 		else
896*cdf0e10cSrcweir 		{
897*cdf0e10cSrcweir 			/* can have only free and span segments here */
898*cdf0e10cSrcweir 			OSL_ASSERT(segment->m_type == RTL_ARENA_SEGMENT_TYPE_SPAN);
899*cdf0e10cSrcweir 		}
900*cdf0e10cSrcweir 
901*cdf0e10cSrcweir 		/* remove from segment list */
902*cdf0e10cSrcweir 		QUEUE_REMOVE_NAMED(segment, s);
903*cdf0e10cSrcweir 
904*cdf0e10cSrcweir 		/* release segment descriptor */
905*cdf0e10cSrcweir 		rtl_arena_segment_put (arena, &segment);
906*cdf0e10cSrcweir 	}
907*cdf0e10cSrcweir 
908*cdf0e10cSrcweir 	/* cleanup segment reserve list */
909*cdf0e10cSrcweir 	head = &(arena->m_segment_reserve_head);
910*cdf0e10cSrcweir 	for (segment = head->m_snext; segment != head; segment = head->m_snext)
911*cdf0e10cSrcweir 	{
912*cdf0e10cSrcweir 		/* remove from segment list */
913*cdf0e10cSrcweir 		QUEUE_REMOVE_NAMED(segment, s);
914*cdf0e10cSrcweir 	}
915*cdf0e10cSrcweir 
916*cdf0e10cSrcweir 	/* cleanup segment reserve span(s) */
917*cdf0e10cSrcweir 	head = &(arena->m_segment_reserve_span_head);
918*cdf0e10cSrcweir 	for (segment = head->m_snext; segment != head; segment = head->m_snext)
919*cdf0e10cSrcweir 	{
920*cdf0e10cSrcweir 		/* can have only span segments here */
921*cdf0e10cSrcweir 		OSL_ASSERT(segment->m_type == RTL_ARENA_SEGMENT_TYPE_SPAN);
922*cdf0e10cSrcweir 
923*cdf0e10cSrcweir 		/* remove from segment list */
924*cdf0e10cSrcweir 		QUEUE_REMOVE_NAMED(segment, s);
925*cdf0e10cSrcweir 
926*cdf0e10cSrcweir 		/* return span to g_machdep_arena */
927*cdf0e10cSrcweir 		rtl_machdep_free (gp_machdep_arena, (void*)(segment->m_addr), segment->m_size);
928*cdf0e10cSrcweir 	}
929*cdf0e10cSrcweir }
930*cdf0e10cSrcweir 
931*cdf0e10cSrcweir /* ================================================================= *
932*cdf0e10cSrcweir  *
933*cdf0e10cSrcweir  * arena implementation.
934*cdf0e10cSrcweir  *
935*cdf0e10cSrcweir  * ================================================================= */
936*cdf0e10cSrcweir 
937*cdf0e10cSrcweir /** rtl_arena_create()
938*cdf0e10cSrcweir  */
939*cdf0e10cSrcweir rtl_arena_type *
940*cdf0e10cSrcweir SAL_CALL rtl_arena_create (
941*cdf0e10cSrcweir 	const char *       name,
942*cdf0e10cSrcweir 	sal_Size           quantum,
943*cdf0e10cSrcweir 	sal_Size           quantum_cache_max,
944*cdf0e10cSrcweir 	rtl_arena_type *   source_arena,
945*cdf0e10cSrcweir 	void * (SAL_CALL * source_alloc)(rtl_arena_type *, sal_Size *),
946*cdf0e10cSrcweir 	void   (SAL_CALL * source_free) (rtl_arena_type *, void *, sal_Size),
947*cdf0e10cSrcweir 	int                flags
948*cdf0e10cSrcweir ) SAL_THROW_EXTERN_C()
949*cdf0e10cSrcweir {
950*cdf0e10cSrcweir 	rtl_arena_type * result = 0;
951*cdf0e10cSrcweir 	sal_Size         size   = sizeof(rtl_arena_type);
952*cdf0e10cSrcweir 
953*cdf0e10cSrcweir     (void) flags; /* unused */
954*cdf0e10cSrcweir 
955*cdf0e10cSrcweir try_alloc:
956*cdf0e10cSrcweir 	result = (rtl_arena_type*)rtl_arena_alloc (gp_arena_arena, &size);
957*cdf0e10cSrcweir 	if (result != 0)
958*cdf0e10cSrcweir 	{
959*cdf0e10cSrcweir 		rtl_arena_type * arena = result;
960*cdf0e10cSrcweir 		VALGRIND_CREATE_MEMPOOL(arena, 0, 0);
961*cdf0e10cSrcweir 		rtl_arena_constructor (arena);
962*cdf0e10cSrcweir 
963*cdf0e10cSrcweir 		if (!source_arena)
964*cdf0e10cSrcweir 		{
965*cdf0e10cSrcweir 			OSL_ASSERT(gp_default_arena != 0);
966*cdf0e10cSrcweir 			source_arena = gp_default_arena;
967*cdf0e10cSrcweir 		}
968*cdf0e10cSrcweir 
969*cdf0e10cSrcweir 		result = rtl_arena_activate (
970*cdf0e10cSrcweir 			arena,
971*cdf0e10cSrcweir 			name,
972*cdf0e10cSrcweir 			quantum,
973*cdf0e10cSrcweir 			quantum_cache_max,
974*cdf0e10cSrcweir 			source_arena,
975*cdf0e10cSrcweir 			source_alloc,
976*cdf0e10cSrcweir 			source_free
977*cdf0e10cSrcweir 		);
978*cdf0e10cSrcweir 
979*cdf0e10cSrcweir 		if (result == 0)
980*cdf0e10cSrcweir 		{
981*cdf0e10cSrcweir 			rtl_arena_deactivate (arena);
982*cdf0e10cSrcweir 			rtl_arena_destructor (arena);
983*cdf0e10cSrcweir 			VALGRIND_DESTROY_MEMPOOL(arena);
984*cdf0e10cSrcweir 			rtl_arena_free (gp_arena_arena, arena, size);
985*cdf0e10cSrcweir 		}
986*cdf0e10cSrcweir 	}
987*cdf0e10cSrcweir 	else if (gp_arena_arena == 0)
988*cdf0e10cSrcweir 	{
989*cdf0e10cSrcweir 		if (rtl_arena_init())
990*cdf0e10cSrcweir 		{
991*cdf0e10cSrcweir 			/* try again */
992*cdf0e10cSrcweir 			goto try_alloc;
993*cdf0e10cSrcweir 		}
994*cdf0e10cSrcweir 	}
995*cdf0e10cSrcweir 	return (result);
996*cdf0e10cSrcweir }
997*cdf0e10cSrcweir 
998*cdf0e10cSrcweir /** rtl_arena_destroy()
999*cdf0e10cSrcweir  */
1000*cdf0e10cSrcweir void
1001*cdf0e10cSrcweir SAL_CALL rtl_arena_destroy (
1002*cdf0e10cSrcweir 	rtl_arena_type * arena
1003*cdf0e10cSrcweir )
1004*cdf0e10cSrcweir {
1005*cdf0e10cSrcweir 	if (arena != 0)
1006*cdf0e10cSrcweir 	{
1007*cdf0e10cSrcweir 		rtl_arena_deactivate (arena);
1008*cdf0e10cSrcweir 		rtl_arena_destructor (arena);
1009*cdf0e10cSrcweir 		VALGRIND_DESTROY_MEMPOOL(arena);
1010*cdf0e10cSrcweir 		rtl_arena_free (gp_arena_arena, arena, sizeof(rtl_arena_type));
1011*cdf0e10cSrcweir 	}
1012*cdf0e10cSrcweir }
1013*cdf0e10cSrcweir 
1014*cdf0e10cSrcweir /** rtl_arena_alloc()
1015*cdf0e10cSrcweir  */
1016*cdf0e10cSrcweir void *
1017*cdf0e10cSrcweir SAL_CALL rtl_arena_alloc (
1018*cdf0e10cSrcweir 	rtl_arena_type * arena,
1019*cdf0e10cSrcweir 	sal_Size *       pSize
1020*cdf0e10cSrcweir ) SAL_THROW_EXTERN_C()
1021*cdf0e10cSrcweir {
1022*cdf0e10cSrcweir 	void * addr = 0;
1023*cdf0e10cSrcweir 
1024*cdf0e10cSrcweir 	if ((arena != 0) && (pSize != 0))
1025*cdf0e10cSrcweir 	{
1026*cdf0e10cSrcweir 		sal_Size size = RTL_MEMORY_ALIGN((*pSize), arena->m_quantum);
1027*cdf0e10cSrcweir 		if (size > arena->m_qcache_max)
1028*cdf0e10cSrcweir 		{
1029*cdf0e10cSrcweir 			/* allocate from segment list */
1030*cdf0e10cSrcweir 			rtl_arena_segment_type *segment = 0;
1031*cdf0e10cSrcweir 
1032*cdf0e10cSrcweir 			RTL_MEMORY_LOCK_ACQUIRE(&(arena->m_lock));
1033*cdf0e10cSrcweir 			if (rtl_arena_segment_alloc (arena, size, &segment) ||
1034*cdf0e10cSrcweir 				rtl_arena_segment_create(arena, size, &segment)    )
1035*cdf0e10cSrcweir 			{
1036*cdf0e10cSrcweir 				/* shrink to fit */
1037*cdf0e10cSrcweir 				sal_Size oversize;
1038*cdf0e10cSrcweir 
1039*cdf0e10cSrcweir 				/* mark segment used */
1040*cdf0e10cSrcweir 				OSL_ASSERT(segment->m_type == RTL_ARENA_SEGMENT_TYPE_FREE);
1041*cdf0e10cSrcweir 				segment->m_type = RTL_ARENA_SEGMENT_TYPE_USED;
1042*cdf0e10cSrcweir 
1043*cdf0e10cSrcweir 				/* resize */
1044*cdf0e10cSrcweir 				OSL_ASSERT(segment->m_size >= size);
1045*cdf0e10cSrcweir 				oversize = segment->m_size - size;
1046*cdf0e10cSrcweir 				if (oversize >= SAL_MAX(arena->m_quantum, arena->m_qcache_max))
1047*cdf0e10cSrcweir 				{
1048*cdf0e10cSrcweir 					rtl_arena_segment_type * remainder = 0;
1049*cdf0e10cSrcweir 					rtl_arena_segment_get (arena, &remainder);
1050*cdf0e10cSrcweir 					if (remainder != 0)
1051*cdf0e10cSrcweir 					{
1052*cdf0e10cSrcweir 						segment->m_size = size;
1053*cdf0e10cSrcweir 
1054*cdf0e10cSrcweir 						remainder->m_addr = segment->m_addr + segment->m_size;
1055*cdf0e10cSrcweir 						remainder->m_size = oversize;
1056*cdf0e10cSrcweir 						remainder->m_type = RTL_ARENA_SEGMENT_TYPE_FREE;
1057*cdf0e10cSrcweir 						QUEUE_INSERT_HEAD_NAMED(segment, remainder, s);
1058*cdf0e10cSrcweir 
1059*cdf0e10cSrcweir 						rtl_arena_freelist_insert (arena, remainder);
1060*cdf0e10cSrcweir 					}
1061*cdf0e10cSrcweir 				}
1062*cdf0e10cSrcweir 
1063*cdf0e10cSrcweir 				rtl_arena_hash_insert (arena, segment);
1064*cdf0e10cSrcweir 
1065*cdf0e10cSrcweir                 /* DEBUG ONLY: mark allocated, undefined */
1066*cdf0e10cSrcweir 				OSL_DEBUG_ONLY(memset((void*)(segment->m_addr), 0x77777777, segment->m_size));
1067*cdf0e10cSrcweir 				VALGRIND_MEMPOOL_ALLOC(arena, segment->m_addr, segment->m_size);
1068*cdf0e10cSrcweir 
1069*cdf0e10cSrcweir 				(*pSize) = segment->m_size;
1070*cdf0e10cSrcweir 				addr = (void*)(segment->m_addr);
1071*cdf0e10cSrcweir 			}
1072*cdf0e10cSrcweir 			RTL_MEMORY_LOCK_RELEASE(&(arena->m_lock));
1073*cdf0e10cSrcweir 		}
1074*cdf0e10cSrcweir 		else if (size > 0)
1075*cdf0e10cSrcweir 		{
1076*cdf0e10cSrcweir 			/* allocate from quantum cache(s) */
1077*cdf0e10cSrcweir 			int index = (size >> arena->m_quantum_shift) - 1;
1078*cdf0e10cSrcweir 			OSL_ASSERT (arena->m_qcache_ptr[index] != 0);
1079*cdf0e10cSrcweir 
1080*cdf0e10cSrcweir 			addr = rtl_cache_alloc (arena->m_qcache_ptr[index]);
1081*cdf0e10cSrcweir 			if (addr != 0)
1082*cdf0e10cSrcweir 				(*pSize) = size;
1083*cdf0e10cSrcweir 		}
1084*cdf0e10cSrcweir 	}
1085*cdf0e10cSrcweir 	return (addr);
1086*cdf0e10cSrcweir }
1087*cdf0e10cSrcweir 
1088*cdf0e10cSrcweir /** rtl_arena_free()
1089*cdf0e10cSrcweir  */
1090*cdf0e10cSrcweir void
1091*cdf0e10cSrcweir SAL_CALL rtl_arena_free (
1092*cdf0e10cSrcweir 	rtl_arena_type * arena,
1093*cdf0e10cSrcweir 	void *           addr,
1094*cdf0e10cSrcweir 	sal_Size         size
1095*cdf0e10cSrcweir ) SAL_THROW_EXTERN_C()
1096*cdf0e10cSrcweir {
1097*cdf0e10cSrcweir 	if (arena != 0)
1098*cdf0e10cSrcweir 	{
1099*cdf0e10cSrcweir 		size = RTL_MEMORY_ALIGN(size, arena->m_quantum);
1100*cdf0e10cSrcweir 		if (size > arena->m_qcache_max)
1101*cdf0e10cSrcweir 		{
1102*cdf0e10cSrcweir 			/* free to segment list */
1103*cdf0e10cSrcweir 			rtl_arena_segment_type * segment;
1104*cdf0e10cSrcweir 
1105*cdf0e10cSrcweir 			RTL_MEMORY_LOCK_ACQUIRE(&(arena->m_lock));
1106*cdf0e10cSrcweir 
1107*cdf0e10cSrcweir 			segment = rtl_arena_hash_remove (arena, (sal_uIntPtr)(addr), size);
1108*cdf0e10cSrcweir 			if (segment != 0)
1109*cdf0e10cSrcweir 			{
1110*cdf0e10cSrcweir 				rtl_arena_segment_type *next, *prev;
1111*cdf0e10cSrcweir 
1112*cdf0e10cSrcweir 				/* DEBUG ONLY: mark unallocated, undefined */
1113*cdf0e10cSrcweir 				VALGRIND_MEMPOOL_FREE(arena, segment->m_addr);
1114*cdf0e10cSrcweir                 /* OSL_DEBUG_ONLY() */ VALGRIND_MAKE_MEM_UNDEFINED(segment->m_addr, segment->m_size);
1115*cdf0e10cSrcweir                 OSL_DEBUG_ONLY(memset((void*)(segment->m_addr), 0x33333333, segment->m_size));
1116*cdf0e10cSrcweir 
1117*cdf0e10cSrcweir 				/* coalesce w/ adjacent free segment(s) */
1118*cdf0e10cSrcweir 				rtl_arena_segment_coalesce (arena, segment);
1119*cdf0e10cSrcweir 
1120*cdf0e10cSrcweir 				/* determine (new) next and prev segment */
1121*cdf0e10cSrcweir 				next = segment->m_snext, prev = segment->m_sprev;
1122*cdf0e10cSrcweir 
1123*cdf0e10cSrcweir 				/* entire span free when prev is a span, and next is either a span or a list head */
1124*cdf0e10cSrcweir 				if (((prev->m_type == RTL_ARENA_SEGMENT_TYPE_SPAN)) &&
1125*cdf0e10cSrcweir 					((next->m_type == RTL_ARENA_SEGMENT_TYPE_SPAN)  ||
1126*cdf0e10cSrcweir 					 (next->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD))    )
1127*cdf0e10cSrcweir 				{
1128*cdf0e10cSrcweir 					OSL_ASSERT((prev->m_addr == segment->m_addr) &&
1129*cdf0e10cSrcweir 							   (prev->m_size == segment->m_size)    );
1130*cdf0e10cSrcweir 
1131*cdf0e10cSrcweir 					if (arena->m_source_free)
1132*cdf0e10cSrcweir 					{
1133*cdf0e10cSrcweir 						addr = (void*)(prev->m_addr);
1134*cdf0e10cSrcweir 						size = prev->m_size;
1135*cdf0e10cSrcweir 
1136*cdf0e10cSrcweir 						/* remove from segment list */
1137*cdf0e10cSrcweir 						QUEUE_REMOVE_NAMED(segment, s);
1138*cdf0e10cSrcweir 
1139*cdf0e10cSrcweir 						/* release segment descriptor */
1140*cdf0e10cSrcweir 						rtl_arena_segment_put (arena, &segment);
1141*cdf0e10cSrcweir 
1142*cdf0e10cSrcweir 						/* remove from segment list */
1143*cdf0e10cSrcweir 						QUEUE_REMOVE_NAMED(prev, s);
1144*cdf0e10cSrcweir 
1145*cdf0e10cSrcweir 						/* release (span) segment descriptor */
1146*cdf0e10cSrcweir 						rtl_arena_segment_put (arena, &prev);
1147*cdf0e10cSrcweir 
1148*cdf0e10cSrcweir 						/* update stats, return span to source arena */
1149*cdf0e10cSrcweir 						arena->m_stats.m_mem_total -= size;
1150*cdf0e10cSrcweir 						RTL_MEMORY_LOCK_RELEASE(&(arena->m_lock));
1151*cdf0e10cSrcweir 
1152*cdf0e10cSrcweir 						(arena->m_source_free)(arena->m_source_arena, addr, size);
1153*cdf0e10cSrcweir 						return;
1154*cdf0e10cSrcweir 					}
1155*cdf0e10cSrcweir 				}
1156*cdf0e10cSrcweir 
1157*cdf0e10cSrcweir 				/* insert onto freelist */
1158*cdf0e10cSrcweir 				rtl_arena_freelist_insert (arena, segment);
1159*cdf0e10cSrcweir 			}
1160*cdf0e10cSrcweir 
1161*cdf0e10cSrcweir 			RTL_MEMORY_LOCK_RELEASE(&(arena->m_lock));
1162*cdf0e10cSrcweir 		}
1163*cdf0e10cSrcweir 		else if (size > 0)
1164*cdf0e10cSrcweir 		{
1165*cdf0e10cSrcweir 			/* free to quantum cache(s) */
1166*cdf0e10cSrcweir 			int index = (size >> arena->m_quantum_shift) - 1;
1167*cdf0e10cSrcweir 			OSL_ASSERT (arena->m_qcache_ptr[index] != 0);
1168*cdf0e10cSrcweir 
1169*cdf0e10cSrcweir 			rtl_cache_free (arena->m_qcache_ptr[index], addr);
1170*cdf0e10cSrcweir 		}
1171*cdf0e10cSrcweir 	}
1172*cdf0e10cSrcweir }
1173*cdf0e10cSrcweir 
1174*cdf0e10cSrcweir /* ================================================================= *
1175*cdf0e10cSrcweir  *
1176*cdf0e10cSrcweir  * machdep internals.
1177*cdf0e10cSrcweir  *
1178*cdf0e10cSrcweir  * ================================================================= */
1179*cdf0e10cSrcweir 
1180*cdf0e10cSrcweir #if defined(SAL_UNX)
1181*cdf0e10cSrcweir #include <sys/mman.h>
1182*cdf0e10cSrcweir #elif defined(SAL_W32) || defined(SAL_OS2)
1183*cdf0e10cSrcweir #define MAP_FAILED 0
1184*cdf0e10cSrcweir #endif /* SAL_UNX || SAL_W32 */
1185*cdf0e10cSrcweir 
1186*cdf0e10cSrcweir /** rtl_machdep_alloc()
1187*cdf0e10cSrcweir  */
1188*cdf0e10cSrcweir static void *
1189*cdf0e10cSrcweir SAL_CALL rtl_machdep_alloc (
1190*cdf0e10cSrcweir 	rtl_arena_type * pArena,
1191*cdf0e10cSrcweir 	sal_Size *       pSize
1192*cdf0e10cSrcweir )
1193*cdf0e10cSrcweir {
1194*cdf0e10cSrcweir 	void *   addr;
1195*cdf0e10cSrcweir 	sal_Size size = (*pSize);
1196*cdf0e10cSrcweir 
1197*cdf0e10cSrcweir 	OSL_PRECOND(pArena == gp_machdep_arena, "rtl_machdep_alloc(): invalid argument");
1198*cdf0e10cSrcweir 
1199*cdf0e10cSrcweir #if defined(SOLARIS) && defined(SPARC)
1200*cdf0e10cSrcweir 	/* see @ mmap(2) man pages */
1201*cdf0e10cSrcweir 	size += (pArena->m_quantum + pArena->m_quantum); /* "red-zone" pages */
1202*cdf0e10cSrcweir 	if (size > (4 << 20))
1203*cdf0e10cSrcweir 		size = RTL_MEMORY_P2ROUNDUP(size, (4 << 20));
1204*cdf0e10cSrcweir 	else if (size > (512 << 10))
1205*cdf0e10cSrcweir 		size = RTL_MEMORY_P2ROUNDUP(size, (512 << 10));
1206*cdf0e10cSrcweir 	else
1207*cdf0e10cSrcweir 		size = RTL_MEMORY_P2ROUNDUP(size, (64 << 10));
1208*cdf0e10cSrcweir 	size -= (pArena->m_quantum + pArena->m_quantum); /* "red-zone" pages */
1209*cdf0e10cSrcweir #else
1210*cdf0e10cSrcweir 	/* default allocation granularity */
1211*cdf0e10cSrcweir 	size = RTL_MEMORY_P2ROUNDUP(size, SAL_MAX(pArena->m_quantum, 64 << 10));
1212*cdf0e10cSrcweir #endif
1213*cdf0e10cSrcweir 
1214*cdf0e10cSrcweir #if defined(SAL_UNX)
1215*cdf0e10cSrcweir 	addr = mmap (NULL, (size_t)(size), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
1216*cdf0e10cSrcweir #elif defined(SAL_W32)
1217*cdf0e10cSrcweir 	addr = VirtualAlloc (NULL, (SIZE_T)(size), MEM_COMMIT, PAGE_READWRITE);
1218*cdf0e10cSrcweir #elif defined(SAL_OS2)
1219*cdf0e10cSrcweir 	{
1220*cdf0e10cSrcweir 	APIRET rc;
1221*cdf0e10cSrcweir 	addr = 0;
1222*cdf0e10cSrcweir 	// Use DosAlloc* to get a 4KB page aligned address.
1223*cdf0e10cSrcweir 	rc = DosAllocMem( &addr, size, PAG_COMMIT | PAG_READ | PAG_WRITE | OBJ_ANY);
1224*cdf0e10cSrcweir 	if (rc) {
1225*cdf0e10cSrcweir 		fprintf( stderr, "sal3::DosAllocMem failed rc=%d\n", rc);
1226*cdf0e10cSrcweir 		addr = 0;
1227*cdf0e10cSrcweir 	}
1228*cdf0e10cSrcweir 	}
1229*cdf0e10cSrcweir #endif /* (SAL_UNX || SAL_W32 || SAL_OS2) */
1230*cdf0e10cSrcweir 
1231*cdf0e10cSrcweir 	if (addr != MAP_FAILED)
1232*cdf0e10cSrcweir 	{
1233*cdf0e10cSrcweir 		pArena->m_stats.m_alloc += 1;
1234*cdf0e10cSrcweir 		pArena->m_stats.m_mem_total += size;
1235*cdf0e10cSrcweir 		pArena->m_stats.m_mem_alloc += size;
1236*cdf0e10cSrcweir 
1237*cdf0e10cSrcweir 		(*pSize) = size;
1238*cdf0e10cSrcweir 		return (addr);
1239*cdf0e10cSrcweir 	}
1240*cdf0e10cSrcweir 	return (NULL);
1241*cdf0e10cSrcweir }
1242*cdf0e10cSrcweir 
1243*cdf0e10cSrcweir /** rtl_machdep_free()
1244*cdf0e10cSrcweir  */
1245*cdf0e10cSrcweir static void
1246*cdf0e10cSrcweir SAL_CALL rtl_machdep_free (
1247*cdf0e10cSrcweir 	rtl_arena_type * pArena,
1248*cdf0e10cSrcweir 	void *           pAddr,
1249*cdf0e10cSrcweir 	sal_Size         nSize
1250*cdf0e10cSrcweir )
1251*cdf0e10cSrcweir {
1252*cdf0e10cSrcweir 	OSL_PRECOND(pArena == gp_machdep_arena, "rtl_machdep_free(): invalid argument");
1253*cdf0e10cSrcweir 
1254*cdf0e10cSrcweir 	pArena->m_stats.m_free += 1;
1255*cdf0e10cSrcweir 	pArena->m_stats.m_mem_total -= nSize;
1256*cdf0e10cSrcweir 	pArena->m_stats.m_mem_alloc -= nSize;
1257*cdf0e10cSrcweir 
1258*cdf0e10cSrcweir #if defined(SAL_UNX)
1259*cdf0e10cSrcweir 	(void) munmap(pAddr, nSize);
1260*cdf0e10cSrcweir #elif defined(SAL_W32)
1261*cdf0e10cSrcweir 	(void) VirtualFree ((LPVOID)(pAddr), (SIZE_T)(0), MEM_RELEASE);
1262*cdf0e10cSrcweir #elif defined(SAL_OS2)
1263*cdf0e10cSrcweir 	(void) DosFreeMem( pAddr);
1264*cdf0e10cSrcweir #endif /* (SAL_UNX || SAL_W32) */
1265*cdf0e10cSrcweir }
1266*cdf0e10cSrcweir 
1267*cdf0e10cSrcweir /** rtl_machdep_pagesize()
1268*cdf0e10cSrcweir  */
1269*cdf0e10cSrcweir static sal_Size
1270*cdf0e10cSrcweir rtl_machdep_pagesize (void)
1271*cdf0e10cSrcweir {
1272*cdf0e10cSrcweir #if defined(SAL_UNX)
1273*cdf0e10cSrcweir #if defined(FREEBSD) || defined(NETBSD)
1274*cdf0e10cSrcweir 	return ((sal_Size)getpagesize());
1275*cdf0e10cSrcweir #else  /* POSIX */
1276*cdf0e10cSrcweir 	return ((sal_Size)sysconf(_SC_PAGESIZE));
1277*cdf0e10cSrcweir #endif /* xBSD || POSIX */
1278*cdf0e10cSrcweir #elif defined(SAL_W32)
1279*cdf0e10cSrcweir 	SYSTEM_INFO info;
1280*cdf0e10cSrcweir 	GetSystemInfo (&info);
1281*cdf0e10cSrcweir 	return ((sal_Size)(info.dwPageSize));
1282*cdf0e10cSrcweir #elif defined(SAL_OS2)
1283*cdf0e10cSrcweir 	ULONG ulPageSize;
1284*cdf0e10cSrcweir 	DosQuerySysInfo(QSV_PAGE_SIZE, QSV_PAGE_SIZE, &ulPageSize, sizeof(ULONG));
1285*cdf0e10cSrcweir 	return ((sal_Size)ulPageSize);
1286*cdf0e10cSrcweir #endif /* (SAL_UNX || SAL_W32) */
1287*cdf0e10cSrcweir }
1288*cdf0e10cSrcweir 
1289*cdf0e10cSrcweir /* ================================================================= *
1290*cdf0e10cSrcweir  *
1291*cdf0e10cSrcweir  * arena initialization.
1292*cdf0e10cSrcweir  *
1293*cdf0e10cSrcweir  * ================================================================= */
1294*cdf0e10cSrcweir 
1295*cdf0e10cSrcweir static void
1296*cdf0e10cSrcweir rtl_arena_once_init (void)
1297*cdf0e10cSrcweir {
1298*cdf0e10cSrcweir 	{
1299*cdf0e10cSrcweir 		/* list of arenas */
1300*cdf0e10cSrcweir 		RTL_MEMORY_LOCK_INIT(&(g_arena_list.m_lock));
1301*cdf0e10cSrcweir 		rtl_arena_constructor (&(g_arena_list.m_arena_head));
1302*cdf0e10cSrcweir 	}
1303*cdf0e10cSrcweir 	{
1304*cdf0e10cSrcweir 		/* machdep (pseudo) arena */
1305*cdf0e10cSrcweir 		static rtl_arena_type g_machdep_arena;
1306*cdf0e10cSrcweir 
1307*cdf0e10cSrcweir 		OSL_ASSERT(gp_machdep_arena == 0);
1308*cdf0e10cSrcweir 		VALGRIND_CREATE_MEMPOOL(&g_machdep_arena, 0, 0);
1309*cdf0e10cSrcweir 		rtl_arena_constructor (&g_machdep_arena);
1310*cdf0e10cSrcweir 
1311*cdf0e10cSrcweir 		gp_machdep_arena = rtl_arena_activate (
1312*cdf0e10cSrcweir 			&g_machdep_arena,
1313*cdf0e10cSrcweir 			"rtl_machdep_arena",
1314*cdf0e10cSrcweir 			rtl_machdep_pagesize(),
1315*cdf0e10cSrcweir 			0,       /* no quantum caching */
1316*cdf0e10cSrcweir 			0, 0, 0  /* no source */
1317*cdf0e10cSrcweir 		);
1318*cdf0e10cSrcweir 		OSL_ASSERT(gp_machdep_arena != 0);
1319*cdf0e10cSrcweir 	}
1320*cdf0e10cSrcweir 	{
1321*cdf0e10cSrcweir 		/* default arena */
1322*cdf0e10cSrcweir 		static rtl_arena_type g_default_arena;
1323*cdf0e10cSrcweir 
1324*cdf0e10cSrcweir 		OSL_ASSERT(gp_default_arena == 0);
1325*cdf0e10cSrcweir 		VALGRIND_CREATE_MEMPOOL(&g_default_arena, 0, 0);
1326*cdf0e10cSrcweir 		rtl_arena_constructor (&g_default_arena);
1327*cdf0e10cSrcweir 
1328*cdf0e10cSrcweir 		gp_default_arena = rtl_arena_activate (
1329*cdf0e10cSrcweir 			&g_default_arena,
1330*cdf0e10cSrcweir 			"rtl_default_arena",
1331*cdf0e10cSrcweir 			rtl_machdep_pagesize(),
1332*cdf0e10cSrcweir 			0,                 /* no quantum caching */
1333*cdf0e10cSrcweir 			gp_machdep_arena,  /* source */
1334*cdf0e10cSrcweir 			rtl_machdep_alloc,
1335*cdf0e10cSrcweir 			rtl_machdep_free
1336*cdf0e10cSrcweir 		);
1337*cdf0e10cSrcweir 		OSL_ASSERT(gp_default_arena != 0);
1338*cdf0e10cSrcweir 	}
1339*cdf0e10cSrcweir 	{
1340*cdf0e10cSrcweir 		/* arena internal arena */
1341*cdf0e10cSrcweir 		static rtl_arena_type g_arena_arena;
1342*cdf0e10cSrcweir 
1343*cdf0e10cSrcweir 		OSL_ASSERT(gp_arena_arena == 0);
1344*cdf0e10cSrcweir 		VALGRIND_CREATE_MEMPOOL(&g_arena_arena, 0, 0);
1345*cdf0e10cSrcweir 		rtl_arena_constructor (&g_arena_arena);
1346*cdf0e10cSrcweir 
1347*cdf0e10cSrcweir 		gp_arena_arena = rtl_arena_activate (
1348*cdf0e10cSrcweir 			&g_arena_arena,
1349*cdf0e10cSrcweir 			"rtl_arena_internal_arena",
1350*cdf0e10cSrcweir 			64,                /* quantum */
1351*cdf0e10cSrcweir 			0,                 /* no quantum caching */
1352*cdf0e10cSrcweir 			gp_default_arena,  /* source */
1353*cdf0e10cSrcweir 			rtl_arena_alloc,
1354*cdf0e10cSrcweir 			rtl_arena_free
1355*cdf0e10cSrcweir 		);
1356*cdf0e10cSrcweir 		OSL_ASSERT(gp_arena_arena != 0);
1357*cdf0e10cSrcweir 	}
1358*cdf0e10cSrcweir }
1359*cdf0e10cSrcweir 
1360*cdf0e10cSrcweir static int
1361*cdf0e10cSrcweir rtl_arena_init (void)
1362*cdf0e10cSrcweir {
1363*cdf0e10cSrcweir 	static sal_once_type g_once = SAL_ONCE_INIT;
1364*cdf0e10cSrcweir 	SAL_ONCE(&g_once, rtl_arena_once_init);
1365*cdf0e10cSrcweir 	return (gp_arena_arena != 0);
1366*cdf0e10cSrcweir }
1367*cdf0e10cSrcweir 
1368*cdf0e10cSrcweir /* ================================================================= */
1369*cdf0e10cSrcweir 
1370*cdf0e10cSrcweir /*
1371*cdf0e10cSrcweir   Issue http://udk.openoffice.org/issues/show_bug.cgi?id=92388
1372*cdf0e10cSrcweir 
1373*cdf0e10cSrcweir   Mac OS X does not seem to support "__cxa__atexit", thus leading
1374*cdf0e10cSrcweir   to the situation that "__attribute__((destructor))__" functions
1375*cdf0e10cSrcweir   (in particular "rtl_{memory|cache|arena}_fini") become called
1376*cdf0e10cSrcweir   _before_ global C++ object d'tors.
1377*cdf0e10cSrcweir 
1378*cdf0e10cSrcweir   Delegated the call to "rtl_arena_fini()" into a dummy C++ object,
1379*cdf0e10cSrcweir   see alloc_fini.cxx .
1380*cdf0e10cSrcweir */
1381*cdf0e10cSrcweir #if defined(__GNUC__) && !defined(MACOSX)
1382*cdf0e10cSrcweir static void rtl_arena_fini (void) __attribute__((destructor));
1383*cdf0e10cSrcweir #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
1384*cdf0e10cSrcweir #pragma fini(rtl_arena_fini)
1385*cdf0e10cSrcweir static void rtl_arena_fini (void);
1386*cdf0e10cSrcweir #endif /* __GNUC__ || __SUNPRO_C */
1387*cdf0e10cSrcweir 
1388*cdf0e10cSrcweir void
1389*cdf0e10cSrcweir rtl_arena_fini (void)
1390*cdf0e10cSrcweir {
1391*cdf0e10cSrcweir 	if (gp_arena_arena != 0)
1392*cdf0e10cSrcweir 	{
1393*cdf0e10cSrcweir 		rtl_arena_type * arena, * head;
1394*cdf0e10cSrcweir 
1395*cdf0e10cSrcweir 		RTL_MEMORY_LOCK_ACQUIRE(&(g_arena_list.m_lock));
1396*cdf0e10cSrcweir 		head = &(g_arena_list.m_arena_head);
1397*cdf0e10cSrcweir 
1398*cdf0e10cSrcweir 		for (arena = head->m_arena_next; arena != head; arena = arena->m_arena_next)
1399*cdf0e10cSrcweir 		{
1400*cdf0e10cSrcweir 			OSL_TRACE(
1401*cdf0e10cSrcweir 				"rtl_arena_fini(\"%s\"): "
1402*cdf0e10cSrcweir 				"allocs: %"PRIu64", frees: %"PRIu64"; total: %lu, used: %lu",
1403*cdf0e10cSrcweir 				arena->m_name,
1404*cdf0e10cSrcweir 				arena->m_stats.m_alloc, arena->m_stats.m_free,
1405*cdf0e10cSrcweir 				arena->m_stats.m_mem_total, arena->m_stats.m_mem_alloc
1406*cdf0e10cSrcweir 			);
1407*cdf0e10cSrcweir 		}
1408*cdf0e10cSrcweir 		RTL_MEMORY_LOCK_RELEASE(&(g_arena_list.m_lock));
1409*cdf0e10cSrcweir 	}
1410*cdf0e10cSrcweir }
1411*cdf0e10cSrcweir 
1412*cdf0e10cSrcweir /* ================================================================= */
1413