EFL 1.7 svn doobies
[profile/ivi/eina.git] / src / modules / mp / one_big / eina_one_big.c
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 <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
60 static int _eina_one_big_mp_log_dom = -1;
61
62 typedef struct _One_Big One_Big;
63 struct _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
85 static void *
86 eina_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
145 on_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
154 static void
155 eina_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
200 static void *
201 eina_one_big_realloc(__UNUSED__ void *data,
202                      __UNUSED__ void *element,
203                      __UNUSED__ unsigned int size)
204 {
205    return NULL;
206 }
207
208 static void *
209 eina_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
246 static void
247 eina_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
294 static 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
306 Eina_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
321 void 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
332 EINA_MODULE_INIT(one_big_init);
333 EINA_MODULE_SHUTDOWN(one_big_shutdown);
334
335 #endif /* ! EINA_STATIC_BUILD_ONE_BIG */
336