]> git.sur5r.net Git - openldap/blob - servers/slapd/sl_malloc.c
unifdef -UNEW_LOGGING
[openldap] / servers / slapd / sl_malloc.c
1 /* sl_malloc.c - malloc routines using a per-thread slab */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2003-2004 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16
17 #include "portable.h"
18
19 #include <stdio.h>
20 #include <ac/string.h>
21
22 #include "slap.h"
23
24 struct slab_heap {
25         void *h_base;
26         void *h_last;
27         void *h_end;
28 };
29
30 void
31 slap_sl_mem_destroy(
32         void *key,
33         void *data
34 )
35 {
36         struct slab_heap *sh = data;
37
38         ber_memfree_x(sh->h_base, NULL);
39         ber_memfree_x(sh, NULL);
40 }
41
42 BerMemoryFunctions slap_sl_mfuncs =
43         { slap_sl_malloc, slap_sl_calloc, slap_sl_realloc, slap_sl_free };
44
45 void
46 slap_sl_mem_init()
47 {
48         ber_set_option( NULL, LBER_OPT_MEMORY_FNS, &slap_sl_mfuncs );
49 }
50
51 #ifdef NO_THREADS
52 static struct slab_heap *slheap;
53 #endif
54
55 void *
56 slap_sl_mem_create(
57         ber_len_t size,
58         void *ctx
59 )
60 {
61         struct slab_heap *sh = NULL;
62         int pad = 2*sizeof(int)-1;
63
64 #ifdef NO_THREADS
65         sh = slheap;
66 #else
67         ldap_pvt_thread_pool_getkey( ctx, (void *)slap_sl_mem_init, (void **)&sh, NULL );
68 #endif
69
70         /* round up to doubleword boundary */
71         size += pad;
72         size &= ~pad;
73
74         if (!sh) {
75                 sh = ch_malloc( sizeof(struct slab_heap) );
76                 sh->h_base = ch_malloc( size );
77 #ifdef NO_THREADS
78                 slheap = sh;
79 #else
80                 ldap_pvt_thread_pool_setkey( ctx, (void *)slap_sl_mem_init,
81                         (void *)sh, slap_sl_mem_destroy );
82 #endif
83         } else if ( size > (char *) sh->h_end - (char *) sh->h_base ) {
84                 sh->h_base = ch_realloc( sh->h_base, size );
85         }
86         sh->h_last = sh->h_base;
87         sh->h_end = (char *) sh->h_base + size;
88         return sh;
89 }
90
91 void
92 slap_sl_mem_detach(
93         void *ctx,
94         void *memctx
95 )
96 {
97 #ifdef NO_THREADS
98         slheap = NULL;
99 #else
100         /* separate from context */
101         ldap_pvt_thread_pool_setkey( ctx, (void *)slap_sl_mem_init, NULL, NULL );
102 #endif
103 }
104
105 void *
106 slap_sl_malloc(
107     ber_len_t   size,
108     void *ctx
109 )
110 {
111         struct slab_heap *sh = ctx;
112         int pad = 2*sizeof(int)-1;
113         ber_len_t *new;
114
115         /* ber_set_option calls us like this */
116         if (!ctx) return ber_memalloc_x( size, NULL );
117
118         /* round up to doubleword boundary */
119         size += pad + sizeof( ber_len_t );
120         size &= ~pad;
121
122         if ((char *) sh->h_last + size >= (char *) sh->h_end ) {
123                 Debug( LDAP_DEBUG_TRACE,
124                         "slap_sl_malloc of %lu bytes failed, using ch_malloc\n",
125                         (long)size, 0,0 );
126                 return ch_malloc( size );
127         }
128         new = sh->h_last;
129         *new++ = size - sizeof(ber_len_t);
130         sh->h_last = (char *) sh->h_last + size;
131         
132         return( (void *)new );
133 }
134
135 void *
136 slap_sl_calloc( ber_len_t n, ber_len_t size, void *ctx )
137 {
138         void *new;
139
140         new = slap_sl_malloc( n*size, ctx );
141         if ( new ) {
142                 memset( new, 0, n*size );
143         }
144         return new;
145 }
146
147 void *
148 slap_sl_realloc( void *ptr, ber_len_t size, void *ctx )
149 {
150         struct slab_heap *sh = ctx;
151         int pad = 2*sizeof(int)-1;
152         ber_len_t *p = (ber_len_t *)ptr;
153         ber_len_t *new;
154
155         if ( ptr == NULL ) return slap_sl_malloc( size, ctx );
156
157         /* Not our memory? */
158         if ( !sh || ptr < sh->h_base || ptr >= sh->h_end ) {
159                 /* duplicate of ch_realloc behavior, oh well */
160                 new = ber_memrealloc_x( ptr, size, NULL );
161                 if (new ) {
162                         return new;
163                 }
164                 Debug( LDAP_DEBUG_ANY, "ch_realloc of %lu bytes failed\n",
165                         (long) size, 0, 0 );
166                 assert( 0 );
167                 exit( EXIT_FAILURE );
168         }
169
170         if ( size == 0 ) {
171                 slap_sl_free( ptr, ctx );
172                 return NULL;
173         }
174
175         /* round up to doubleword boundary */
176         size += pad + sizeof( ber_len_t );
177         size &= ~pad;
178
179         /* Never shrink blocks */
180         if (size <= p[-1]) {
181                 new = p;
182         
183         /* If reallocing the last block, we can grow it */
184         } else if ( (char *)ptr + p[-1] == sh->h_last ) {
185                 new = p;
186                 sh->h_last = (char *) sh->h_last + size - p[-1];
187                 p[-1] = size;
188         
189         /* Nowhere to grow, need to alloc and copy */
190         } else {
191                 new = slap_sl_malloc( size, ctx );
192                 AC_MEMCPY( new, ptr, p[-1] );
193         }
194         return new;
195 }
196
197 void
198 slap_sl_free( void *ptr, void *ctx )
199 {
200         struct slab_heap *sh = ctx;
201         ber_len_t *p = (ber_len_t *)ptr;
202
203         if ( !sh || ptr < sh->h_base || ptr >= sh->h_end ) {
204                 ber_memfree_x( ptr, NULL );
205         } else if ( (char *)ptr + p[-1] == sh->h_last ) {
206                 p--;
207                 sh->h_last = p;
208         }
209 }
210
211 void *
212 slap_sl_context( void *ptr )
213 {
214         struct slab_heap *sh = NULL;
215         void *ctx;
216
217 #ifdef NO_THREADS
218         sh = slheap;
219 #else
220         ctx = ldap_pvt_thread_pool_context();
221
222         ldap_pvt_thread_pool_getkey( ctx, (void *)slap_sl_mem_init, (void **)&sh, NULL );
223 #endif
224
225         if ( sh && ptr >= sh->h_base && ptr <= sh->h_end ) {
226                 return sh;
227         }
228         return NULL;
229 }