]> git.sur5r.net Git - openldap/blob - servers/slapd/sl_malloc.c
ITS#3115: don't increment argument to TOLOWER macro
[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 void *
52 slap_sl_mem_create(
53         ber_len_t size,
54         void *ctx
55 )
56 {
57         struct slab_heap *sh = NULL;
58         int pad = 2*sizeof(int)-1;
59
60         ldap_pvt_thread_pool_getkey( ctx, (void *)slap_sl_mem_init, (void **)&sh, NULL );
61
62         /* round up to doubleword boundary */
63         size += pad;
64         size &= ~pad;
65
66         if (!sh) {
67                 sh = ch_malloc( sizeof(struct slab_heap) );
68                 sh->h_base = ch_malloc( size );
69                 ldap_pvt_thread_pool_setkey( ctx, (void *)slap_sl_mem_init,
70                         (void *)sh, slap_sl_mem_destroy );
71         } else if ( size > (char *) sh->h_end - (char *) sh->h_base ) {
72                 sh->h_base = ch_realloc( sh->h_base, size );
73         }
74         sh->h_last = sh->h_base;
75         sh->h_end = (char *) sh->h_base + size;
76         return sh;
77 }
78
79 void
80 slap_sl_mem_detach(
81         void *ctx,
82         void *memctx
83 )
84 {
85         /* separate from context */
86         ldap_pvt_thread_pool_setkey( ctx, (void *)slap_sl_mem_init, NULL, NULL );
87 }
88
89 void *
90 slap_sl_malloc(
91     ber_len_t   size,
92     void *ctx
93 )
94 {
95         struct slab_heap *sh = ctx;
96         int pad = 2*sizeof(int)-1;
97         ber_len_t *new;
98
99         /* ber_set_option calls us like this */
100         if (!ctx) return ber_memalloc_x( size, NULL );
101
102         /* round up to doubleword boundary */
103         size += pad + sizeof( ber_len_t );
104         size &= ~pad;
105
106         if ((char *) sh->h_last + size >= (char *) sh->h_end ) {
107 #ifdef NEW_LOGGING
108                 LDAP_LOG( OPERATION, INFO, 
109                         "slap_sl_malloc of %lu bytes failed, using ch_malloc\n",
110                         (long)size, 0,0 );
111 #else
112                 Debug( LDAP_DEBUG_TRACE,
113                         "slap_sl_malloc of %lu bytes failed, using ch_malloc\n",
114                         (long)size, 0,0 );
115 #endif
116                 return ch_malloc( size );
117         }
118         new = sh->h_last;
119         *new++ = size - sizeof(ber_len_t);
120         sh->h_last = (char *) sh->h_last + size;
121         
122         return( (void *)new );
123 }
124
125 void *
126 slap_sl_calloc( ber_len_t n, ber_len_t size, void *ctx )
127 {
128         void *new;
129
130         new = slap_sl_malloc( n*size, ctx );
131         if ( new ) {
132                 memset( new, 0, n*size );
133         }
134         return new;
135 }
136
137 void *
138 slap_sl_realloc( void *ptr, ber_len_t size, void *ctx )
139 {
140         struct slab_heap *sh = ctx;
141         int pad = 2*sizeof(int)-1;
142         ber_len_t *p = (ber_len_t *)ptr;
143         ber_len_t *new;
144
145         if ( ptr == NULL ) return slap_sl_malloc( size, ctx );
146
147         /* Not our memory? */
148         if ( !sh || ptr < sh->h_base || ptr >= sh->h_end ) {
149                 /* duplicate of ch_realloc behavior, oh well */
150                 new = ber_memrealloc_x( ptr, size, NULL );
151                 if (new ) {
152                         return new;
153                 }
154 #ifdef NEW_LOGGING
155                 LDAP_LOG( OPERATION, ERR, 
156                         "ch_realloc: reallocation of %lu bytes failed\n", (long)size, 0,0 );
157 #else
158                 Debug( LDAP_DEBUG_ANY, "ch_realloc of %lu bytes failed\n",
159                         (long) size, 0, 0 );
160 #endif
161                 assert( 0 );
162                 exit( EXIT_FAILURE );
163         }
164
165         if ( size == 0 ) {
166                 slap_sl_free( ptr, ctx );
167                 return NULL;
168         }
169
170         /* round up to doubleword boundary */
171         size += pad + sizeof( ber_len_t );
172         size &= ~pad;
173
174         /* Never shrink blocks */
175         if (size <= p[-1]) {
176                 new = p;
177         
178         /* If reallocing the last block, we can grow it */
179         } else if ( (char *)ptr + p[-1] == sh->h_last ) {
180                 new = p;
181                 sh->h_last = (char *) sh->h_last + size - p[-1];
182                 p[-1] = size;
183         
184         /* Nowhere to grow, need to alloc and copy */
185         } else {
186                 new = slap_sl_malloc( size, ctx );
187                 AC_MEMCPY( new, ptr, p[-1] );
188         }
189         return new;
190 }
191
192 void
193 slap_sl_free( void *ptr, void *ctx )
194 {
195         struct slab_heap *sh = ctx;
196         ber_len_t *p = (ber_len_t *)ptr;
197
198         if ( !sh || ptr < sh->h_base || ptr >= sh->h_end ) {
199                 ber_memfree_x( ptr, NULL );
200         } else if ( (char *)ptr + p[-1] == sh->h_last ) {
201                 p--;
202                 sh->h_last = p;
203         }
204 }
205
206 void *
207 slap_sl_context( void *ptr )
208 {
209         struct slab_heap *sh = NULL;
210         void *ctx;
211
212         ctx = ldap_pvt_thread_pool_context();
213
214         ldap_pvt_thread_pool_getkey( ctx, (void *)slap_sl_mem_init, (void **)&sh, NULL );
215
216         if ( sh && ptr >= sh->h_base && ptr <= sh->h_end ) {
217                 return sh;
218         }
219         return NULL;
220 }