]> git.sur5r.net Git - openldap/blob - servers/slapd/sl_malloc.c
ITS#3226: Clear attribute flags after schema_check failed
[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 #ifdef NEW_LOGGING
124                 LDAP_LOG( OPERATION, INFO, 
125                         "slap_sl_malloc of %lu bytes failed, using ch_malloc\n",
126                         (long)size, 0,0 );
127 #else
128                 Debug( LDAP_DEBUG_TRACE,
129                         "slap_sl_malloc of %lu bytes failed, using ch_malloc\n",
130                         (long)size, 0,0 );
131 #endif
132                 return ch_malloc( size );
133         }
134         new = sh->h_last;
135         *new++ = size - sizeof(ber_len_t);
136         sh->h_last = (char *) sh->h_last + size;
137         
138         return( (void *)new );
139 }
140
141 void *
142 slap_sl_calloc( ber_len_t n, ber_len_t size, void *ctx )
143 {
144         void *new;
145
146         new = slap_sl_malloc( n*size, ctx );
147         if ( new ) {
148                 memset( new, 0, n*size );
149         }
150         return new;
151 }
152
153 void *
154 slap_sl_realloc( void *ptr, ber_len_t size, void *ctx )
155 {
156         struct slab_heap *sh = ctx;
157         int pad = 2*sizeof(int)-1;
158         ber_len_t *p = (ber_len_t *)ptr;
159         ber_len_t *new;
160
161         if ( ptr == NULL ) return slap_sl_malloc( size, ctx );
162
163         /* Not our memory? */
164         if ( !sh || ptr < sh->h_base || ptr >= sh->h_end ) {
165                 /* duplicate of ch_realloc behavior, oh well */
166                 new = ber_memrealloc_x( ptr, size, NULL );
167                 if (new ) {
168                         return new;
169                 }
170 #ifdef NEW_LOGGING
171                 LDAP_LOG( OPERATION, ERR, 
172                         "ch_realloc: reallocation of %lu bytes failed\n", (long)size, 0,0 );
173 #else
174                 Debug( LDAP_DEBUG_ANY, "ch_realloc of %lu bytes failed\n",
175                         (long) size, 0, 0 );
176 #endif
177                 assert( 0 );
178                 exit( EXIT_FAILURE );
179         }
180
181         if ( size == 0 ) {
182                 slap_sl_free( ptr, ctx );
183                 return NULL;
184         }
185
186         /* round up to doubleword boundary */
187         size += pad + sizeof( ber_len_t );
188         size &= ~pad;
189
190         /* Never shrink blocks */
191         if (size <= p[-1]) {
192                 new = p;
193         
194         /* If reallocing the last block, we can grow it */
195         } else if ( (char *)ptr + p[-1] == sh->h_last ) {
196                 new = p;
197                 sh->h_last = (char *) sh->h_last + size - p[-1];
198                 p[-1] = size;
199         
200         /* Nowhere to grow, need to alloc and copy */
201         } else {
202                 new = slap_sl_malloc( size, ctx );
203                 AC_MEMCPY( new, ptr, p[-1] );
204         }
205         return new;
206 }
207
208 void
209 slap_sl_free( void *ptr, void *ctx )
210 {
211         struct slab_heap *sh = ctx;
212         ber_len_t *p = (ber_len_t *)ptr;
213
214         if ( !sh || ptr < sh->h_base || ptr >= sh->h_end ) {
215                 ber_memfree_x( ptr, NULL );
216         } else if ( (char *)ptr + p[-1] == sh->h_last ) {
217                 p--;
218                 sh->h_last = p;
219         }
220 }
221
222 void *
223 slap_sl_context( void *ptr )
224 {
225         struct slab_heap *sh = NULL;
226         void *ctx;
227
228 #ifdef NO_THREADS
229         sh = slheap;
230 #else
231         ctx = ldap_pvt_thread_pool_context();
232
233         ldap_pvt_thread_pool_getkey( ctx, (void *)slap_sl_mem_init, (void **)&sh, NULL );
234 #endif
235
236         if ( sh && ptr >= sh->h_base && ptr <= sh->h_end ) {
237                 return sh;
238         }
239         return NULL;
240 }