xref: /trunk/main/sal/rtl/source/alloc_global.c (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include "rtl/alloc.h"
29 #include "alloc_impl.h"
30 
31 #ifndef INCLUDED_STRING_H
32 #include <string.h>
33 #define INCLUDED_STRING_H
34 #endif
35 
36 #if !defined(FORCE_SYSALLOC)
37 
38 /* ================================================================= *
39  *
40  * custom allocator includes.
41  *
42  * ================================================================= */
43 
44 #ifndef INCLUDED_STDIO_H
45 #include <stdio.h>
46 #define INCLUDED_STDIO_H
47 #endif
48 #include "internal/once.h"
49 #include "sal/macros.h"
50 #include "osl/diagnose.h"
51 
52 /* ================================================================= *
53  *
54  * custom allocator internals.
55  *
56  * ================================================================= */
57 
58 static const sal_Size g_alloc_sizes[] =
59 {
60     /* powers of 2**(1/4) */
61     4 *    4,           6 *    4,
62     4 *    8, 5 *    8, 6 *    8, 7 *    8,
63     4 *   16, 5 *   16, 6 *   16, 7 *   16,
64     4 *   32, 5 *   32, 6 *   32, 7 *   32,
65     4 *   64, 5 *   64, 6 *   64, 7 *   64,
66     4 *  128, 5 *  128, 6 *  128, 7 *  128,
67     4 *  256, 5 *  256, 6 *  256, 7 *  256,
68     4 *  512, 5 *  512, 6 *  512, 7 *  512,
69     4 * 1024, 5 * 1024, 6 * 1024, 7 * 1024,
70     4 * 2048, 5 * 2048, 6 * 2048, 7 * 2048,
71     4 * 4096
72 };
73 
74 #define RTL_MEMORY_CACHED_LIMIT 4 * 4096
75 #define RTL_MEMORY_CACHED_SIZES (sizeof(g_alloc_sizes) / sizeof(g_alloc_sizes[0]))
76 
77 static rtl_cache_type * g_alloc_caches[RTL_MEMORY_CACHED_SIZES] =
78 {
79     0,
80 };
81 
82 #define RTL_MEMALIGN       8
83 #define RTL_MEMALIGN_SHIFT 3
84 
85 static rtl_cache_type * g_alloc_table[RTL_MEMORY_CACHED_LIMIT >> RTL_MEMALIGN_SHIFT] =
86 {
87     0,
88 };
89 
90 static rtl_arena_type * gp_alloc_arena = 0;
91 
92 /* ================================================================= *
93  *
94  * custom allocator initialization / finalization.
95  *
96  * ================================================================= */
97 
98 static void
99 rtl_memory_once_init (void)
100 {
101     {
102         /* global memory arena */
103         OSL_ASSERT(gp_alloc_arena == 0);
104 
105         gp_alloc_arena = rtl_arena_create (
106             "rtl_alloc_arena",
107             2048,     /* quantum */
108             0,        /* w/o quantum caching */
109             0,        /* default source */
110             rtl_arena_alloc,
111             rtl_arena_free,
112             0         /* flags */
113         );
114         OSL_ASSERT(gp_alloc_arena != 0);
115     }
116     {
117         sal_Size size;
118         int i, n = RTL_MEMORY_CACHED_SIZES;
119 
120         for (i = 0; i < n; i++)
121         {
122             char name[RTL_CACHE_NAME_LENGTH + 1];
123             (void) snprintf (name, sizeof(name), "rtl_alloc_%lu", g_alloc_sizes[i]);
124             g_alloc_caches[i] = rtl_cache_create (name, g_alloc_sizes[i], 0, NULL, NULL, NULL, NULL, NULL, 0);
125         }
126 
127         size = RTL_MEMALIGN;
128         for (i = 0; i < n; i++)
129         {
130             while (size <= g_alloc_sizes[i])
131             {
132                 g_alloc_table[(size - 1) >> RTL_MEMALIGN_SHIFT] = g_alloc_caches[i];
133                 size += RTL_MEMALIGN;
134             }
135         }
136     }
137 }
138 
139 static int
140 rtl_memory_init (void)
141 {
142     static sal_once_type g_once = SAL_ONCE_INIT;
143     SAL_ONCE(&g_once, rtl_memory_once_init);
144     return (gp_alloc_arena != 0);
145 }
146 
147 /* ================================================================= */
148 
149 /*
150   Issue http://udk.openoffice.org/issues/show_bug.cgi?id=92388
151 
152   Mac OS X does not seem to support "__cxa__atexit", thus leading
153   to the situation that "__attribute__((destructor))__" functions
154   (in particular "rtl_{memory|cache|arena}_fini") become called
155   _before_ global C++ object d'tors.
156 
157   Delegated the call to "rtl_memory_fini()" into a dummy C++ object,
158   see alloc_fini.cxx .
159 */
160 #if defined(__GNUC__) && !defined(MACOSX)
161 static void rtl_memory_fini (void) __attribute__((destructor));
162 #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
163 #pragma fini(rtl_memory_fini)
164 static void rtl_memory_fini (void);
165 #endif /* __GNUC__ || __SUNPRO_C */
166 
167 void
168 rtl_memory_fini (void)
169 {
170     int i, n;
171 
172     /* clear g_alloc_table */
173     memset (g_alloc_table, 0, sizeof(g_alloc_table));
174 
175     /* cleanup g_alloc_caches */
176     for (i = 0, n = RTL_MEMORY_CACHED_SIZES; i < n; i++)
177     {
178         if (g_alloc_caches[i] != 0)
179         {
180             rtl_cache_destroy (g_alloc_caches[i]);
181             g_alloc_caches[i] = 0;
182         }
183     }
184 
185     /* cleanup gp_alloc_arena */
186     if (gp_alloc_arena != 0)
187     {
188         rtl_arena_destroy (gp_alloc_arena);
189         gp_alloc_arena = 0;
190     }
191 }
192 
193 /* ================================================================= *
194  *
195  * custom allocator implemenation.
196  *
197  * ================================================================= */
198 
199 void *
200 SAL_CALL rtl_allocateMemory (sal_Size n) SAL_THROW_EXTERN_C()
201 {
202     void * p = 0;
203     if (n > 0)
204     {
205         char *     addr;
206         sal_Size   size = RTL_MEMORY_ALIGN(n + RTL_MEMALIGN, RTL_MEMALIGN);
207 
208         OSL_ASSERT(RTL_MEMALIGN >= sizeof(sal_Size));
209         if (n >= SAL_MAX_SIZE - (RTL_MEMALIGN + RTL_MEMALIGN - 1))
210         {
211             /* requested size too large for roundup alignment */
212             return 0;
213         }
214 
215 try_alloc:
216         if (size <= RTL_MEMORY_CACHED_LIMIT)
217             addr = (char*)rtl_cache_alloc(g_alloc_table[(size - 1) >> RTL_MEMALIGN_SHIFT]);
218         else
219             addr = (char*)rtl_arena_alloc (gp_alloc_arena, &size);
220 
221         if (addr != 0)
222         {
223             ((sal_Size*)(addr))[0] = size;
224             p = addr + RTL_MEMALIGN;
225         }
226         else if (gp_alloc_arena == 0)
227         {
228             if (rtl_memory_init())
229             {
230                 /* try again */
231                 goto try_alloc;
232             }
233         }
234     }
235     return (p);
236 }
237 
238 /* ================================================================= */
239 
240 void SAL_CALL rtl_freeMemory (void * p) SAL_THROW_EXTERN_C()
241 {
242     if (p != 0)
243     {
244         char *   addr = (char*)(p) - RTL_MEMALIGN;
245         sal_Size size = ((sal_Size*)(addr))[0];
246 
247         if (size <= RTL_MEMORY_CACHED_LIMIT)
248             rtl_cache_free(g_alloc_table[(size - 1) >> RTL_MEMALIGN_SHIFT], addr);
249         else
250             rtl_arena_free (gp_alloc_arena, addr, size);
251     }
252 }
253 
254 /* ================================================================= */
255 
256 void * SAL_CALL rtl_reallocateMemory (void * p, sal_Size n) SAL_THROW_EXTERN_C()
257 {
258     if (n > 0)
259     {
260         if (p != 0)
261         {
262             void *   p_old = p;
263             sal_Size n_old = ((sal_Size*)( (char*)(p) - RTL_MEMALIGN  ))[0] - RTL_MEMALIGN;
264 
265             p = rtl_allocateMemory (n);
266             if (p != 0)
267             {
268                 memcpy (p, p_old, SAL_MIN(n, n_old));
269                 rtl_freeMemory (p_old);
270             }
271         }
272         else
273         {
274             p = rtl_allocateMemory (n);
275         }
276     }
277     else if (p != 0)
278     {
279         rtl_freeMemory (p), p = 0;
280     }
281     return (p);
282 }
283 
284 #else  /* FORCE_SYSALLOC */
285 
286 /* ================================================================= *
287  *
288  * system allocator includes.
289  *
290  * ================================================================= */
291 
292 #ifndef INCLUDED_STDLIB_H
293 #include <stdlib.h>
294 #define INCLUDED_STDLIB_H
295 #endif
296 
297 /* ================================================================= *
298  *
299  * system allocator implemenation.
300  *
301  * ================================================================= */
302 
303 void * SAL_CALL rtl_allocateMemory (sal_Size n)
304 {
305     return malloc (n);
306 }
307 
308 /* ================================================================= */
309 
310 void SAL_CALL rtl_freeMemory (void * p)
311 {
312     free (p);
313 }
314 
315 /* ================================================================= */
316 
317 void * SAL_CALL rtl_reallocateMemory (void * p, sal_Size n)
318 {
319     return realloc (p, n);
320 }
321 
322 /* ================================================================= */
323 
324 void
325 rtl_memory_fini (void)
326 {
327     /* nothing to do */
328 }
329 
330 #endif /* FORCE_SYSALLOC */
331 
332 /* ================================================================= *
333  *
334  * rtl_(allocate|free)ZeroMemory() implemenation.
335  *
336  * ================================================================= */
337 
338 void * SAL_CALL rtl_allocateZeroMemory (sal_Size n) SAL_THROW_EXTERN_C()
339 {
340     void * p = rtl_allocateMemory (n);
341     if (p != 0)
342         memset (p, 0, n);
343     return (p);
344 }
345 
346 /* ================================================================= */
347 
348 void SAL_CALL rtl_freeZeroMemory (void * p, sal_Size n) SAL_THROW_EXTERN_C()
349 {
350     if (p != 0)
351     {
352         memset (p, 0, n);
353         rtl_freeMemory (p);
354     }
355 }
356 
357 /* ================================================================= */
358