New test.
[mono.git] / mono / metadata / mempool.c
1 /*
2  * mempool.c: efficient memory allocation
3  *
4  * MonoMemPool is for fast allocation of memory. We free
5  * all memory when the pool is destroyed.
6  *
7  * Author:
8  *   Dietmar Maurer (dietmar@ximian.com)
9  *
10  * (C) 2001 Ximian, Inc.
11  */
12
13 #include <config.h>
14 #include <glib.h>
15 #include <string.h>
16
17 #include "mempool.h"
18
19 /*
20  * MonoMemPool is for fast allocation of memory. We free
21  * all memory when the pool is destroyed.
22  */
23
24 #define MEM_ALIGN 8
25
26 #define MONO_MEMPOOL_PAGESIZE 8192
27
28 #ifndef G_LIKELY
29 #define G_LIKELY(a) (a)
30 #define G_UNLIKELY(a) (a)
31 #endif
32
33 struct _MonoMemPool {
34         MonoMemPool *next;
35         gint rest;
36         guint8 *pos, *end;
37         guint32 size;
38         union {
39                 double pad; /* to assure proper alignment */
40                 guint32 allocated;
41         } d;
42 };
43
44 /**
45  * mono_mempool_new:
46  *
47  * Returns: a new memory pool.
48  */
49 MonoMemPool *
50 mono_mempool_new ()
51 {
52         MonoMemPool *pool = g_malloc (MONO_MEMPOOL_PAGESIZE);
53
54         pool->next = NULL;
55         pool->pos = (guint8*)pool + sizeof (MonoMemPool);
56         pool->end = pool->pos + MONO_MEMPOOL_PAGESIZE - sizeof (MonoMemPool);
57         pool->d.allocated = pool->size = MONO_MEMPOOL_PAGESIZE;
58         return pool;
59 }
60
61 /**
62  * mono_mempool_destroy:
63  * @pool: the memory pool to destroy
64  *
65  * Free all memory associated with this pool.
66  */
67 void
68 mono_mempool_destroy (MonoMemPool *pool)
69 {
70         MonoMemPool *p, *n;
71
72         p = pool;
73         while (p) {
74                 n = p->next;
75                 g_free (p);
76                 p = n;
77         }
78 }
79
80 /**
81  * mono_mempool_invalidate:
82  * @pool: the memory pool to invalidate
83  *
84  * Fill the memory associated with this pool to 0x2a (42). Useful for debugging.
85  */
86 void
87 mono_mempool_invalidate (MonoMemPool *pool)
88 {
89         MonoMemPool *p, *n;
90
91         p = pool;
92         while (p) {
93                 n = p->next;
94                 memset (p, 42, p->size);
95                 p = n;
96         }
97 }
98
99 void
100 mono_mempool_empty (MonoMemPool *pool)
101 {
102         pool->pos = (guint8*)pool + sizeof (MonoMemPool);
103         pool->end = pool->pos + MONO_MEMPOOL_PAGESIZE - sizeof (MonoMemPool);
104 }
105
106 /**
107  * mono_mempool_stats:
108  * @pool: the momory pool we need stats for
109  *
110  * Print a few stats about the mempool
111  */
112 void
113 mono_mempool_stats (MonoMemPool *pool)
114 {
115         MonoMemPool *p;
116         int count = 0;
117         guint32 still_free = 0;
118
119         p = pool;
120         while (p) {
121                 still_free += p->end - p->pos;
122                 p = p->next;
123                 count++;
124         }
125         if (pool) {
126                 g_print ("Mempool %p stats:\n", pool);
127                 g_print ("Total mem allocated: %d\n", pool->d.allocated);
128                 g_print ("Num chunks: %d\n", count);
129                 g_print ("Free memory: %d\n", still_free);
130         }
131 }
132
133 /**
134  * mono_mempool_alloc:
135  * @pool: the momory pool to destroy
136  * @size: size of the momory block
137  *
138  * Allocates a new block of memory in @pool.
139  *
140  * Returns: the address of a newly allocated memory block.
141  */
142 gpointer
143 mono_mempool_alloc (MonoMemPool *pool, guint size)
144 {
145         gpointer rval;
146         
147         size = (size + MEM_ALIGN - 1) & ~(MEM_ALIGN - 1);
148
149         rval = pool->pos;
150         pool->pos = (guint8*)rval + size;
151
152         if (G_UNLIKELY (pool->pos >= pool->end)) {
153                 pool->pos -= size;
154                 if (size >= 4096) {
155                         MonoMemPool *np = g_malloc (sizeof (MonoMemPool) + size);
156                         np->next = pool->next;
157                         pool->next = np;
158                         np->pos = (guint8*)np + sizeof (MonoMemPool);
159                         np->size = sizeof (MonoMemPool) + size;
160                         np->end = np->pos + np->size - sizeof (MonoMemPool);
161                         pool->d.allocated += sizeof (MonoMemPool) + size;
162                         return (guint8*)np + sizeof (MonoMemPool);
163                 } else {
164                         MonoMemPool *np = g_malloc (MONO_MEMPOOL_PAGESIZE);
165                         np->next = pool->next;
166                         pool->next = np;
167                         pool->pos = (guint8*)np + sizeof (MonoMemPool);
168                         np->pos = (guint8*)np + sizeof (MonoMemPool);
169                         np->size = MONO_MEMPOOL_PAGESIZE;
170                         np->end = np->pos;
171                         pool->end = pool->pos + MONO_MEMPOOL_PAGESIZE - sizeof (MonoMemPool);
172                         pool->d.allocated += MONO_MEMPOOL_PAGESIZE;
173
174                         rval = pool->pos;
175                         pool->pos += size;
176                 }
177         }
178
179         return rval;
180 }
181
182 /**
183  * mono_mempool_alloc0:
184  *
185  * same as mono_mempool_alloc, but fills memory with zero.
186  */
187 gpointer
188 mono_mempool_alloc0 (MonoMemPool *pool, guint size)
189 {
190         gpointer rval;
191         
192         size = (size + MEM_ALIGN - 1) & ~(MEM_ALIGN - 1);
193
194         rval = pool->pos;
195         pool->pos = (guint8*)rval + size;
196
197         if (G_UNLIKELY (pool->pos >= pool->end)) {
198                 rval = mono_mempool_alloc (pool, size);
199         }
200
201         memset (rval, 0, size);
202         return rval;
203 }
204
205 /**
206  * mono_mempool_contains_addr:
207  *
208  *  Determines whenever ADDR is inside the memory used by the mempool.
209  */
210 gboolean
211 mono_mempool_contains_addr (MonoMemPool *pool,
212                                                         gpointer addr)
213 {
214         MonoMemPool *p;
215
216         p = pool;
217         while (p) {
218                 if (addr > (gpointer)p && addr <= (gpointer)((guint8*)p + p->size))
219                         return TRUE;
220                 p = p->next;
221         }
222
223         return FALSE;
224 }
225
226 /**
227  * mono_mempool_strdup:
228  *
229  * Same as strdup, but allocates memory from the mempool.
230  * Returns: a pointer to the newly allocated string data inside the mempool.
231  */
232 char*
233 mono_mempool_strdup (MonoMemPool *pool,
234                                          const char *s)
235 {
236         int l;
237         char *res;
238
239         if (s == NULL)
240                 return NULL;
241
242         l = strlen (s);
243         res = mono_mempool_alloc (pool, l + 1);
244         memcpy (res, s, l + 1);
245
246         return res;
247 }
248
249 /**
250  * mono_mempool_get_allocated:
251  *
252  * Return the amount of memory allocated for this mempool.
253  */
254 guint32
255 mono_mempool_get_allocated (MonoMemPool *pool)
256 {
257         return pool->d.allocated;
258 }