1 /* EIO - EFL data type library
2 * Copyright (C) 2010 Enlightenment Developers:
3 * Cedric Bail <cedric.bail@free.fr>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library;
17 * if not, see <http://www.gnu.org/licenses/>.
18 */
19 #include <Efreet_Mime.h>
20 #include "eio_private.h"
21
22 /*============================================================================*
23 * Local *
24 *============================================================================*/
25
26 static Eio_Version _version = { VMAJ, VMIN, VMIC, VREV };
27 EAPI Eio_Version *eio_version = &_version;
28
29 /**
30 * @cond LOCAL
31 */
32
33 /* Progress pool */
34 typedef struct _Eio_Alloc_Pool Eio_Alloc_Pool;
35
36 struct _Eio_Alloc_Pool
37 {
38 Eina_Lock lock;
39
40 Eina_Trash *trash;
41 size_t mem_size;
42 int count;
43 };
44
45 static int _eio_init_count = 0;
46 int _eio_log_dom_global = -1;
47
48 static Eio_Alloc_Pool progress_pool;
49 static Eio_Alloc_Pool direct_info_pool;
50 static Eio_Alloc_Pool char_pool;
51 static Eio_Alloc_Pool associate_pool;
52
53 static size_t memory_pool_limit = -1;
54 static size_t memory_pool_usage = 0;
55 static Eina_Spinlock memory_pool_lock;
56 static Eina_Lock memory_pool_mutex;
57 static Eina_Condition memory_pool_cond;
58 static Eina_Bool memory_pool_suspended = 1;
59 static Efl_Io_Manager *io_manager = NULL;
60
61 static void *
_eio_pool_malloc(Eio_Alloc_Pool * pool)62 _eio_pool_malloc(Eio_Alloc_Pool *pool)
63 {
64 void *result = NULL;
65
66 if (pool->count)
67 {
68 eina_lock_take(&(pool->lock));
69 result = eina_trash_pop(&pool->trash);
70 if (result) pool->count--;
71 eina_lock_release(&(pool->lock));
72 }
73
74 if (!result)
75 {
76 result = malloc(pool->mem_size);
77 eina_spinlock_take(&memory_pool_lock);
78 if (result) memory_pool_usage += pool->mem_size;
79 eina_spinlock_release(&memory_pool_lock);
80 }
81 return result;
82 }
83
84 static void
_eio_pool_free(Eio_Alloc_Pool * pool,void * data)85 _eio_pool_free(Eio_Alloc_Pool *pool, void *data)
86 {
87 if (pool->count >= EIO_PROGRESS_LIMIT)
88 {
89 eina_spinlock_take(&memory_pool_lock);
90 memory_pool_usage -= pool->mem_size;
91 eina_spinlock_release(&memory_pool_lock);
92 free(data);
93
94 if (memory_pool_limit > 0 &&
95 memory_pool_usage < memory_pool_limit)
96 {
97 eina_lock_take(&(memory_pool_mutex));
98 if (memory_pool_suspended)
99 eina_condition_broadcast(&(memory_pool_cond));
100 eina_lock_release(&(memory_pool_mutex));
101 }
102 }
103 else
104 {
105 eina_lock_take(&(pool->lock));
106 eina_trash_push(&pool->trash, data);
107 pool->count++;
108 eina_lock_release(&(pool->lock));
109 }
110 }
111
112 /**
113 * @endcond
114 */
115
116 /*============================================================================*
117 * Global *
118 *============================================================================*/
119
120 /**
121 * @cond LOCAL
122 */
123
124 Eio_Progress *
eio_progress_malloc(void)125 eio_progress_malloc(void)
126 {
127 return _eio_pool_malloc(&progress_pool);
128 }
129
130 void
eio_progress_free(Eio_Progress * data)131 eio_progress_free(Eio_Progress *data)
132 {
133 eina_stringshare_del(data->source);
134 eina_stringshare_del(data->dest);
135
136 _eio_pool_free(&progress_pool, data);
137 }
138
139 void
eio_progress_send(Ecore_Thread * thread,Eio_File_Progress * op,long long current,long long max)140 eio_progress_send(Ecore_Thread *thread, Eio_File_Progress *op, long long current, long long max)
141 {
142 Eio_Progress *progress;
143
144 if (op->progress_cb == NULL)
145 return;
146
147 progress = eio_progress_malloc();
148 if (!progress) return;
149
150 progress->op = op->op;
151 progress->current = current;
152 progress->max = max;
153 progress->percent = max ? (float) current * 100.0 / (float) max : 100;
154 progress->source = eina_stringshare_ref(op->source);
155 progress->dest = eina_stringshare_ref(op->dest);
156
157 ecore_thread_feedback(thread, progress);
158 }
159
160 Eio_File_Direct_Info *
eio_direct_info_malloc(void)161 eio_direct_info_malloc(void)
162 {
163 return _eio_pool_malloc(&direct_info_pool);
164 }
165
166 void
eio_direct_info_free(Eio_File_Direct_Info * data)167 eio_direct_info_free(Eio_File_Direct_Info *data)
168 {
169 _eio_pool_free(&direct_info_pool, data);
170 }
171
172 Eio_File_Char *
eio_char_malloc(void)173 eio_char_malloc(void)
174 {
175 return _eio_pool_malloc(&char_pool);
176 }
177
178 void
eio_char_free(Eio_File_Char * data)179 eio_char_free(Eio_File_Char *data)
180 {
181 _eio_pool_free(&char_pool, data);
182 }
183
184 Eio_File_Associate *
eio_associate_malloc(const void * data,Eina_Free_Cb free_cb)185 eio_associate_malloc(const void *data, Eina_Free_Cb free_cb)
186 {
187 Eio_File_Associate *tmp;
188
189 tmp = _eio_pool_malloc(&associate_pool);
190 if (!tmp) return tmp;
191
192 tmp->data = (void*) data;
193 tmp->free_cb = free_cb;
194
195 return tmp;
196 }
197
198 void
eio_associate_free(void * data)199 eio_associate_free(void *data)
200 {
201 Eio_File_Associate *tmp;
202
203 if (!data) return;
204
205 tmp = data;
206 if (tmp->free_cb)
207 tmp->free_cb(tmp->data);
208 _eio_pool_free(&associate_pool, tmp);
209 }
210
211 Eina_List *
eio_pack_send(Ecore_Thread * thread,Eina_List * pack,double * start)212 eio_pack_send(Ecore_Thread *thread, Eina_List *pack, double *start)
213 {
214 double current;
215
216 current = ecore_time_get();
217 if (current - *start > EIO_PACKED_TIME)
218 {
219 *start = current;
220 ecore_thread_feedback(thread, pack);
221 return NULL;
222 }
223
224 if (memory_pool_limit > 0 &&
225 memory_pool_usage > memory_pool_limit)
226 {
227 eina_lock_take(&(memory_pool_mutex));
228 memory_pool_suspended = EINA_TRUE;
229 eina_condition_wait(&(memory_pool_cond));
230 memory_pool_suspended = EINA_FALSE;
231 eina_lock_release(&(memory_pool_mutex));
232 }
233
234 return pack;
235 }
236
237 void *
eio_common_alloc(size_t size)238 eio_common_alloc(size_t size)
239 {
240 return calloc(1, size);
241 }
242
243 void
eio_common_free(Eio_File * common)244 eio_common_free(Eio_File *common)
245 {
246 free(common);
247 }
248
249 // For now use a list for simplicity and we should not have that many
250 // pending request
251 static Eina_List *tracked_thread = NULL;
252
253 void
eio_file_register(Eio_File * common)254 eio_file_register(Eio_File *common)
255 {
256 tracked_thread = eina_list_append(tracked_thread, common);
257 }
258
259 void
eio_file_unregister(Eio_File * common)260 eio_file_unregister(Eio_File *common)
261 {
262 tracked_thread = eina_list_remove(tracked_thread, common);
263 common->thread = NULL;
264 }
265
266 /**
267 * @endcond
268 */
269
270
271 /*============================================================================*
272 * API *
273 *============================================================================*/
274
275 EAPI int
eio_init(void)276 eio_init(void)
277 {
278 if (++_eio_init_count != 1)
279 return _eio_init_count;
280
281 if (!eina_init())
282 {
283 fprintf(stderr, "Eio can not initialize Eina\n");
284 return --_eio_init_count;
285 }
286
287 _eio_log_dom_global = eina_log_domain_register("eio", EIO_DEFAULT_LOG_COLOR);
288 if (_eio_log_dom_global < 0)
289 {
290 EINA_LOG_ERR("Eio can not create a general log domain.");
291 goto shutdown_eina;
292 }
293
294 if (!ecore_init())
295 {
296 ERR("Can not initialize Ecore\n");
297 goto unregister_log_domain;
298 }
299
300 memset(&progress_pool, 0, sizeof(progress_pool));
301 memset(&direct_info_pool, 0, sizeof(direct_info_pool));
302 memset(&char_pool, 0, sizeof(char_pool));
303 memset(&associate_pool, 0, sizeof(associate_pool));
304
305 eina_lock_new(&(progress_pool.lock));
306 progress_pool.mem_size = sizeof (Eio_Progress);
307 eina_lock_new(&(direct_info_pool.lock));
308 direct_info_pool.mem_size = sizeof (Eio_File_Direct_Info);
309 eina_lock_new(&(char_pool.lock));
310 char_pool.mem_size = sizeof (Eio_File_Char);
311 eina_lock_new(&(associate_pool.lock));
312 associate_pool.mem_size = sizeof (Eio_File_Associate);
313
314 eina_spinlock_new(&(memory_pool_lock));
315 eina_lock_new(&(memory_pool_mutex));
316 eina_condition_new(&(memory_pool_cond), &(memory_pool_mutex));
317
318 eio_monitor_init();
319
320 efreet_mime_init();
321
322 io_manager = efl_add(EFL_IO_MANAGER_CLASS, efl_main_loop_get());
323 efl_provider_register(efl_main_loop_get(), EFL_IO_MANAGER_CLASS, io_manager);
324
325 eina_log_timing(_eio_log_dom_global,
326 EINA_LOG_STATE_STOP,
327 EINA_LOG_STATE_INIT);
328
329 return _eio_init_count;
330
331 unregister_log_domain:
332 eina_log_domain_unregister(_eio_log_dom_global);
333 _eio_log_dom_global = -1;
334 shutdown_eina:
335 eina_shutdown();
336 return --_eio_init_count;
337 }
338
339 EAPI int
eio_shutdown(void)340 eio_shutdown(void)
341 {
342 Eio_File_Direct_Info *info;
343 Eio_File_Char *cin;
344 Eio_Progress *pg;
345 Eio_File_Associate *asso;
346 Eio_File *f;
347 Eina_List *l;
348
349 if (_eio_init_count <= 0)
350 {
351 ERR("Init count not greater than 0 in shutdown.");
352 return 0;
353 }
354 if (--_eio_init_count != 0)
355 return _eio_init_count;
356
357 eina_log_timing(_eio_log_dom_global,
358 EINA_LOG_STATE_START,
359 EINA_LOG_STATE_SHUTDOWN);
360
361 efl_provider_unregister(efl_main_loop_get(), EFL_IO_MANAGER_CLASS, io_manager);
362 efl_del(io_manager);
363 io_manager = NULL;
364
365 EINA_LIST_FOREACH(tracked_thread, l, f)
366 ecore_thread_cancel(f->thread);
367
368 EINA_LIST_FREE(tracked_thread, f)
369 {
370 if (!ecore_thread_wait(f->thread, 0.5))
371 CRI("We couldn't terminate in less than 30s some pending IO. This can led to some crash.");
372 }
373
374 efreet_mime_shutdown();
375
376 eio_monitor_shutdown();
377
378 eina_condition_free(&(memory_pool_cond));
379 eina_lock_free(&(memory_pool_mutex));
380 eina_spinlock_free(&(memory_pool_lock));
381
382 eina_lock_free(&(direct_info_pool.lock));
383 eina_lock_free(&(progress_pool.lock));
384 eina_lock_free(&(char_pool.lock));
385 eina_lock_free(&(associate_pool.lock));
386
387 /* Cleanup pool */
388 EINA_TRASH_CLEAN(&progress_pool.trash, pg)
389 free(pg);
390 progress_pool.count = 0;
391
392 EINA_TRASH_CLEAN(&direct_info_pool.trash, info)
393 free(info);
394 direct_info_pool.count = 0;
395
396 EINA_TRASH_CLEAN(&char_pool.trash, cin)
397 free(cin);
398 char_pool.count = 0;
399
400 EINA_TRASH_CLEAN(&associate_pool.trash, asso)
401 free(asso);
402 associate_pool.count = 0;
403
404 ecore_shutdown();
405 eina_log_domain_unregister(_eio_log_dom_global);
406 _eio_log_dom_global = -1;
407 eina_shutdown();
408
409 return _eio_init_count;
410 }
411
412 EAPI void
eio_memory_burst_limit_set(size_t limit)413 eio_memory_burst_limit_set(size_t limit)
414 {
415 eina_lock_take(&(memory_pool_mutex));
416 memory_pool_limit = limit;
417 if (memory_pool_suspended)
418 {
419 if (memory_pool_usage < memory_pool_limit)
420 eina_condition_broadcast(&(memory_pool_cond));
421 }
422 eina_lock_release(&(memory_pool_mutex));
423 }
424
425 EAPI size_t
eio_memory_burst_limit_get(void)426 eio_memory_burst_limit_get(void)
427 {
428 return memory_pool_limit;
429 }
430