1 /*
2 * gcc -o ecore_thread_example ecore_thread_example.c `pkg-config --cflags --libs ecore eina`
3 */
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <unistd.h>
7
8 #include <Ecore.h>
9 #include <Ecore_Getopt.h>
10
11 typedef struct
12 {
13 Ecore_Thread *thread_3;
14 int msgs_received;
15 int max_msgs;
16 Eina_Lock mutex;
17 Eina_Condition condition;
18 } App_Data;
19
20 typedef struct
21 {
22 Eina_List *list;
23 } Thread_Data;
24
25 typedef struct
26 {
27 char *name;
28 char *base;
29 Eina_Lock mutex;
30 } Feedback_Thread_Data;
31
32 typedef struct
33 {
34 int all_done;
35 Eina_List *list;
36 } App_Msg;
37
38 static void
_local_data_free(void * data)39 _local_data_free(void *data)
40 {
41 Thread_Data *td = data;
42 char *str;
43
44 EINA_LIST_FREE(td->list, str)
45 {
46 printf("Freeing string: %s\n", str);
47 free(str);
48 }
49 free(td);
50 }
51
52 static void
_short_job(void * data EINA_UNUSED,Ecore_Thread * th)53 _short_job(void *data EINA_UNUSED, Ecore_Thread *th)
54 {
55 Thread_Data *td;
56 int i;
57
58 td = ecore_thread_local_data_find(th, "data");
59 if (!td)
60 {
61 td = calloc(1, sizeof(Thread_Data));
62 if (!td)
63 {
64 ecore_thread_cancel(th);
65 return;
66 }
67 ecore_thread_local_data_add(th, "data", td, _local_data_free,
68 EINA_FALSE);
69 }
70
71 for (i = 0; i < 10; i++)
72 {
73 char buf[200];
74
75 if (ecore_thread_check(th))
76 {
77 ecore_thread_local_data_del(th, "data");
78 break;
79 }
80
81 snprintf(buf, sizeof(buf), "Thread %p: String number %d", th, i);
82 td->list = eina_list_append(td->list, strdup(buf));
83 sleep(1);
84 }
85 }
86
87 static void
_feedback_job(void * data EINA_UNUSED,Ecore_Thread * th)88 _feedback_job(void *data EINA_UNUSED, Ecore_Thread *th)
89 {
90 time_t t;
91 int i, count;
92 Feedback_Thread_Data *ftd = NULL;
93 Eina_Iterator *it;
94 App_Msg *msg;
95 char *name;
96
97 count = (int)(uintptr_t)ecore_thread_global_data_find("count");
98 for (i = 0; i < count; i++)
99 {
100 char buf[32];
101 snprintf(buf, sizeof(buf), "data%d", i);
102 ftd = ecore_thread_global_data_find(buf);
103 if (!ftd)
104 continue;
105 if (eina_lock_take_try(&ftd->mutex))
106 break;
107 else
108 ftd = NULL;
109 }
110 if (!ftd)
111 return;
112
113 it = eina_file_ls(ftd->base);
114 if (!it)
115 goto the_end;
116
117 msg = calloc(1, sizeof(App_Msg));
118
119 t = time(NULL);
120 EINA_ITERATOR_FOREACH(it, name)
121 {
122 if (time(NULL) >= (t + 2))
123 {
124 eina_stringshare_del(name);
125 break;
126 }
127 if (eina_stringshare_strlen(name) >= 10)
128 msg->list = eina_list_append(msg->list, strdup(name));
129 eina_stringshare_del(name);
130 }
131
132 eina_iterator_free(it);
133 ecore_thread_feedback(th, msg);
134
135 the_end:
136 ecore_thread_global_data_del(ftd->name);
137 free(ftd->name);
138 free(ftd->base);
139 eina_lock_release(&ftd->mutex);
140 eina_lock_free(&ftd->mutex);
141 free(ftd);
142 ecore_thread_reschedule(th);
143 }
144
145 static void
_out_of_pool_job(void * data,Ecore_Thread * th)146 _out_of_pool_job(void *data, Ecore_Thread *th)
147 {
148 App_Data *ad = data;
149 App_Msg *msg;
150
151 while (1)
152 {
153 int msgs;
154 eina_condition_wait(&ad->condition);
155 msgs = ad->msgs_received;
156 eina_lock_release(&ad->mutex);
157 if (msgs == ad->max_msgs)
158 {
159 msg = calloc(1, sizeof(App_Msg));
160 msg->all_done = 1;
161 ecore_thread_feedback(th, msg);
162 return;
163 }
164 }
165 }
166
167 static void
_print_status(void)168 _print_status(void)
169 {
170 int active, pending_total, pending_feedback, pending_short, available;
171
172 active = ecore_thread_active_get();
173 pending_total = ecore_thread_pending_total_get();
174 pending_feedback = ecore_thread_pending_feedback_get();
175 pending_short = ecore_thread_pending_get();
176 available = ecore_thread_available_get();
177
178 printf("Status:\n\t* Active threads: %d\n"
179 "\t* Available threads: %d\n"
180 "\t* Pending short jobs: %d\n"
181 "\t* Pending feedback jobs: %d\n"
182 "\t* Pending total: %d\n", active, available, pending_short,
183 pending_feedback, pending_total);
184 }
185
186 static void
_feedback_job_msg_cb(void * data,Ecore_Thread * th,void * msg_data)187 _feedback_job_msg_cb(void *data, Ecore_Thread *th, void *msg_data)
188 {
189 App_Data *ad = data;
190 App_Msg *msg = msg_data;
191 char *str;
192
193 if (msg->all_done)
194 {
195 ecore_main_loop_quit();
196 free(msg);
197 return;
198 }
199
200 _print_status();
201
202 if (!msg->list)
203 printf("Received an empty list from thread %p\n", th);
204 else
205 {
206 int i = 0;
207 printf("Received %d elements from threads %p (printing first 5):\n",
208 eina_list_count(msg->list), th);
209 EINA_LIST_FREE(msg->list, str)
210 {
211 if (i <= 5)
212 printf("\t%s\n", str);
213 free(str);
214 i++;
215 }
216 }
217
218 eina_lock_take(&ad->mutex);
219 ad->msgs_received++;
220 eina_condition_signal(&ad->condition);
221 eina_lock_release(&ad->mutex);
222
223 free(msg);
224 }
225
226 static void
_thread_end_cb(void * data,Ecore_Thread * th)227 _thread_end_cb(void *data, Ecore_Thread *th)
228 {
229 App_Data *ad = data;
230
231 printf("Normal termination for thread %p.\n", th);
232 if (th == ad->thread_3)
233 ad->thread_3 = NULL;
234 }
235
236 static void
_thread_cancel_cb(void * data,Ecore_Thread * th)237 _thread_cancel_cb(void *data, Ecore_Thread *th)
238 {
239 App_Data *ad = data;
240
241 printf("Thread %p got cancelled.\n", th);
242 if (th == ad->thread_3)
243 ad->thread_3 = NULL;
244 }
245
246 static Eina_Bool
_cancel_timer_cb(void * data)247 _cancel_timer_cb(void *data)
248 {
249 App_Data *ad = data;
250
251 if (ad->thread_3 && !ecore_thread_check(ad->thread_3))
252 ecore_thread_cancel(ad->thread_3);
253
254 return EINA_FALSE;
255 }
256
257 static Eina_Bool
_status_timer_cb(void * data EINA_UNUSED)258 _status_timer_cb(void *data EINA_UNUSED)
259 {
260 _print_status();
261
262 return EINA_TRUE;
263 }
264
265 static const Ecore_Getopt optdesc = {
266 "ecore_thread_example",
267 NULL,
268 "0.0",
269 "(C) 2011 Enlightenment",
270 "Public domain?",
271 "Example program for Ecore_Thread",
272 0,
273 {
274 ECORE_GETOPT_STORE_INT('t', "threads", "Max number of threads to run"),
275 ECORE_GETOPT_STORE_INT('m', "msgs", "Max number of messages to receive"),
276 ECORE_GETOPT_APPEND_METAVAR('p', "path", "Add path for feedback job",
277 "STRING", ECORE_GETOPT_TYPE_STR),
278 ECORE_GETOPT_HELP('h', "help"),
279 ECORE_GETOPT_SENTINEL
280 }
281 };
282
283 int
main(int argc,char * argv[])284 main(int argc, char *argv[])
285 {
286 int i, max_threads = 0, max_msgs = 0;
287 Eina_Bool opt_quit = EINA_FALSE;
288 Eina_List *path_list = NULL;
289 App_Data appdata;
290 Ecore_Getopt_Value values[] = {
291 ECORE_GETOPT_VALUE_INT(max_threads),
292 ECORE_GETOPT_VALUE_INT(max_msgs),
293 ECORE_GETOPT_VALUE_LIST(path_list),
294 ECORE_GETOPT_VALUE_BOOL(opt_quit),
295 ECORE_GETOPT_VALUE_NONE
296 };
297
298 ecore_init();
299
300 i = ecore_thread_max_get();
301 printf("Initial max threads: %d\n", i);
302
303 memset(&appdata, 0, sizeof(App_Data));
304 appdata.max_msgs = 1;
305
306 if (ecore_getopt_parse(&optdesc, values, argc, argv) < 0)
307 {
308 printf("Argument parsing failed\n");
309 return 1;
310 }
311
312 if (opt_quit)
313 return 0;
314
315 if (max_threads)
316 {
317 ecore_thread_max_set(max_threads);
318 printf("Max threads: %d\n", ecore_thread_max_get());
319 }
320 if (max_msgs)
321 appdata.max_msgs = max_msgs;
322
323 if (!path_list)
324 {
325 Feedback_Thread_Data *ftd;
326 ecore_thread_global_data_add("count", (void *)3, NULL, EINA_FALSE);
327 ftd = calloc(1, sizeof(Feedback_Thread_Data));
328 ftd->name = strdup("data0");
329 #ifdef _WIN32
330 ftd->base = strdup("c:/windows/System32");
331 #else
332 ftd->base = strdup("/usr/bin");
333 #endif
334 eina_lock_new(&ftd->mutex);
335 ecore_thread_global_data_add(ftd->name, ftd, NULL, EINA_TRUE);
336 ftd = calloc(1, sizeof(Feedback_Thread_Data));
337 ftd->name = strdup("data1");
338 #ifdef _WIN32
339 ftd->base = strdup("c:/windows/Fonts");
340 #else
341 ftd->base = strdup("/usr/lib");
342 #endif
343 eina_lock_new(&ftd->mutex);
344 ecore_thread_global_data_add(ftd->name, ftd, NULL, EINA_TRUE);
345 ftd = calloc(1, sizeof(Feedback_Thread_Data));
346 ftd->name = strdup("data2");
347 #ifdef _WIN32
348 ftd->base = strdup("c:/windows/Help");
349 #else
350 ftd->base = strdup("/usr/lib");
351 #endif
352 eina_lock_new(&ftd->mutex);
353 ecore_thread_global_data_add(ftd->name, ftd, NULL, EINA_TRUE);
354 }
355 else
356 {
357 Feedback_Thread_Data *ftd;
358 char *str;
359 ecore_thread_global_data_add("count",
360 (void *)(uintptr_t)eina_list_count(path_list), NULL,
361 EINA_FALSE);
362 i = 0;
363 EINA_LIST_FREE(path_list, str)
364 {
365 char buf[32];
366 snprintf(buf, sizeof(buf), "data%d", i);
367 ftd = calloc(1, sizeof(Feedback_Thread_Data));
368 ftd->name = strdup(buf);
369 ftd->base = strdup(str);
370 eina_lock_new(&ftd->mutex);
371 ecore_thread_global_data_add(ftd->name, ftd, NULL, EINA_TRUE);
372 free(str);
373 i++;
374 }
375 }
376
377 eina_lock_new(&appdata.mutex);
378 eina_condition_new(&appdata.condition, &appdata.mutex);
379
380 ecore_thread_feedback_run(_out_of_pool_job, _feedback_job_msg_cb, NULL,
381 NULL, &appdata, EINA_TRUE);
382
383 ecore_thread_run(_short_job, _thread_end_cb, _thread_cancel_cb, &appdata);
384 ecore_thread_feedback_run(_feedback_job, _feedback_job_msg_cb,
385 _thread_end_cb, _thread_cancel_cb, &appdata,
386 EINA_FALSE);
387 appdata.thread_3 = ecore_thread_run(_short_job, _thread_end_cb,
388 _thread_cancel_cb, &appdata);
389 ecore_thread_feedback_run(_feedback_job, _feedback_job_msg_cb,
390 _thread_end_cb, _thread_cancel_cb, &appdata,
391 EINA_FALSE);
392
393 ecore_timer_add(1.0, _cancel_timer_cb, &appdata);
394 ecore_timer_add(2.0, _status_timer_cb, NULL);
395
396 _print_status();
397
398 ecore_main_loop_begin();
399
400 eina_condition_free(&appdata.condition);
401 eina_lock_free(&appdata.mutex);
402
403 ecore_shutdown();
404
405 return 0;
406 }
407