sl_malloc.c revision 1.1.1.2 1 1.1.1.2 lukem /* $NetBSD: sl_malloc.c,v 1.1.1.2 2010/03/08 02:14:20 lukem Exp $ */
2 1.1.1.2 lukem
3 1.1 lukem /* sl_malloc.c - malloc routines using a per-thread slab */
4 1.1.1.2 lukem /* OpenLDAP: pkg/ldap/servers/slapd/sl_malloc.c,v 1.39.2.10 2009/11/18 01:22:22 quanah Exp */
5 1.1 lukem /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6 1.1 lukem *
7 1.1.1.2 lukem * Copyright 2003-2009 The OpenLDAP Foundation.
8 1.1 lukem * All rights reserved.
9 1.1 lukem *
10 1.1 lukem * Redistribution and use in source and binary forms, with or without
11 1.1 lukem * modification, are permitted only as authorized by the OpenLDAP
12 1.1 lukem * Public License.
13 1.1 lukem *
14 1.1 lukem * A copy of this license is available in the file LICENSE in the
15 1.1 lukem * top-level directory of the distribution or, alternatively, at
16 1.1 lukem * <http://www.OpenLDAP.org/license.html>.
17 1.1 lukem */
18 1.1 lukem
19 1.1 lukem #include "portable.h"
20 1.1 lukem
21 1.1 lukem #include <stdio.h>
22 1.1 lukem #include <ac/string.h>
23 1.1 lukem
24 1.1 lukem #include "slap.h"
25 1.1 lukem
26 1.1 lukem static struct slab_object * slap_replenish_sopool(struct slab_heap* sh);
27 1.1 lukem #ifdef SLAPD_UNUSED
28 1.1 lukem static void print_slheap(int level, void *ctx);
29 1.1 lukem #endif
30 1.1 lukem
31 1.1 lukem void
32 1.1 lukem slap_sl_mem_destroy(
33 1.1 lukem void *key,
34 1.1 lukem void *data
35 1.1 lukem )
36 1.1 lukem {
37 1.1 lukem struct slab_heap *sh = data;
38 1.1 lukem int pad = 2*sizeof(int)-1, pad_shift;
39 1.1 lukem int order_start = -1, i;
40 1.1 lukem struct slab_object *so;
41 1.1 lukem
42 1.1 lukem if (sh->sh_stack) {
43 1.1 lukem ber_memfree_x(sh->sh_base, NULL);
44 1.1 lukem ber_memfree_x(sh, NULL);
45 1.1 lukem } else {
46 1.1 lukem pad_shift = pad - 1;
47 1.1 lukem do {
48 1.1 lukem order_start++;
49 1.1 lukem } while (pad_shift >>= 1);
50 1.1 lukem
51 1.1 lukem for (i = 0; i <= sh->sh_maxorder - order_start; i++) {
52 1.1 lukem so = LDAP_LIST_FIRST(&sh->sh_free[i]);
53 1.1 lukem while (so) {
54 1.1 lukem struct slab_object *so_tmp = so;
55 1.1 lukem so = LDAP_LIST_NEXT(so, so_link);
56 1.1 lukem LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, so_tmp, so_link);
57 1.1 lukem }
58 1.1 lukem ch_free(sh->sh_map[i]);
59 1.1 lukem }
60 1.1 lukem ch_free(sh->sh_free);
61 1.1 lukem ch_free(sh->sh_map);
62 1.1 lukem
63 1.1 lukem so = LDAP_LIST_FIRST(&sh->sh_sopool);
64 1.1 lukem while (so) {
65 1.1 lukem struct slab_object *so_tmp = so;
66 1.1 lukem so = LDAP_LIST_NEXT(so, so_link);
67 1.1 lukem if (!so_tmp->so_blockhead) {
68 1.1 lukem LDAP_LIST_REMOVE(so_tmp, so_link);
69 1.1 lukem }
70 1.1 lukem }
71 1.1 lukem so = LDAP_LIST_FIRST(&sh->sh_sopool);
72 1.1 lukem while (so) {
73 1.1 lukem struct slab_object *so_tmp = so;
74 1.1 lukem so = LDAP_LIST_NEXT(so, so_link);
75 1.1 lukem ch_free(so_tmp);
76 1.1 lukem }
77 1.1 lukem ber_memfree_x(sh->sh_base, NULL);
78 1.1 lukem ber_memfree_x(sh, NULL);
79 1.1 lukem }
80 1.1 lukem }
81 1.1 lukem
82 1.1 lukem BerMemoryFunctions slap_sl_mfuncs =
83 1.1 lukem { slap_sl_malloc, slap_sl_calloc, slap_sl_realloc, slap_sl_free };
84 1.1 lukem
85 1.1 lukem void
86 1.1 lukem slap_sl_mem_init()
87 1.1 lukem {
88 1.1 lukem ber_set_option( NULL, LBER_OPT_MEMORY_FNS, &slap_sl_mfuncs );
89 1.1 lukem }
90 1.1 lukem
91 1.1 lukem #ifdef NO_THREADS
92 1.1 lukem static struct slab_heap *slheap;
93 1.1 lukem #endif
94 1.1 lukem
95 1.1.1.2 lukem /* This allocator always returns memory aligned on a 2-int boundary.
96 1.1.1.2 lukem *
97 1.1.1.2 lukem * The stack-based allocator stores the size as a ber_len_t at both
98 1.1.1.2 lukem * the head and tail of the allocated block. When freeing a block, the
99 1.1.1.2 lukem * tail length is ORed with 1 to mark it as free. Freed space can only
100 1.1.1.2 lukem * be reclaimed from the tail forward. If the tail block is never freed,
101 1.1.1.2 lukem * nothing else will be reclaimed until the slab is reset...
102 1.1.1.2 lukem */
103 1.1 lukem void *
104 1.1 lukem slap_sl_mem_create(
105 1.1 lukem ber_len_t size,
106 1.1 lukem int stack,
107 1.1 lukem void *ctx,
108 1.1 lukem int new
109 1.1 lukem )
110 1.1 lukem {
111 1.1 lukem struct slab_heap *sh;
112 1.1 lukem ber_len_t size_shift;
113 1.1 lukem int pad = 2*sizeof(int)-1, pad_shift;
114 1.1 lukem int order = -1, order_start = -1, order_end = -1;
115 1.1 lukem int i;
116 1.1 lukem struct slab_object *so;
117 1.1 lukem
118 1.1 lukem #ifdef NO_THREADS
119 1.1 lukem sh = slheap;
120 1.1 lukem #else
121 1.1 lukem void *sh_tmp = NULL;
122 1.1 lukem ldap_pvt_thread_pool_getkey(
123 1.1 lukem ctx, (void *)slap_sl_mem_init, &sh_tmp, NULL );
124 1.1 lukem sh = sh_tmp;
125 1.1 lukem #endif
126 1.1 lukem
127 1.1.1.2 lukem if ( sh && !new )
128 1.1 lukem return sh;
129 1.1 lukem
130 1.1 lukem /* round up to doubleword boundary */
131 1.1 lukem size += pad;
132 1.1 lukem size &= ~pad;
133 1.1 lukem
134 1.1 lukem if (stack) {
135 1.1 lukem if (!sh) {
136 1.1 lukem sh = ch_malloc(sizeof(struct slab_heap));
137 1.1 lukem sh->sh_base = ch_malloc(size);
138 1.1 lukem #ifdef NO_THREADS
139 1.1 lukem slheap = sh;
140 1.1 lukem #else
141 1.1 lukem ldap_pvt_thread_pool_setkey(ctx, (void *)slap_sl_mem_init,
142 1.1 lukem (void *)sh, slap_sl_mem_destroy, NULL, NULL);
143 1.1 lukem #endif
144 1.1 lukem } else if ( size > (char *)sh->sh_end - (char *)sh->sh_base ) {
145 1.1 lukem void *newptr;
146 1.1 lukem
147 1.1 lukem newptr = ch_realloc( sh->sh_base, size );
148 1.1 lukem if ( newptr == NULL ) return NULL;
149 1.1 lukem sh->sh_base = newptr;
150 1.1 lukem }
151 1.1.1.2 lukem /* insert dummy len */
152 1.1.1.2 lukem {
153 1.1.1.2 lukem ber_len_t *i = sh->sh_base;
154 1.1.1.2 lukem *i++ = 0;
155 1.1.1.2 lukem sh->sh_last = i;
156 1.1.1.2 lukem }
157 1.1 lukem sh->sh_end = (char *) sh->sh_base + size;
158 1.1 lukem sh->sh_stack = stack;
159 1.1 lukem return sh;
160 1.1 lukem } else {
161 1.1 lukem size_shift = size - 1;
162 1.1 lukem do {
163 1.1 lukem order_end++;
164 1.1 lukem } while (size_shift >>= 1);
165 1.1 lukem
166 1.1 lukem pad_shift = pad - 1;
167 1.1 lukem do {
168 1.1 lukem order_start++;
169 1.1 lukem } while (pad_shift >>= 1);
170 1.1 lukem
171 1.1 lukem order = order_end - order_start + 1;
172 1.1 lukem
173 1.1 lukem if (!sh) {
174 1.1 lukem sh = (struct slab_heap *) ch_malloc(sizeof(struct slab_heap));
175 1.1 lukem sh->sh_base = ch_malloc(size);
176 1.1 lukem #ifdef NO_THREADS
177 1.1 lukem slheap = sh;
178 1.1 lukem #else
179 1.1 lukem ldap_pvt_thread_pool_setkey(ctx, (void *)slap_sl_mem_init,
180 1.1 lukem (void *)sh, slap_sl_mem_destroy, NULL, NULL);
181 1.1 lukem #endif
182 1.1 lukem } else {
183 1.1 lukem for (i = 0; i <= sh->sh_maxorder - order_start; i++) {
184 1.1 lukem so = LDAP_LIST_FIRST(&sh->sh_free[i]);
185 1.1 lukem while (so) {
186 1.1 lukem struct slab_object *so_tmp = so;
187 1.1 lukem so = LDAP_LIST_NEXT(so, so_link);
188 1.1 lukem LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, so_tmp, so_link);
189 1.1 lukem }
190 1.1 lukem ch_free(sh->sh_map[i]);
191 1.1 lukem }
192 1.1 lukem ch_free(sh->sh_free);
193 1.1 lukem ch_free(sh->sh_map);
194 1.1 lukem
195 1.1 lukem so = LDAP_LIST_FIRST(&sh->sh_sopool);
196 1.1 lukem while (so) {
197 1.1 lukem struct slab_object *so_tmp = so;
198 1.1 lukem so = LDAP_LIST_NEXT(so, so_link);
199 1.1 lukem if (!so_tmp->so_blockhead) {
200 1.1 lukem LDAP_LIST_REMOVE(so_tmp, so_link);
201 1.1 lukem }
202 1.1 lukem }
203 1.1 lukem so = LDAP_LIST_FIRST(&sh->sh_sopool);
204 1.1 lukem while (so) {
205 1.1 lukem struct slab_object *so_tmp = so;
206 1.1 lukem so = LDAP_LIST_NEXT(so, so_link);
207 1.1 lukem ch_free(so_tmp);
208 1.1 lukem }
209 1.1 lukem
210 1.1 lukem if (size > (char *)sh->sh_end - (char *)sh->sh_base) {
211 1.1 lukem void *newptr;
212 1.1 lukem
213 1.1.1.2 lukem newptr = ch_realloc( sh->sh_base, size );
214 1.1 lukem if ( newptr == NULL ) return NULL;
215 1.1 lukem sh->sh_base = newptr;
216 1.1 lukem }
217 1.1 lukem }
218 1.1 lukem sh->sh_end = (char *)sh->sh_base + size;
219 1.1 lukem sh->sh_maxorder = order_end;
220 1.1 lukem
221 1.1 lukem sh->sh_free = (struct sh_freelist *)
222 1.1 lukem ch_malloc(order * sizeof(struct sh_freelist));
223 1.1 lukem for (i = 0; i < order; i++) {
224 1.1 lukem LDAP_LIST_INIT(&sh->sh_free[i]);
225 1.1 lukem }
226 1.1 lukem
227 1.1 lukem LDAP_LIST_INIT(&sh->sh_sopool);
228 1.1 lukem
229 1.1 lukem if (LDAP_LIST_EMPTY(&sh->sh_sopool)) {
230 1.1 lukem slap_replenish_sopool(sh);
231 1.1 lukem }
232 1.1 lukem so = LDAP_LIST_FIRST(&sh->sh_sopool);
233 1.1 lukem LDAP_LIST_REMOVE(so, so_link);
234 1.1 lukem so->so_ptr = sh->sh_base;
235 1.1 lukem
236 1.1 lukem LDAP_LIST_INSERT_HEAD(&sh->sh_free[order-1], so, so_link);
237 1.1 lukem
238 1.1 lukem sh->sh_map = (unsigned char **)
239 1.1 lukem ch_malloc(order * sizeof(unsigned char *));
240 1.1 lukem for (i = 0; i < order; i++) {
241 1.1 lukem int shiftamt = order_start + 1 + i;
242 1.1 lukem int nummaps = size >> shiftamt;
243 1.1 lukem assert(nummaps);
244 1.1 lukem nummaps >>= 3;
245 1.1 lukem if (!nummaps) nummaps = 1;
246 1.1 lukem sh->sh_map[i] = (unsigned char *) ch_malloc(nummaps);
247 1.1 lukem memset(sh->sh_map[i], 0, nummaps);
248 1.1 lukem }
249 1.1 lukem sh->sh_stack = stack;
250 1.1 lukem return sh;
251 1.1 lukem }
252 1.1 lukem }
253 1.1 lukem
254 1.1 lukem void
255 1.1 lukem slap_sl_mem_detach(
256 1.1 lukem void *ctx,
257 1.1 lukem void *memctx
258 1.1 lukem )
259 1.1 lukem {
260 1.1 lukem #ifdef NO_THREADS
261 1.1 lukem slheap = NULL;
262 1.1 lukem #else
263 1.1 lukem /* separate from context */
264 1.1 lukem ldap_pvt_thread_pool_setkey( ctx, (void *)slap_sl_mem_init,
265 1.1 lukem NULL, 0, NULL, NULL );
266 1.1 lukem #endif
267 1.1 lukem }
268 1.1 lukem
269 1.1 lukem void *
270 1.1 lukem slap_sl_malloc(
271 1.1 lukem ber_len_t size,
272 1.1 lukem void *ctx
273 1.1 lukem )
274 1.1 lukem {
275 1.1 lukem struct slab_heap *sh = ctx;
276 1.1 lukem int pad = 2*sizeof(int)-1, pad_shift;
277 1.1 lukem ber_len_t *ptr, *newptr;
278 1.1 lukem
279 1.1 lukem #ifdef SLAP_NO_SL_MALLOC
280 1.1.1.2 lukem newptr = ber_memalloc_x( size, NULL );
281 1.1.1.2 lukem if ( newptr ) return newptr;
282 1.1.1.2 lukem assert( 0 );
283 1.1.1.2 lukem exit( EXIT_FAILURE );
284 1.1 lukem #endif
285 1.1 lukem
286 1.1 lukem /* ber_set_option calls us like this */
287 1.1.1.2 lukem if (!ctx) {
288 1.1.1.2 lukem newptr = ber_memalloc_x( size, NULL );
289 1.1.1.2 lukem if ( newptr ) return newptr;
290 1.1.1.2 lukem assert( 0 );
291 1.1.1.2 lukem exit( EXIT_FAILURE );
292 1.1.1.2 lukem }
293 1.1 lukem
294 1.1.1.2 lukem /* round up to doubleword boundary, plus space for len at head and tail */
295 1.1.1.2 lukem size += 2*sizeof(ber_len_t) + pad;
296 1.1 lukem size &= ~pad;
297 1.1 lukem
298 1.1 lukem if (sh->sh_stack) {
299 1.1 lukem if ((char *)sh->sh_last + size >= (char *)sh->sh_end) {
300 1.1 lukem Debug(LDAP_DEBUG_TRACE,
301 1.1 lukem "slap_sl_malloc of %lu bytes failed, using ch_malloc\n",
302 1.1 lukem (long)size, 0, 0);
303 1.1 lukem return ch_malloc(size);
304 1.1 lukem }
305 1.1 lukem newptr = sh->sh_last;
306 1.1 lukem sh->sh_last = (char *) sh->sh_last + size;
307 1.1.1.2 lukem size -= sizeof(ber_len_t);
308 1.1.1.2 lukem *newptr++ = size;
309 1.1.1.2 lukem *(ber_len_t *)((char *)sh->sh_last - sizeof(ber_len_t)) = size;
310 1.1 lukem return( (void *)newptr );
311 1.1 lukem } else {
312 1.1.1.2 lukem struct slab_object *so_new, *so_left, *so_right;
313 1.1.1.2 lukem ber_len_t size_shift;
314 1.1.1.2 lukem int order = -1, order_start = -1;
315 1.1.1.2 lukem unsigned long diff;
316 1.1.1.2 lukem int i, j;
317 1.1.1.2 lukem
318 1.1 lukem size_shift = size - 1;
319 1.1 lukem do {
320 1.1 lukem order++;
321 1.1 lukem } while (size_shift >>= 1);
322 1.1 lukem
323 1.1 lukem pad_shift = pad - 1;
324 1.1 lukem do {
325 1.1 lukem order_start++;
326 1.1 lukem } while (pad_shift >>= 1);
327 1.1 lukem
328 1.1 lukem for (i = order; i <= sh->sh_maxorder &&
329 1.1 lukem LDAP_LIST_EMPTY(&sh->sh_free[i-order_start]); i++);
330 1.1 lukem
331 1.1 lukem if (i == order) {
332 1.1 lukem so_new = LDAP_LIST_FIRST(&sh->sh_free[i-order_start]);
333 1.1 lukem LDAP_LIST_REMOVE(so_new, so_link);
334 1.1 lukem ptr = so_new->so_ptr;
335 1.1 lukem diff = (unsigned long)((char*)ptr -
336 1.1 lukem (char*)sh->sh_base) >> (order + 1);
337 1.1 lukem sh->sh_map[order-order_start][diff>>3] |= (1 << (diff & 0x7));
338 1.1 lukem *ptr++ = size - sizeof(ber_len_t);
339 1.1 lukem LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, so_new, so_link);
340 1.1 lukem return((void*)ptr);
341 1.1 lukem } else if (i <= sh->sh_maxorder) {
342 1.1 lukem for (j = i; j > order; j--) {
343 1.1 lukem so_left = LDAP_LIST_FIRST(&sh->sh_free[j-order_start]);
344 1.1 lukem LDAP_LIST_REMOVE(so_left, so_link);
345 1.1 lukem if (LDAP_LIST_EMPTY(&sh->sh_sopool)) {
346 1.1 lukem slap_replenish_sopool(sh);
347 1.1 lukem }
348 1.1 lukem so_right = LDAP_LIST_FIRST(&sh->sh_sopool);
349 1.1 lukem LDAP_LIST_REMOVE(so_right, so_link);
350 1.1 lukem so_right->so_ptr = (void *)((char *)so_left->so_ptr + (1 << j));
351 1.1 lukem if (j == order + 1) {
352 1.1 lukem ptr = so_left->so_ptr;
353 1.1 lukem diff = (unsigned long)((char*)ptr -
354 1.1 lukem (char*)sh->sh_base) >> (order+1);
355 1.1 lukem sh->sh_map[order-order_start][diff>>3] |=
356 1.1 lukem (1 << (diff & 0x7));
357 1.1 lukem *ptr++ = size - sizeof(ber_len_t);
358 1.1 lukem LDAP_LIST_INSERT_HEAD(
359 1.1 lukem &sh->sh_free[j-1-order_start], so_right, so_link);
360 1.1 lukem LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, so_left, so_link);
361 1.1 lukem return((void*)ptr);
362 1.1 lukem } else {
363 1.1 lukem LDAP_LIST_INSERT_HEAD(
364 1.1 lukem &sh->sh_free[j-1-order_start], so_right, so_link);
365 1.1 lukem LDAP_LIST_INSERT_HEAD(
366 1.1 lukem &sh->sh_free[j-1-order_start], so_left, so_link);
367 1.1 lukem }
368 1.1 lukem }
369 1.1 lukem } else {
370 1.1 lukem Debug( LDAP_DEBUG_TRACE,
371 1.1 lukem "slap_sl_malloc of %lu bytes failed, using ch_malloc\n",
372 1.1 lukem (long)size, 0, 0);
373 1.1 lukem return (void*)ch_malloc(size);
374 1.1 lukem }
375 1.1 lukem }
376 1.1 lukem
377 1.1 lukem /* FIXME: missing return; guessing... */
378 1.1 lukem return NULL;
379 1.1 lukem }
380 1.1 lukem
381 1.1 lukem void *
382 1.1 lukem slap_sl_calloc( ber_len_t n, ber_len_t size, void *ctx )
383 1.1 lukem {
384 1.1 lukem void *newptr;
385 1.1 lukem
386 1.1 lukem newptr = slap_sl_malloc( n*size, ctx );
387 1.1 lukem if ( newptr ) {
388 1.1 lukem memset( newptr, 0, n*size );
389 1.1 lukem }
390 1.1 lukem return newptr;
391 1.1 lukem }
392 1.1 lukem
393 1.1 lukem void *
394 1.1 lukem slap_sl_realloc(void *ptr, ber_len_t size, void *ctx)
395 1.1 lukem {
396 1.1 lukem struct slab_heap *sh = ctx;
397 1.1 lukem int pad = 2*sizeof(int) -1;
398 1.1 lukem ber_len_t *p = (ber_len_t *)ptr, *newptr;
399 1.1 lukem
400 1.1 lukem if (ptr == NULL)
401 1.1 lukem return slap_sl_malloc(size, ctx);
402 1.1 lukem
403 1.1 lukem #ifdef SLAP_NO_SL_MALLOC
404 1.1.1.2 lukem newptr = ber_memrealloc_x( ptr, size, NULL );
405 1.1.1.2 lukem if ( newptr ) return newptr;
406 1.1.1.2 lukem assert( 0 );
407 1.1.1.2 lukem exit( EXIT_FAILURE );
408 1.1 lukem #endif
409 1.1 lukem
410 1.1 lukem /* Not our memory? */
411 1.1 lukem if (!sh || ptr < sh->sh_base || ptr >= sh->sh_end) {
412 1.1 lukem /* duplicate of realloc behavior, oh well */
413 1.1 lukem newptr = ber_memrealloc_x(ptr, size, NULL);
414 1.1 lukem if (newptr) {
415 1.1 lukem return newptr;
416 1.1 lukem }
417 1.1 lukem Debug(LDAP_DEBUG_ANY, "ch_realloc of %lu bytes failed\n",
418 1.1 lukem (long) size, 0, 0);
419 1.1 lukem assert(0);
420 1.1 lukem exit( EXIT_FAILURE );
421 1.1 lukem }
422 1.1 lukem
423 1.1 lukem if (size == 0) {
424 1.1 lukem slap_sl_free(ptr, ctx);
425 1.1 lukem return NULL;
426 1.1 lukem }
427 1.1 lukem
428 1.1 lukem if (sh->sh_stack) {
429 1.1 lukem /* round up to doubleword boundary */
430 1.1 lukem size += pad + sizeof( ber_len_t );
431 1.1 lukem size &= ~pad;
432 1.1 lukem
433 1.1.1.2 lukem p--;
434 1.1.1.2 lukem
435 1.1 lukem /* Never shrink blocks */
436 1.1.1.2 lukem if (size <= p[0]) {
437 1.1.1.2 lukem newptr = ptr;
438 1.1 lukem
439 1.1 lukem /* If reallocing the last block, we can grow it */
440 1.1.1.2 lukem } else if ((char *)ptr + p[0] == sh->sh_last &&
441 1.1 lukem (char *)ptr + size < (char *)sh->sh_end ) {
442 1.1.1.2 lukem newptr = ptr;
443 1.1.1.2 lukem sh->sh_last = (char *)ptr + size;
444 1.1.1.2 lukem p[0] = size;
445 1.1.1.2 lukem p[size/sizeof(ber_len_t)] = size;
446 1.1.1.2 lukem
447 1.1 lukem /* Nowhere to grow, need to alloc and copy */
448 1.1 lukem } else {
449 1.1.1.2 lukem newptr = slap_sl_malloc(size-sizeof(ber_len_t), ctx);
450 1.1.1.2 lukem AC_MEMCPY(newptr, ptr, p[0]-sizeof(ber_len_t));
451 1.1.1.2 lukem /* mark old region as free */
452 1.1.1.2 lukem p[p[0]/sizeof(ber_len_t)] |= 1;
453 1.1 lukem }
454 1.1 lukem return newptr;
455 1.1 lukem } else {
456 1.1 lukem void *newptr2;
457 1.1 lukem
458 1.1 lukem newptr2 = slap_sl_malloc(size, ctx);
459 1.1 lukem if (size < p[-1]) {
460 1.1 lukem AC_MEMCPY(newptr2, ptr, size);
461 1.1 lukem } else {
462 1.1 lukem AC_MEMCPY(newptr2, ptr, p[-1]);
463 1.1 lukem }
464 1.1 lukem slap_sl_free(ptr, ctx);
465 1.1 lukem return newptr2;
466 1.1 lukem }
467 1.1 lukem }
468 1.1 lukem
469 1.1 lukem void
470 1.1 lukem slap_sl_free(void *ptr, void *ctx)
471 1.1 lukem {
472 1.1 lukem struct slab_heap *sh = ctx;
473 1.1.1.2 lukem ber_len_t size;
474 1.1 lukem ber_len_t *p = (ber_len_t *)ptr, *tmpp;
475 1.1 lukem
476 1.1 lukem if (!ptr)
477 1.1 lukem return;
478 1.1 lukem
479 1.1 lukem #ifdef SLAP_NO_SL_MALLOC
480 1.1 lukem ber_memfree_x( ptr, NULL );
481 1.1 lukem return;
482 1.1 lukem #endif
483 1.1 lukem
484 1.1 lukem if (!sh || ptr < sh->sh_base || ptr >= sh->sh_end) {
485 1.1 lukem ber_memfree_x(ptr, NULL);
486 1.1.1.2 lukem } else if (sh->sh_stack) {
487 1.1.1.2 lukem tmpp = (ber_len_t *)((char *)ptr + p[-1]);
488 1.1.1.2 lukem /* mark it free */
489 1.1.1.2 lukem tmpp[-1] |= 1;
490 1.1.1.2 lukem /* reclaim free space off tail */
491 1.1.1.2 lukem while ( tmpp == sh->sh_last ) {
492 1.1.1.2 lukem if ( tmpp[-1] & 1 ) {
493 1.1.1.2 lukem size = tmpp[-1] ^ 1;
494 1.1.1.2 lukem ptr = (char *)tmpp - size;
495 1.1.1.2 lukem p = (ber_len_t *)ptr;
496 1.1.1.2 lukem p--;
497 1.1.1.2 lukem sh->sh_last = p;
498 1.1.1.2 lukem tmpp = sh->sh_last;
499 1.1.1.2 lukem } else {
500 1.1.1.2 lukem break;
501 1.1.1.2 lukem }
502 1.1.1.2 lukem }
503 1.1.1.2 lukem } else {
504 1.1.1.2 lukem int size_shift, order_size;
505 1.1.1.2 lukem int pad = 2*sizeof(int)-1, pad_shift;
506 1.1.1.2 lukem int order_start = -1, order = -1;
507 1.1.1.2 lukem struct slab_object *so;
508 1.1.1.2 lukem unsigned long diff;
509 1.1.1.2 lukem int i, inserted = 0;
510 1.1.1.2 lukem
511 1.1 lukem size = *(--p);
512 1.1 lukem size_shift = size + sizeof(ber_len_t) - 1;
513 1.1 lukem do {
514 1.1 lukem order++;
515 1.1 lukem } while (size_shift >>= 1);
516 1.1 lukem
517 1.1 lukem pad_shift = pad - 1;
518 1.1 lukem do {
519 1.1 lukem order_start++;
520 1.1 lukem } while (pad_shift >>= 1);
521 1.1 lukem
522 1.1 lukem for (i = order, tmpp = p; i <= sh->sh_maxorder; i++) {
523 1.1 lukem order_size = 1 << (i+1);
524 1.1 lukem diff = (unsigned long)((char*)tmpp - (char*)sh->sh_base) >> (i+1);
525 1.1 lukem sh->sh_map[i-order_start][diff>>3] &= (~(1 << (diff & 0x7)));
526 1.1 lukem if (diff == ((diff>>1)<<1)) {
527 1.1 lukem if (!(sh->sh_map[i-order_start][(diff+1)>>3] &
528 1.1 lukem (1<<((diff+1)&0x7)))) {
529 1.1 lukem so = LDAP_LIST_FIRST(&sh->sh_free[i-order_start]);
530 1.1 lukem while (so) {
531 1.1 lukem if ((char*)so->so_ptr == (char*)tmpp) {
532 1.1 lukem LDAP_LIST_REMOVE( so, so_link );
533 1.1 lukem } else if ((char*)so->so_ptr ==
534 1.1 lukem (char*)tmpp + order_size) {
535 1.1 lukem LDAP_LIST_REMOVE(so, so_link);
536 1.1 lukem break;
537 1.1 lukem }
538 1.1 lukem so = LDAP_LIST_NEXT(so, so_link);
539 1.1 lukem }
540 1.1 lukem if (so) {
541 1.1 lukem if (i < sh->sh_maxorder) {
542 1.1 lukem inserted = 1;
543 1.1 lukem so->so_ptr = tmpp;
544 1.1 lukem LDAP_LIST_INSERT_HEAD(&sh->sh_free[i-order_start+1],
545 1.1 lukem so, so_link);
546 1.1 lukem }
547 1.1 lukem continue;
548 1.1 lukem } else {
549 1.1 lukem if (LDAP_LIST_EMPTY(&sh->sh_sopool)) {
550 1.1 lukem slap_replenish_sopool(sh);
551 1.1 lukem }
552 1.1 lukem so = LDAP_LIST_FIRST(&sh->sh_sopool);
553 1.1 lukem LDAP_LIST_REMOVE(so, so_link);
554 1.1 lukem so->so_ptr = tmpp;
555 1.1 lukem LDAP_LIST_INSERT_HEAD(&sh->sh_free[i-order_start],
556 1.1 lukem so, so_link);
557 1.1 lukem break;
558 1.1 lukem
559 1.1 lukem Debug(LDAP_DEBUG_TRACE, "slap_sl_free: "
560 1.1 lukem "free object not found while bit is clear.\n",
561 1.1 lukem 0, 0, 0);
562 1.1 lukem assert(so != NULL);
563 1.1 lukem
564 1.1 lukem }
565 1.1 lukem } else {
566 1.1 lukem if (!inserted) {
567 1.1 lukem if (LDAP_LIST_EMPTY(&sh->sh_sopool)) {
568 1.1 lukem slap_replenish_sopool(sh);
569 1.1 lukem }
570 1.1 lukem so = LDAP_LIST_FIRST(&sh->sh_sopool);
571 1.1 lukem LDAP_LIST_REMOVE(so, so_link);
572 1.1 lukem so->so_ptr = tmpp;
573 1.1 lukem LDAP_LIST_INSERT_HEAD(&sh->sh_free[i-order_start],
574 1.1 lukem so, so_link);
575 1.1 lukem }
576 1.1 lukem break;
577 1.1 lukem }
578 1.1 lukem } else {
579 1.1 lukem if (!(sh->sh_map[i-order_start][(diff-1)>>3] &
580 1.1 lukem (1<<((diff-1)&0x7)))) {
581 1.1 lukem so = LDAP_LIST_FIRST(&sh->sh_free[i-order_start]);
582 1.1 lukem while (so) {
583 1.1 lukem if ((char*)so->so_ptr == (char*)tmpp) {
584 1.1 lukem LDAP_LIST_REMOVE(so, so_link);
585 1.1 lukem } else if ((char*)tmpp == (char *)so->so_ptr + order_size) {
586 1.1 lukem LDAP_LIST_REMOVE(so, so_link);
587 1.1 lukem tmpp = so->so_ptr;
588 1.1 lukem break;
589 1.1 lukem }
590 1.1 lukem so = LDAP_LIST_NEXT(so, so_link);
591 1.1 lukem }
592 1.1 lukem if (so) {
593 1.1 lukem if (i < sh->sh_maxorder) {
594 1.1 lukem inserted = 1;
595 1.1 lukem LDAP_LIST_INSERT_HEAD(&sh->sh_free[i-order_start+1], so, so_link);
596 1.1 lukem continue;
597 1.1 lukem }
598 1.1 lukem } else {
599 1.1 lukem if (LDAP_LIST_EMPTY(&sh->sh_sopool)) {
600 1.1 lukem slap_replenish_sopool(sh);
601 1.1 lukem }
602 1.1 lukem so = LDAP_LIST_FIRST(&sh->sh_sopool);
603 1.1 lukem LDAP_LIST_REMOVE(so, so_link);
604 1.1 lukem so->so_ptr = tmpp;
605 1.1 lukem LDAP_LIST_INSERT_HEAD(&sh->sh_free[i-order_start],
606 1.1 lukem so, so_link);
607 1.1 lukem break;
608 1.1 lukem
609 1.1 lukem Debug(LDAP_DEBUG_TRACE, "slap_sl_free: "
610 1.1 lukem "free object not found while bit is clear.\n",
611 1.1 lukem 0, 0, 0 );
612 1.1 lukem assert(so != NULL);
613 1.1 lukem
614 1.1 lukem }
615 1.1 lukem } else {
616 1.1 lukem if ( !inserted ) {
617 1.1 lukem if (LDAP_LIST_EMPTY(&sh->sh_sopool)) {
618 1.1 lukem slap_replenish_sopool(sh);
619 1.1 lukem }
620 1.1 lukem so = LDAP_LIST_FIRST(&sh->sh_sopool);
621 1.1 lukem LDAP_LIST_REMOVE(so, so_link);
622 1.1 lukem so->so_ptr = tmpp;
623 1.1 lukem LDAP_LIST_INSERT_HEAD(&sh->sh_free[i-order_start],
624 1.1 lukem so, so_link);
625 1.1 lukem }
626 1.1 lukem break;
627 1.1 lukem }
628 1.1 lukem }
629 1.1 lukem }
630 1.1 lukem }
631 1.1 lukem }
632 1.1 lukem
633 1.1 lukem void *
634 1.1 lukem slap_sl_context( void *ptr )
635 1.1 lukem {
636 1.1 lukem struct slab_heap *sh;
637 1.1 lukem void *ctx, *sh_tmp;
638 1.1 lukem
639 1.1 lukem if ( slapMode & SLAP_TOOL_MODE ) return NULL;
640 1.1 lukem
641 1.1 lukem #ifdef NO_THREADS
642 1.1 lukem sh = slheap;
643 1.1 lukem #else
644 1.1 lukem ctx = ldap_pvt_thread_pool_context();
645 1.1 lukem
646 1.1 lukem sh_tmp = NULL;
647 1.1 lukem ldap_pvt_thread_pool_getkey(
648 1.1 lukem ctx, (void *)slap_sl_mem_init, &sh_tmp, NULL);
649 1.1 lukem sh = sh_tmp;
650 1.1 lukem #endif
651 1.1 lukem
652 1.1 lukem if (sh && ptr >= sh->sh_base && ptr <= sh->sh_end) {
653 1.1 lukem return sh;
654 1.1 lukem }
655 1.1 lukem return NULL;
656 1.1 lukem }
657 1.1 lukem
658 1.1 lukem static struct slab_object *
659 1.1 lukem slap_replenish_sopool(
660 1.1 lukem struct slab_heap* sh
661 1.1 lukem )
662 1.1 lukem {
663 1.1 lukem struct slab_object *so_block;
664 1.1 lukem int i;
665 1.1 lukem
666 1.1 lukem so_block = (struct slab_object *)ch_malloc(
667 1.1 lukem SLAP_SLAB_SOBLOCK * sizeof(struct slab_object));
668 1.1 lukem
669 1.1 lukem if ( so_block == NULL ) {
670 1.1 lukem return NULL;
671 1.1 lukem }
672 1.1 lukem
673 1.1 lukem so_block[0].so_blockhead = 1;
674 1.1 lukem LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, &so_block[0], so_link);
675 1.1 lukem for (i = 1; i < SLAP_SLAB_SOBLOCK; i++) {
676 1.1 lukem so_block[i].so_blockhead = 0;
677 1.1 lukem LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, &so_block[i], so_link );
678 1.1 lukem }
679 1.1 lukem
680 1.1 lukem return so_block;
681 1.1 lukem }
682 1.1 lukem
683 1.1 lukem #ifdef SLAPD_UNUSED
684 1.1 lukem static void
685 1.1 lukem print_slheap(int level, void *ctx)
686 1.1 lukem {
687 1.1 lukem struct slab_heap *sh = ctx;
688 1.1 lukem int order_start = -1;
689 1.1 lukem int pad = 2*sizeof(int)-1, pad_shift;
690 1.1 lukem struct slab_object *so;
691 1.1 lukem int i, j, once = 0;
692 1.1 lukem
693 1.1 lukem if (!ctx) {
694 1.1 lukem Debug(level, "NULL memctx\n", 0, 0, 0);
695 1.1 lukem return;
696 1.1 lukem }
697 1.1 lukem
698 1.1 lukem pad_shift = pad - 1;
699 1.1 lukem do {
700 1.1 lukem order_start++;
701 1.1 lukem } while (pad_shift >>= 1);
702 1.1 lukem
703 1.1 lukem Debug(level, "sh->sh_maxorder=%d\n", sh->sh_maxorder, 0, 0);
704 1.1 lukem
705 1.1 lukem for (i = order_start; i <= sh->sh_maxorder; i++) {
706 1.1 lukem once = 0;
707 1.1 lukem Debug(level, "order=%d\n", i, 0, 0);
708 1.1 lukem for (j = 0; j < (1<<(sh->sh_maxorder-i))/8; j++) {
709 1.1 lukem Debug(level, "%02x ", sh->sh_map[i-order_start][j], 0, 0);
710 1.1 lukem once = 1;
711 1.1 lukem }
712 1.1 lukem if (!once) {
713 1.1 lukem Debug(level, "%02x ", sh->sh_map[i-order_start][0], 0, 0);
714 1.1 lukem }
715 1.1 lukem Debug(level, "\n", 0, 0, 0);
716 1.1 lukem Debug(level, "free list:\n", 0, 0, 0);
717 1.1 lukem so = LDAP_LIST_FIRST(&sh->sh_free[i-order_start]);
718 1.1 lukem while (so) {
719 1.1 lukem Debug(level, "%lx\n", (unsigned long) so->so_ptr, 0, 0);
720 1.1 lukem so = LDAP_LIST_NEXT(so, so_link);
721 1.1 lukem }
722 1.1 lukem }
723 1.1 lukem }
724 1.1 lukem #endif
725