more docs
[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 = (char *)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 = (char *)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, *n;
116         int count = 0;
117         guint32 still_free = 0;
118
119         p = pool;
120         while (p) {
121                 still_free += p->end - p->pos;
122                 n = p->next;
123                 p = n;
124                 count++;
125         }
126         if (pool) {
127                 g_print ("Mempool %p stats:\n", pool);
128                 g_print ("Total mem allocated: %d\n", pool->d.allocated);
129                 g_print ("Num chunks: %d\n", count);
130                 g_print ("Free memory: %d\n", still_free);
131         }
132 }
133
134 /**
135  * mono_mempool_alloc:
136  * @pool: the momory pool to destroy
137  * @size: size of the momory block
138  *
139  * Allocates a new block of memory in @pool.
140  *
141  * Returns: the address of a newly allocated memory block.
142  */
143 gpointer
144 mono_mempool_alloc (MonoMemPool *pool, guint size)
145 {
146         gpointer rval;
147         
148         size = (size + MEM_ALIGN - 1) & ~(MEM_ALIGN - 1);
149
150         rval = pool->pos;
151         pool->pos = (char*)rval + size;
152
153         if (G_UNLIKELY (pool->pos >= pool->end)) {
154                 pool->pos -= size;
155                 if (size >= 4096) {
156                         MonoMemPool *np = g_malloc (sizeof (MonoMemPool) + size);
157                         np->next = pool->next;
158                         pool->next = np;
159                         np->size = sizeof (MonoMemPool) + size;
160                         pool->d.allocated += sizeof (MonoMemPool) + size;
161                         return (char *)np + sizeof (MonoMemPool);
162                 } else {
163                         MonoMemPool *np = g_malloc (MONO_MEMPOOL_PAGESIZE);
164                         np->next = pool->next;
165                         pool->next = np;
166                         pool->pos = (char *)np + sizeof (MonoMemPool);
167                         np->size = MONO_MEMPOOL_PAGESIZE;
168                         pool->end = pool->pos + MONO_MEMPOOL_PAGESIZE - sizeof (MonoMemPool);
169                         pool->d.allocated += MONO_MEMPOOL_PAGESIZE;
170
171                         rval = pool->pos;
172                         pool->pos += size;
173                 }
174         }
175
176         return rval;
177 }
178
179 /**
180  * mono_mempool_alloc0:
181  *
182  * same as mono_mempool_alloc, but fills memory with zero.
183  */
184 gpointer
185 mono_mempool_alloc0 (MonoMemPool *pool, guint size)
186 {
187         gpointer rval;
188         
189         size = (size + MEM_ALIGN - 1) & ~(MEM_ALIGN - 1);
190
191         rval = pool->pos;
192         pool->pos = (char*)rval + size;
193
194         if (G_UNLIKELY (pool->pos >= pool->end)) {
195                 rval = mono_mempool_alloc (pool, size);
196         }
197
198         memset (rval, 0, size);
199         return rval;
200 }
201
202 /**
203  * mono_mempool_contains_addr:
204  *
205  *  Determines whenever ADDR is inside the memory used by the mempool.
206  */
207 gboolean
208 mono_mempool_contains_addr (MonoMemPool *pool,
209                                                         gpointer addr)
210 {
211         MonoMemPool *p;
212
213         p = pool;
214         while (p) {
215                 if (addr > (gpointer)p && addr <= (gpointer)((guint8*)p + p->size))
216                         return TRUE;
217                 p = p->next;
218         }
219
220         return FALSE;
221 }