aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/eina/src/modules/mp/one_big/eina_one_big.c
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/eina/src/modules/mp/one_big/eina_one_big.c')
-rw-r--r--libraries/eina/src/modules/mp/one_big/eina_one_big.c336
1 files changed, 336 insertions, 0 deletions
diff --git a/libraries/eina/src/modules/mp/one_big/eina_one_big.c b/libraries/eina/src/modules/mp/one_big/eina_one_big.c
new file mode 100644
index 0000000..dadec65
--- /dev/null
+++ b/libraries/eina/src/modules/mp/one_big/eina_one_big.c
@@ -0,0 +1,336 @@
1/* EINA - EFL data type library
2 * Copyright (C) 2010 Cedric BAIL, Vincent Torri
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library;
16 * if not, see <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H
20# include "config.h"
21#endif
22
23#include <stdlib.h>
24#include <string.h>
25
26#ifdef EFL_HAVE_POSIX_THREADS
27# include <pthread.h>
28#endif
29
30#include <assert.h>
31
32#ifdef EFL_HAVE_WIN32_THREADS
33# define WIN32_LEAN_AND_MEAN
34# include <windows.h>
35# undef WIN32_LEAN_AND_MEAN
36#endif
37
38#include "eina_mempool.h"
39#include "eina_trash.h"
40#include "eina_inlist.h"
41#include "eina_log.h"
42#include "eina_lock.h"
43
44#ifndef NVALGRIND
45# include <valgrind/memcheck.h>
46#endif
47
48#include "eina_private.h"
49
50#ifdef INF
51#undef INF
52#endif
53#define INF(...) EINA_LOG_DOM_INFO(_eina_mempool_log_dom, __VA_ARGS__)
54
55#ifdef WRN
56#undef WRN
57#endif
58#define WRN(...) EINA_LOG_DOM_WARN(_eina_one_big_mp_log_dom, __VA_ARGS__)
59
60static int _eina_one_big_mp_log_dom = -1;
61
62typedef struct _One_Big One_Big;
63struct _One_Big
64{
65 const char *name;
66
67 int item_size;
68
69 int usage;
70 int over;
71
72 int served;
73 int max;
74 unsigned char *base;
75
76 Eina_Trash *empty;
77 Eina_Inlist *over_list;
78
79#ifdef EFL_DEBUG_THREADS
80 pthread_t self;
81#endif
82 Eina_Lock mutex;
83};
84
85static void *
86eina_one_big_malloc(void *data, __UNUSED__ unsigned int size)
87{
88 One_Big *pool = data;
89 unsigned char *mem = NULL;
90
91 if (!eina_lock_take(&pool->mutex))
92 {
93#ifdef EFL_DEBUG_THREADS
94 assert(pthread_equal(pool->self, pthread_self()));
95#endif
96 }
97
98 if (pool->empty)
99 {
100#ifndef NVALGRIND
101 VALGRIND_MAKE_MEM_DEFINED(pool->empty, pool->item_size);
102#endif
103 mem = eina_trash_pop(&pool->empty);
104 pool->usage++;
105 goto on_exit;
106 }
107
108 if (!pool->base)
109 {
110 pool->base = malloc(pool->item_size * pool->max);
111 if (!pool->base)
112 {
113 eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
114 goto retry_smaller;
115 }
116#ifndef NVALGRIND
117 VALGRIND_MAKE_MEM_NOACCESS(pool->base, pool->item_size * pool->max);
118#endif
119 }
120
121 if (pool->served < pool->max)
122 {
123 mem = pool->base + (pool->served++ *pool->item_size);
124 pool->usage++;
125 goto on_exit;
126 }
127
128 retry_smaller:
129 eina_error_set(0);
130 mem = malloc(sizeof(Eina_Inlist) + pool->item_size);
131 if (!mem)
132 eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
133 else
134 {
135 pool->over++;
136 memset(mem, 0, sizeof(Eina_Inlist));
137 pool->over_list = eina_inlist_append(pool->over_list,
138 (Eina_Inlist *)mem);
139 mem = ((unsigned char *)mem) + sizeof(Eina_Inlist);
140 }
141#ifndef NVALGRIND
142 VALGRIND_MAKE_MEM_NOACCESS(mem, pool->item_size);
143#endif
144
145on_exit:
146 eina_lock_release(&pool->mutex);
147
148#ifndef NVALGRIND
149 VALGRIND_MEMPOOL_ALLOC(pool, mem, pool->item_size);
150#endif
151 return mem;
152}
153
154static void
155eina_one_big_free(void *data, void *ptr)
156{
157 One_Big *pool = data;
158
159 if (!eina_lock_take(&pool->mutex))
160 {
161#ifdef EFL_DEBUG_THREADS
162 assert(pthread_equal(pool->self, pthread_self()));
163#endif
164 }
165
166 if ((void *)pool->base <= ptr
167 && ptr < (void *)(pool->base + (pool->max * pool->item_size)))
168 {
169 eina_trash_push(&pool->empty, ptr);
170 pool->usage--;
171 }
172 else
173 {
174#ifndef NDEBUG
175 Eina_Inlist *it;
176#endif
177 Eina_Inlist *il;
178
179 il = (Eina_Inlist *)(((unsigned char *)ptr) - sizeof(Eina_Inlist));
180
181#ifndef NDEBUG
182 for (it = pool->over_list; it != NULL; it = it->next)
183 if (it == il) break;
184
185 assert(it != NULL);
186#endif
187
188 pool->over_list = eina_inlist_remove(pool->over_list, il);
189 free(il);
190 pool->over--;
191 }
192
193#ifndef NVALGRIND
194 VALGRIND_MEMPOOL_FREE(pool, ptr);
195#endif
196
197 eina_lock_release(&pool->mutex);
198}
199
200static void *
201eina_one_big_realloc(__UNUSED__ void *data,
202 __UNUSED__ void *element,
203 __UNUSED__ unsigned int size)
204{
205 return NULL;
206}
207
208static void *
209eina_one_big_init(const char *context,
210 __UNUSED__ const char *option,
211 va_list args)
212{
213 One_Big *pool;
214 int item_size;
215 size_t length;
216
217 length = context ? strlen(context) + 1 : 0;
218
219 pool = calloc(1, sizeof (One_Big) + length);
220 if (!pool)
221 return NULL;
222
223 item_size = va_arg(args, int);
224
225 pool->item_size = eina_mempool_alignof(item_size);
226 pool->max = va_arg(args, int);
227
228 if (length)
229 {
230 pool->name = (const char *)(pool + 1);
231 memcpy((char *)pool->name, context, length);
232 }
233
234#ifdef EFL_DEBUG_THREADS
235 pool->self = pthread_self();
236#endif
237 eina_lock_new(&pool->mutex);
238
239#ifndef NVALGRIND
240 VALGRIND_CREATE_MEMPOOL(pool, 0, 1);
241#endif
242
243 return pool;
244}
245
246static void
247eina_one_big_shutdown(void *data)
248{
249 One_Big *pool = data;
250
251 if (!pool) return;
252 if (!eina_lock_take(&pool->mutex))
253 {
254#ifdef EFL_DEBUG_THREADS
255 assert(pthread_equal(pool->self, pthread_self()));
256#endif
257 }
258
259 if (pool->over > 0)
260 {
261// FIXME: should we warn here? one_big mempool exceeded its alloc and now
262// mempool is cleaning up the mess created. be quiet for now as we were before
263// but edje seems to be a big offender at the moment! bad cedric! :)
264// WRN(
265// "Pool [%s] over by %i. cleaning up for you",
266// pool->name, pool->over);
267 while (pool->over_list)
268 {
269 Eina_Inlist *il = pool->over_list;
270 pool->over_list = eina_inlist_remove(pool->over_list, il);
271 free(il);
272 pool->over--;
273 }
274 }
275 if (pool->over > 0)
276 {
277 WRN(
278 "Pool [%s] still over by %i\n",
279 pool->name, pool->over);
280 }
281
282#ifndef NVALGRIND
283 VALGRIND_DESTROY_MEMPOOL(pool);
284#endif
285
286 if (pool->base) free(pool->base);
287
288 eina_lock_release(&pool->mutex);
289 eina_lock_free(&pool->mutex);
290 free(pool);
291}
292
293
294static Eina_Mempool_Backend _eina_one_big_mp_backend = {
295 "one_big",
296 &eina_one_big_init,
297 &eina_one_big_free,
298 &eina_one_big_malloc,
299 &eina_one_big_realloc,
300 NULL,
301 NULL,
302 &eina_one_big_shutdown,
303 NULL
304};
305
306Eina_Bool one_big_init(void)
307{
308#ifdef DEBUG
309 _eina_one_big_mp_log_dom = eina_log_domain_register("eina_one_big_mempool",
310 EINA_LOG_COLOR_DEFAULT);
311 if (_eina_one_big_mp_log_dom < 0)
312 {
313 EINA_LOG_ERR("Could not register log domain: eina_one_big_mempool");
314 return EINA_FALSE;
315 }
316
317#endif
318 return eina_mempool_register(&_eina_one_big_mp_backend);
319}
320
321void one_big_shutdown(void)
322{
323 eina_mempool_unregister(&_eina_one_big_mp_backend);
324#ifdef DEBUG
325 eina_log_domain_unregister(_eina_one_big_mp_log_dom);
326 _eina_one_big_mp_log_dom = -1;
327#endif
328}
329
330#ifndef EINA_STATIC_BUILD_ONE_BIG
331
332EINA_MODULE_INIT(one_big_init);
333EINA_MODULE_SHUTDOWN(one_big_shutdown);
334
335#endif /* ! EINA_STATIC_BUILD_ONE_BIG */
336