1 /* EINA - EFL data type library
2 * Copyright (C) 2008-2010 Cedric BAIL, Vincent Torri
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.
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.
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/>.
26 #ifdef EFL_HAVE_POSIX_THREADS
30 #ifdef EFL_HAVE_WIN32_THREADS
31 # define WIN32_LEAN_AND_MEAN
33 # undef WIN32_LEAN_AND_MEAN
36 #include "eina_inlist.h"
37 #include "eina_error.h"
38 #include "eina_module.h"
39 #include "eina_mempool.h"
40 #include "eina_trash.h"
42 #include "eina_private.h"
47 static int _eina_mempool_log_dom = -1;
52 #define INF(...) EINA_LOG_DOM_INFO(_eina_mempool_log_dom, __VA_ARGS__)
55 typedef struct _Chained_Mempool Chained_Mempool;
56 struct _Chained_Mempool
65 #ifdef EFL_HAVE_THREADS
66 # ifdef EFL_HAVE_POSIX_THREADS
67 pthread_mutex_t mutex;
74 typedef struct _Chained_Pool Chained_Pool;
85 static inline Chained_Pool *
86 _eina_chained_mp_pool_new(Chained_Mempool *pool)
92 p = malloc(pool->alloc_size);
95 eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
99 ptr = (unsigned char *)p + eina_mempool_alignof(sizeof(Chained_Pool));
104 p->limit = ptr + pool->item_alloc * pool->pool_size;
109 _eina_chained_mp_pool_free(Chained_Pool *p)
115 eina_chained_mempool_malloc(void *data, __UNUSED__ unsigned int size)
117 Chained_Mempool *pool = data;
118 Chained_Pool *p = NULL;
121 #ifdef EFL_HAVE_THREADS
122 if (_threads_activated)
124 # ifdef EFL_HAVE_POSIX_THREADS
125 pthread_mutex_lock(&pool->mutex);
127 WaitForSingleObject(pool->mutex, INFINITE);
132 // look 4 pool from 2nd bucket on
133 EINA_INLIST_FOREACH(pool->first, p)
135 // base is not NULL - has a free slot
136 if (p->base || p->last)
138 pool->first = eina_inlist_demote(pool->first, EINA_INLIST_GET(p));
143 // we have reached the end of the list - no free pools
146 p = _eina_chained_mp_pool_new(pool);
149 #ifdef EFL_HAVE_PTHREAD
150 if (_threads_activated)
152 # ifdef EFL_HAVE_POSIX_THREADS
153 pthread_mutex_unlock(&pool->mutex);
155 ReleaseMutex(pool->mutex);
162 pool->first = eina_inlist_prepend(pool->first, EINA_INLIST_GET(p));
168 p->last += pool->item_alloc;
169 if (p->last >= p->limit)
173 // Request a free pointer
174 mem = eina_trash_pop(&p->base);
176 // move to end - it just filled up
177 if (!p->base && !p->last)
178 pool->first = eina_inlist_demote(pool->first, EINA_INLIST_GET(p));
183 #ifdef EFL_HAVE_THREADS
184 if (_threads_activated)
186 # ifdef EFL_HAVE_POSIX_THREADS
187 pthread_mutex_unlock(&pool->mutex);
189 ReleaseMutex(pool->mutex);
198 eina_chained_mempool_free(void *data, void *ptr)
200 Chained_Mempool *pool = data;
205 psize = pool->group_size;
208 #ifdef EFL_HAVE_THREADS
209 if (_threads_activated)
211 # ifdef EFL_HAVE_POSIX_THREADS
212 pthread_mutex_lock(&pool->mutex);
214 WaitForSingleObject(pool->mutex, INFINITE);
219 EINA_INLIST_FOREACH(pool->first, p)
221 // Could the pointer be inside that pool
225 pmem = (void *)(((unsigned char *)p) + sizeof(Chained_Pool));
226 // is it in pool mem?
229 // freed node points to prev free node
230 eina_trash_push(&p->base, ptr);
231 // next free node is now the one we freed
237 pool->first = eina_inlist_remove(pool->first, EINA_INLIST_GET(p));
238 _eina_chained_mp_pool_free(p);
242 pool->first = eina_inlist_promote(pool->first, EINA_INLIST_GET(p));
249 #ifdef EFL_HAVE_THREADS
250 if (_threads_activated)
252 # ifdef EFL_HAVE_POSIX_THREADS
253 pthread_mutex_unlock(&pool->mutex);
255 ReleaseMutex(pool->mutex);
262 eina_chained_mempool_realloc(__UNUSED__ void *data,
263 __UNUSED__ void *element,
264 __UNUSED__ unsigned int size)
270 eina_chained_mempool_init(const char *context,
271 __UNUSED__ const char *option,
278 length = context ? strlen(context) + 1 : 0;
280 mp = calloc(1, sizeof(Chained_Mempool) + length);
284 item_size = va_arg(args, int);
285 mp->pool_size = va_arg(args, int);
289 mp->name = (const char *)(mp + 1);
290 memcpy((char *)mp->name, context, length);
293 mp->item_alloc = eina_mempool_alignof(item_size);
294 mp->group_size = mp->item_alloc * mp->pool_size;
295 mp->alloc_size = mp->group_size + eina_mempool_alignof(sizeof(Chained_Pool));
297 #ifdef EFL_HAVE_THREADS
298 # ifdef EFL_HAVE_POSIX_THREADS
299 pthread_mutex_init(&mp->mutex, NULL);
301 mp->mutex = CreateMutex(NULL, FALSE, NULL);
309 eina_chained_mempool_shutdown(void *data)
313 mp = (Chained_Mempool *)data;
317 Chained_Pool *p = (Chained_Pool *)mp->first;
321 INF("Bad news we are destroying not an empty mempool [%s]\n",
326 mp->first = eina_inlist_remove(mp->first, mp->first);
327 _eina_chained_mp_pool_free(p);
330 #ifdef EFL_HAVE_THREADS
331 # ifdef EFL_HAVE_POSIX_THREADS
332 pthread_mutex_destroy(&mp->mutex);
334 CloseHandle(mp->mutex);
341 static Eina_Mempool_Backend _eina_chained_mp_backend = {
343 &eina_chained_mempool_init,
344 &eina_chained_mempool_free,
345 &eina_chained_mempool_malloc,
346 &eina_chained_mempool_realloc,
349 &eina_chained_mempool_shutdown
352 Eina_Bool chained_init(void)
355 _eina_mempool_log_dom = eina_log_domain_register("eina_mempool",
356 EINA_LOG_COLOR_DEFAULT);
357 if (_eina_mempool_log_dom < 0)
359 EINA_LOG_ERR("Could not register log domain: eina_mempool");
364 return eina_mempool_register(&_eina_chained_mp_backend);
367 void chained_shutdown(void)
369 eina_mempool_unregister(&_eina_chained_mp_backend);
371 eina_log_domain_unregister(_eina_mempool_log_dom);
372 _eina_mempool_log_dom = -1;
376 #ifndef EINA_STATIC_BUILD_CHAINED_POOL
378 EINA_MODULE_INIT(chained_init);
379 EINA_MODULE_SHUTDOWN(chained_shutdown);
381 #endif /* ! EINA_STATIC_BUILD_CHAINED_POOL */