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