9 #ifdef EFL_HAVE_PTHREAD
14 #include "ecore_private.h"
16 #ifdef EFL_HAVE_PTHREAD
17 typedef struct _Ecore_Pthread_Worker Ecore_Pthread_Worker;
18 typedef struct _Ecore_Pthread_Data Ecore_Pthread_Data;
19 typedef struct _Ecore_Pthread Ecore_Pthread;
21 struct _Ecore_Pthread_Worker
23 void (*func_heavy)(void *data);
24 void (*func_end)(void *data);
25 void (*func_cancel)(void *data);
32 struct _Ecore_Pthread_Data
39 static int _ecore_thread_count_max = 0;
40 static int ECORE_THREAD_PIPE_DEL = 0;
42 #ifdef EFL_HAVE_PTHREAD
43 static int _ecore_thread_count = 0;
44 static Eina_List *_ecore_thread_data = NULL;
45 static Eina_List *_ecore_thread = NULL;
46 static Ecore_Event_Handler *del_handler = NULL;
48 static pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER;
51 _ecore_thread_pipe_free(void *data __UNUSED__, void *event)
53 Ecore_Pipe *p = event;
59 _ecore_thread_pipe_del(void *data __UNUSED__, int type __UNUSED__, void *event __UNUSED__)
61 /* This is a hack to delay pipe destruction until we are out of it's internal loop. */
66 _ecore_thread_end(Ecore_Pthread_Data *pth)
70 if (pthread_join(pth->thread, (void**) &p) != 0)
73 _ecore_thread = eina_list_remove(_ecore_thread, pth);
75 ecore_event_add(ECORE_THREAD_PIPE_DEL, pth->p, _ecore_thread_pipe_free, NULL);
79 _ecore_thread_worker(Ecore_Pthread_Data *pth)
81 Ecore_Pthread_Worker *work;
83 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
84 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
86 pthread_mutex_lock(&_mutex);
87 _ecore_thread_count++;
88 pthread_mutex_unlock(&_mutex);
92 while (_ecore_thread_data)
94 pthread_mutex_lock(&_mutex);
96 if (!_ecore_thread_data)
98 pthread_mutex_unlock(&_mutex);
102 work = eina_list_data_get(_ecore_thread_data);
103 _ecore_thread_data = eina_list_remove_list(_ecore_thread_data, _ecore_thread_data);
105 pthread_mutex_unlock(&_mutex);
107 work->func_heavy((void*) work->data);
109 ecore_pipe_write(pth->p, &work, sizeof (Ecore_Pthread_Worker*));
112 pthread_mutex_lock(&_mutex);
113 if (_ecore_thread_data)
115 pthread_mutex_unlock(&_mutex);
118 _ecore_thread_count--;
120 pthread_mutex_unlock(&_mutex);
122 work = malloc(sizeof (Ecore_Pthread_Worker));
123 if (!work) return NULL;
126 work->func_heavy = NULL;
127 work->func_end = (void*) _ecore_thread_end;
128 work->func_cancel = NULL;
129 work->cancel = EINA_FALSE;
131 ecore_pipe_write(pth->p, &work, sizeof (Ecore_Pthread_Worker*));
137 _ecore_thread_handler(void *data __UNUSED__, void *buffer, unsigned int nbyte)
139 Ecore_Pthread_Worker *work;
141 if (nbyte != sizeof (Ecore_Pthread_Worker*)) return ;
143 work = *(Ecore_Pthread_Worker**)buffer;
147 if (work->func_cancel)
148 work->func_cancel((void*) work->data);
152 work->func_end((void*) work->data);
160 _ecore_thread_init(void)
162 _ecore_thread_count_max = eina_cpu_count();
163 if (_ecore_thread_count_max <= 0)
164 _ecore_thread_count_max = 1;
166 ECORE_THREAD_PIPE_DEL = ecore_event_type_new();
167 #ifdef EFL_HAVE_PTHREAD
168 del_handler = ecore_event_handler_add(ECORE_THREAD_PIPE_DEL, _ecore_thread_pipe_del, NULL);
173 _ecore_thread_shutdown(void)
175 /* FIXME: If function are still running in the background, should we kill them ? */
176 #ifdef EFL_HAVE_PTHREAD
177 Ecore_Pthread_Worker *work;
178 Ecore_Pthread_Data *pth;
180 pthread_mutex_lock(&_mutex);
182 EINA_LIST_FREE(_ecore_thread_data, work)
184 if (work->func_cancel)
185 work->func_cancel((void*)work->data);
189 pthread_mutex_unlock(&_mutex);
191 EINA_LIST_FREE(_ecore_thread, pth)
195 pthread_cancel(pth->thread);
196 pthread_join(pth->thread, (void **) &p);
198 ecore_pipe_del(pth->p);
201 ecore_event_handler_del(del_handler);
207 * ecore_thread_run provide a facility for easily managing heavy task in a
208 * parallel thread. You should provide two function, the first one, func_heavy,
209 * that will do the heavy work in another thread (so you should not use the
210 * EFL in it except Eina if you are carefull), and the second one, func_end,
211 * that will be called in Ecore main loop when func_heavy is done. So you
212 * can use all the EFL inside this function.
214 * Be aware, that you can't make assumption on the result order of func_end
215 * after many call to ecore_thread_run, as we start as much thread as the
216 * host CPU can handle.
219 ecore_thread_run(void (*func_heavy)(void *data),
220 void (*func_end)(void *data),
221 void (*func_cancel)(void *data),
224 #ifdef EFL_HAVE_PTHREAD
225 Ecore_Pthread_Worker *work;
226 Ecore_Pthread_Data *pth;
228 work = malloc(sizeof (Ecore_Pthread_Worker));
231 func_cancel((void*) data);
235 work->func_heavy = func_heavy;
236 work->func_end = func_end;
237 work->func_cancel = func_cancel;
238 work->cancel = EINA_FALSE;
241 pthread_mutex_lock(&_mutex);
242 _ecore_thread_data = eina_list_append(_ecore_thread_data, work);
244 if (_ecore_thread_count == _ecore_thread_count_max)
246 pthread_mutex_unlock(&_mutex);
247 return (Ecore_Thread*) work;
250 pthread_mutex_unlock(&_mutex);
252 /* One more thread could be created. */
253 pth = malloc(sizeof (Ecore_Pthread_Data));
257 pth->p = ecore_pipe_add(_ecore_thread_handler, NULL);
259 if (pthread_create(&pth->thread, NULL, (void*) _ecore_thread_worker, pth) == 0)
260 return (Ecore_Thread*) work;
263 if (_ecore_thread_count == 0)
265 if (work->func_cancel)
266 work->func_cancel((void*) work->data);
272 If no thread and as we don't want to break app that rely on this
273 facility, we will lock the interface until we are done.
275 func_heavy((void *)data);
276 func_end((void *)data);
283 * ecore_thread_cancel give the possibility to cancel a task still running. It
284 * will return EINA_FALSE, if the destruction is delayed or EINA_TRUE if it is
285 * cancelled after this call.
287 * You should use this function only in the main loop.
289 * func_end, func_cancel will destroy the handler, so don't use it after.
290 * And if ecore_thread_cancel return EINA_TRUE, you should not use Ecore_Thread also.
293 ecore_thread_cancel(Ecore_Thread *thread)
295 #ifdef EFL_HAVE_PTHREAD
296 Ecore_Pthread_Worker *work;
299 pthread_mutex_lock(&_mutex);
301 EINA_LIST_FOREACH(_ecore_thread_data, l, work)
302 if ((void*) work == (void*) thread)
304 _ecore_thread_data = eina_list_remove_list(_ecore_thread_data, l);
306 pthread_mutex_unlock(&_mutex);
308 if (work->func_cancel)
309 work->func_cancel((void*) work->data);
315 pthread_mutex_unlock(&_mutex);
317 /* Delay the destruction */
318 ((Ecore_Pthread_Worker*)thread)->cancel = EINA_TRUE;