]> git.sur5r.net Git - openldap/blob - servers/slapd/sl_malloc.c
ITS#2542 fix?
[openldap] / servers / slapd / sl_malloc.c
1 /* sl_malloc.c - malloc routines using a per-thread slab */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 2003 The OpenLDAP Foundation, All Rights Reserved.
5  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6  */
7
8 #include "portable.h"
9
10 #include <stdio.h>
11 #include <ac/string.h>
12
13 #include "slap.h"
14
15 struct slab_heap {
16         void *h_base;
17         void *h_last;
18         void *h_end;
19 };
20
21 void
22 sl_mem_destroy(
23         void *key,
24         void *data
25 )
26 {
27         struct slab_heap *sh = data;
28
29         ber_memfree_x(sh->h_base, NULL);
30         ber_memfree_x(sh, NULL);
31 }
32
33 BER_MEMALLOC_FN sl_malloc;
34 BER_MEMCALLOC_FN sl_calloc;
35 BER_MEMREALLOC_FN sl_realloc;
36 BER_MEMFREE_FN sl_free;
37
38
39 BerMemoryFunctions sl_mfuncs =
40         { sl_malloc, sl_calloc, sl_realloc, sl_free };
41
42 void
43 sl_mem_init()
44 {
45         ber_set_option( NULL, LBER_OPT_MEMORY_FNS, &sl_mfuncs );
46 }
47
48 void *
49 sl_mem_create(
50         ber_len_t size,
51         void *ctx
52 )
53 {
54         struct slab_heap *sh = NULL;
55         int pad = 2*sizeof(int)-1;
56
57         ldap_pvt_thread_pool_getkey( ctx, sl_mem_init, (void **)&sh, NULL );
58
59         /* round up to doubleword boundary */
60         size += pad;
61         size &= ~pad;
62
63         if (!sh) {
64                 sh = ch_malloc( sizeof(struct slab_heap) );
65                 sh->h_base = ch_malloc( size );
66                 ldap_pvt_thread_pool_setkey( ctx, sl_mem_init, (void *)sh, sl_mem_destroy );
67         } else if ( size > (char *) sh->h_end - (char *) sh->h_base ) {
68                 sh->h_base = ch_realloc( sh->h_base, size );
69         }
70         sh->h_last = sh->h_base;
71         sh->h_end = (char *) sh->h_base + size;
72         return sh;
73 }
74
75 void
76 sl_mem_detach(
77         void *ctx,
78         void *memctx
79 )
80 {
81         ldap_pvt_thread_pool_setkey( ctx, sl_mem_init, NULL, NULL );
82 }
83
84 void *
85 sl_malloc(
86     ber_len_t   size,
87     void *ctx
88 )
89 {
90         struct slab_heap *sh = ctx;
91         int pad = 2*sizeof(int)-1;
92         ber_len_t *new;
93
94         /* ber_set_option calls us like this */
95         if (!ctx) return ber_memalloc_x( size, NULL );
96
97         /* round up to doubleword boundary */
98         size += pad + sizeof( ber_len_t );
99         size &= ~pad;
100
101         if ((char *) sh->h_last + size >= (char *) sh->h_end ) {
102 #ifdef NEW_LOGGING
103                 LDAP_LOG( OPERATION, INFO, 
104                            "sl_malloc of %lu bytes failed, using ch_malloc\n", (long)size, 0,0 );
105 #else
106                 Debug( LDAP_DEBUG_TRACE,
107                            "sl_malloc of %lu bytes failed, using ch_malloc\n", (long)size, 0,0 );
108 #endif
109                 return ch_malloc( size );
110         }
111         new = sh->h_last;
112         *new++ = size - sizeof(ber_len_t);
113         sh->h_last = (char *) sh->h_last + size;
114         
115         return( (void *)new );
116 }
117
118 void *
119 sl_calloc( ber_len_t n, ber_len_t size, void *ctx )
120 {
121         void *new;
122
123         new = sl_malloc( n*size, ctx );
124         if ( new ) {
125                 memset( new, 0, n*size );
126         }
127         return new;
128 }
129
130 void *
131 sl_realloc( void *ptr, ber_len_t size, void *ctx )
132 {
133         struct slab_heap *sh = ctx;
134         int pad = 2*sizeof(int)-1;
135         ber_len_t *p = (ber_len_t *)ptr;
136         ber_len_t *new;
137
138         if ( ptr == NULL ) return sl_malloc( size, ctx );
139
140         /* Not our memory? */
141         if ( !sh || ptr < sh->h_base || ptr >= sh->h_end ) {
142                 /* duplicate of ch_realloc behavior, oh well */
143                 new = ber_memrealloc_x( ptr, size, NULL );
144                 if (new ) {
145                         return new;
146                 }
147 #ifdef NEW_LOGGING
148                 LDAP_LOG( OPERATION, ERR, 
149                            "ch_realloc: reallocation of %lu bytes failed\n", (long)size, 0,0 );
150 #else
151                 Debug( LDAP_DEBUG_ANY, "ch_realloc of %lu bytes failed\n",
152                         (long) size, 0, 0 );
153 #endif
154                 assert( 0 );
155                 exit( EXIT_FAILURE );
156         }
157
158         if ( size == 0 ) {
159                 sl_free( ptr, ctx );
160                 return NULL;
161         }
162
163         /* round up to doubleword boundary */
164         size += pad + sizeof( ber_len_t );
165         size &= ~pad;
166
167         /* Never shrink blocks */
168         if (size <= p[-1]) {
169                 new = p;
170         
171         /* If reallocing the last block, we can grow it */
172         } else if ( (char *)ptr + p[-1] == sh->h_last ) {
173                 new = p;
174                 sh->h_last = (char *) sh->h_last + size - p[-1];
175                 p[-1] = size;
176         
177         /* Nowhere to grow, need to alloc and copy */
178         } else {
179                 new = sl_malloc( size, ctx );
180                 AC_MEMCPY( new, ptr, p[-1] );
181         }
182         return new;
183 }
184
185 void
186 sl_free( void *ptr, void *ctx )
187 {
188         struct slab_heap *sh = ctx;
189         ber_len_t *p = (ber_len_t *)ptr;
190
191         if ( !sh || ptr < sh->h_base || ptr >= sh->h_end ) {
192                 ber_memfree_x( ptr, NULL );
193         } else if ( (char *)ptr + p[-1] == sh->h_last ) {
194                 p--;
195                 sh->h_last = p;
196         }
197 }
198
199 void
200 sl_release( void *ptr, void *ctx )
201 {
202         struct slab_heap *sh = ctx;
203
204         if ( sh && ptr >= sh->h_base && ptr <= sh->h_end ) {
205                 sh->h_last = ptr;
206         }
207 }
208
209 void *
210 sl_mark( void *ctx )
211 {
212         struct slab_heap *sh = ctx;
213         void *ret = NULL;
214
215         if (sh) ret = sh->h_last;
216
217         return ret;
218 }
219
220 void *
221 sl_context( void *ptr )
222 {
223         struct slab_heap *sh = NULL;
224         void *ctx;
225
226         ctx = ldap_pvt_thread_pool_context();
227
228         ldap_pvt_thread_pool_getkey( ctx, sl_mem_init, (void **)&sh, NULL );
229
230         if ( sh && ptr >= sh->h_base && ptr <= sh->h_end ) {
231                 return sh;
232         }
233         return NULL;
234 }