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 #ifdef EFL_DEBUG_THREADS
59 typedef struct _Chained_Mempool Chained_Mempool;
60 struct _Chained_Mempool
69 #ifdef EFL_HAVE_THREADS
70 #ifdef EFL_DEBUG_THREADS
73 # ifdef EFL_HAVE_POSIX_THREADS
74 pthread_mutex_t mutex;
81 typedef struct _Chained_Pool Chained_Pool;
92 static inline Chained_Pool *
93 _eina_chained_mp_pool_new(Chained_Mempool *pool)
99 p = malloc(pool->alloc_size);
102 eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
106 ptr = (unsigned char *)p + eina_mempool_alignof(sizeof(Chained_Pool));
111 p->limit = ptr + pool->item_alloc * pool->pool_size;
116 _eina_chained_mp_pool_free(Chained_Pool *p)
122 eina_chained_mempool_malloc(void *data, __UNUSED__ unsigned int size)
124 Chained_Mempool *pool = data;
125 Chained_Pool *p = NULL;
128 #ifdef EFL_HAVE_THREADS
129 if (_threads_activated)
131 # ifdef EFL_HAVE_POSIX_THREADS
132 pthread_mutex_lock(&pool->mutex);
134 WaitForSingleObject(pool->mutex, INFINITE);
137 #ifdef EFL_DEBUG_THREADS
139 assert(pool->self == pthread_self());
143 // look 4 pool from 2nd bucket on
144 EINA_INLIST_FOREACH(pool->first, p)
146 // base is not NULL - has a free slot
147 if (p->base || p->last)
149 pool->first = eina_inlist_demote(pool->first, EINA_INLIST_GET(p));
154 // we have reached the end of the list - no free pools
157 p = _eina_chained_mp_pool_new(pool);
160 #ifdef EFL_HAVE_PTHREAD
161 if (_threads_activated)
163 # ifdef EFL_HAVE_POSIX_THREADS
164 pthread_mutex_unlock(&pool->mutex);
166 ReleaseMutex(pool->mutex);
173 pool->first = eina_inlist_prepend(pool->first, EINA_INLIST_GET(p));
179 p->last += pool->item_alloc;
180 if (p->last >= p->limit)
184 // Request a free pointer
185 mem = eina_trash_pop(&p->base);
187 // move to end - it just filled up
188 if (!p->base && !p->last)
189 pool->first = eina_inlist_demote(pool->first, EINA_INLIST_GET(p));
194 #ifdef EFL_HAVE_THREADS
195 if (_threads_activated)
197 # ifdef EFL_HAVE_POSIX_THREADS
198 pthread_mutex_unlock(&pool->mutex);
200 ReleaseMutex(pool->mutex);
209 eina_chained_mempool_free(void *data, void *ptr)
211 Chained_Mempool *pool = data;
216 psize = pool->group_size;
219 #ifdef EFL_HAVE_THREADS
220 if (_threads_activated)
222 # ifdef EFL_HAVE_POSIX_THREADS
223 pthread_mutex_lock(&pool->mutex);
225 WaitForSingleObject(pool->mutex, INFINITE);
228 #ifdef EFL_DEBUG_THREADS
230 assert(pool->self == pthread_self());
234 EINA_INLIST_FOREACH(pool->first, p)
236 // Could the pointer be inside that pool
237 if ((unsigned char*) ptr < p->limit)
240 pmem = (void *)(((unsigned char *)p) + sizeof(Chained_Pool));
241 // is it in pool mem?
244 // freed node points to prev free node
245 eina_trash_push(&p->base, ptr);
246 // next free node is now the one we freed
252 pool->first = eina_inlist_remove(pool->first, EINA_INLIST_GET(p));
253 _eina_chained_mp_pool_free(p);
257 pool->first = eina_inlist_promote(pool->first, EINA_INLIST_GET(p));
264 #ifdef EFL_HAVE_THREADS
265 if (_threads_activated)
267 # ifdef EFL_HAVE_POSIX_THREADS
268 pthread_mutex_unlock(&pool->mutex);
270 ReleaseMutex(pool->mutex);
277 eina_chained_mempool_realloc(__UNUSED__ void *data,
278 __UNUSED__ void *element,
279 __UNUSED__ unsigned int size)
285 eina_chained_mempool_init(const char *context,
286 __UNUSED__ const char *option,
293 length = context ? strlen(context) + 1 : 0;
295 mp = calloc(1, sizeof(Chained_Mempool) + length);
299 item_size = va_arg(args, int);
300 mp->pool_size = va_arg(args, int);
304 mp->name = (const char *)(mp + 1);
305 memcpy((char *)mp->name, context, length);
308 mp->item_alloc = eina_mempool_alignof(item_size);
309 mp->group_size = mp->item_alloc * mp->pool_size;
310 mp->alloc_size = mp->group_size + eina_mempool_alignof(sizeof(Chained_Pool));
311 #ifdef EFL_DEBUG_THREADS
312 mp->self = pthread_self();
315 #ifdef EFL_HAVE_THREADS
316 # ifdef EFL_HAVE_POSIX_THREADS
317 pthread_mutex_init(&mp->mutex, NULL);
319 mp->mutex = CreateMutex(NULL, FALSE, NULL);
327 eina_chained_mempool_shutdown(void *data)
331 mp = (Chained_Mempool *)data;
335 Chained_Pool *p = (Chained_Pool *)mp->first;
339 INF("Bad news we are destroying not an empty mempool [%s]\n",
344 mp->first = eina_inlist_remove(mp->first, mp->first);
345 _eina_chained_mp_pool_free(p);
348 #ifdef EFL_HAVE_THREADS
349 #ifdef EFL_DEBUG_THREADS
350 assert(mp->self == pthread_self());
352 # ifdef EFL_HAVE_POSIX_THREADS
353 pthread_mutex_destroy(&mp->mutex);
355 CloseHandle(mp->mutex);
362 static Eina_Mempool_Backend _eina_chained_mp_backend = {
364 &eina_chained_mempool_init,
365 &eina_chained_mempool_free,
366 &eina_chained_mempool_malloc,
367 &eina_chained_mempool_realloc,
370 &eina_chained_mempool_shutdown
373 Eina_Bool chained_init(void)
376 _eina_mempool_log_dom = eina_log_domain_register("eina_mempool",
377 EINA_LOG_COLOR_DEFAULT);
378 if (_eina_mempool_log_dom < 0)
380 EINA_LOG_ERR("Could not register log domain: eina_mempool");
385 return eina_mempool_register(&_eina_chained_mp_backend);
388 void chained_shutdown(void)
390 eina_mempool_unregister(&_eina_chained_mp_backend);
392 eina_log_domain_unregister(_eina_mempool_log_dom);
393 _eina_mempool_log_dom = -1;
397 #ifndef EINA_STATIC_BUILD_CHAINED_POOL
399 EINA_MODULE_INIT(chained_init);
400 EINA_MODULE_SHUTDOWN(chained_shutdown);
402 #endif /* ! EINA_STATIC_BUILD_CHAINED_POOL */