From c575d2d4c69627fc40ae7559669a5e251834b873 Mon Sep 17 00:00:00 2001 From: Carsten Haitzler Date: Wed, 28 Sep 2011 11:53:41 +0000 Subject: [PATCH] Document how to use thread with EFL in nice detail for "beginners" who know already how to use threads (pthread) and then how to use that with EFL. SVN revision: 63641 --- legacy/elementary/doc/examples.dox | 167 ++++++++++++++++++ legacy/elementary/doc/index.doxy | 23 +++ legacy/elementary/src/examples/Makefile.am | 16 +- legacy/elementary/src/examples/efl_thread_1.c | 74 ++++++++ legacy/elementary/src/examples/efl_thread_2.c | 90 ++++++++++ legacy/elementary/src/examples/efl_thread_3.c | 93 ++++++++++ legacy/elementary/src/examples/efl_thread_4.c | 116 ++++++++++++ legacy/elementary/src/examples/efl_thread_5.c | 99 +++++++++++ legacy/elementary/src/examples/efl_thread_6.c | 164 +++++++++++++++++ 9 files changed, 840 insertions(+), 2 deletions(-) create mode 100644 legacy/elementary/src/examples/efl_thread_1.c create mode 100644 legacy/elementary/src/examples/efl_thread_2.c create mode 100644 legacy/elementary/src/examples/efl_thread_3.c create mode 100644 legacy/elementary/src/examples/efl_thread_4.c create mode 100644 legacy/elementary/src/examples/efl_thread_5.c create mode 100644 legacy/elementary/src/examples/efl_thread_6.c diff --git a/legacy/elementary/doc/examples.dox b/legacy/elementary/doc/examples.dox index 95df23b5a1..b6d7783c46 100644 --- a/legacy/elementary/doc/examples.dox +++ b/legacy/elementary/doc/examples.dox @@ -92,6 +92,18 @@ * @ref progressbar_example * * @ref slideshow_example + * + * @ref efl_thread_1 + * + * @ref efl_thread_2 + * + * @ref efl_thread_3 + * + * @ref efl_thread_4 + * + * @ref efl_thread_5 + * + * @ref efl_thread_6 */ /** @@ -5927,6 +5939,125 @@ * @example win_example.c */ +/** + * @page efl_thread_1 EFL Threading example 1 + * + * You can use threads with Elementary (and EFL) but you need to be careful + * to only use eina or eet calls inside a thread. Other libraries are not + * totally threadsafe except for some specific ecore calls designed for + * working from threads like the ecore_pipe_write() and ecore_thread calls. + * + * Below is an example of how to use EFL calls from a native thread you have + * already created. You have to put the EFL calls inside the critical block + * between ecore_thread_main_loop_begin() and ecore_thread_main_loop_end() + * which ensure you gain a lock on the mainloop. Beware that this requires + * that the thread WAIT to synchronize with the mainloop at the beginning of + * the critical section. It is highly suggested you use as few of these + * in your thread as possible and probably put just a single + * ecore_thread_main_loop_begin() / ecore_thread_main_loop_end() section + * at the end of the threads calculation or work when it is done and + * would otherwise exit to sit idle. + * + * For a progression of examples that become more complex and show other + * ways to use threading with EFL, please see: + * + * @ref efl_thread_2 + * + * @ref efl_thread_3 + * + * @ref efl_thread_4 + * + * @ref efl_thread_5 + * + * @ref efl_thread_6 + * + * @include efl_thread_1.c + */ + +/** + * @page efl_thread_2 EFL Threading example 2 + * + * You can also use ecore_main_loop_thread_safe_call_sync() to call a + * specific function that needs to do EFL main loop operations. This call + * will block and wait to synchronise to the mainloop just like + * ecore_thread_main_loop_begin() / ecore_thread_main_loop_end() will, + * but instead you simply provide it the function callback to call instead + * of inlining your code. + * + * @ref efl_thread_3 + * + * @ref efl_thread_4 + * + * @ref efl_thread_5 + * + * @ref efl_thread_6 + * + * @include efl_thread_2.c + */ + +/** + * @page efl_thread_3 EFL Threading example 3 + * + * Like with ecore_main_loop_thread_safe_call_sync() you can provide a + * callback to call inline in the mainloop, but this time with + * ecore_main_loop_thread_safe_call_async() the callback is queued and + * called asynchronously, without the thread blocking. The mainloop will + * call this function when it comes around to its synchronisation point. This + * acts as a "fire and forget" way of having the mainloop do some work + * for a thread that has finished processing some data and is read to hand it + * off to the mainloop and the thread wants to march on and do some more work + * while the main loop deals with "displaying" the results of the previous + * calculation. + * + * @ref efl_thread_4 + * + * @ref efl_thread_5 + * + * @ref efl_thread_6 + * + * @include efl_thread_3.c + */ + +/** + * @page efl_thread_4 EFL Threading example 4 + * + * Now when you want to have a thread do some work, send back results to + * the mainloop and continue running but the mainloop controls when the + * thread should stop working, you need some extra flags. This is an example + * of how you might use ecore_main_loop_thread_safe_call_async() and pthreads + * to do this. + * + * @ref efl_thread_5 + * + * @ref efl_thread_6 + * + * @include efl_thread_4.c + */ + +/** + * @page efl_thread_5 EFL Threading example 5 + * + * This is the same as @ref efl_thread_4 but now uses the ecore_thread + * infrastructure to have a running worker thread that feeds results back + * to the mainloop and can easily be cancelled. This saves some code in the + * application and makes for fewer problem spots if you forget a mutex. + * + * @ref efl_thread_6 + * + * @include efl_thread_5.c + */ + +/** + * @page efl_thread_6 EFL Threading example 6 + * + * You can also use the ecore_thread infrastructure for compute tasks that + * don't send feedback as they go - they are one-shot compute jobs and when + * done they will trigger the end callback in the mainloop which is intended + * to pick up the results and "display them". + * + * @include efl_thread_6.c + */ + /** * @page bg_example_01_c bg_example_01.c * @include bg_example_01.c @@ -6087,3 +6218,39 @@ * @include slideshow_example.c * @example slideshow_example.c */ + +/** + * @page efl_thread_1_c EFL Threading example 1 + * @include efl_thread_1.c + * @example efl_thread_1.c + */ + +/** + * @page efl_thread_2_c EFL Threading example 2 + * @include efl_thread_2.c + * @example efl_thread_2.c + */ + +/** + * @page efl_thread_3_c EFL Threading example 3 + * @include efl_thread_3.c + * @example efl_thread_3.c + */ + +/** + * @page efl_thread_4_c EFL Threading example 4 + * @include efl_thread_4.c + * @example efl_thread_4.c + */ + +/** + * @page efl_thread_5_c EFL Threading example 5 + * @include efl_thread_5.c + * @example efl_thread_5.c + */ + +/** + * @page efl_thread_6_c EFL Threading example 6 + * @include efl_thread_6.c + * @example efl_thread_6.c + */ diff --git a/legacy/elementary/doc/index.doxy b/legacy/elementary/doc/index.doxy index 83ee765f25..caebcd79fd 100644 --- a/legacy/elementary/doc/index.doxy +++ b/legacy/elementary/doc/index.doxy @@ -30,6 +30,9 @@ * @li @ref widgetslist - These are the widgets you'll compose your UI out of. * @li @ref containerslist - These are the containers in which the widgets will * be laid out. + * + * Also see other generic EFL programming guides: + * @li @ref threading */ /** * @page widgetslist Widget list @@ -290,3 +293,23 @@ * @li @ref infralist - These are modules that deal with Elementary as a whole. * @li @ref widgetslist - These are the widgets you'll compose your UI out of. */ +/** + * @page threading Threading + * + * You may use threads with EFL, but only in specific ways. If you plan on + * using threads it is very important you see the following example guides. + * See the following + * + * @ref efl_thread_1 + * + * @ref efl_thread_2 + * + * @ref efl_thread_3 + * + * @ref efl_thread_4 + * + * @ref efl_thread_5 + * + * @ref efl_thread_6 + * + */ diff --git a/legacy/elementary/src/examples/Makefile.am b/legacy/elementary/src/examples/Makefile.am index 8e4fc6e079..e1ae01d04b 100644 --- a/legacy/elementary/src/examples/Makefile.am +++ b/legacy/elementary/src/examples/Makefile.am @@ -115,7 +115,13 @@ SRCS = \ table_example_02.c \ menu_example_01.c \ thumb_example_01.c \ - win_example.c + win_example.c \ + efl_thread_1.c \ + efl_thread_2.c \ + efl_thread_3.c \ + efl_thread_4.c \ + efl_thread_5.c \ + efl_thread_6.c pkglib_PROGRAMS = @@ -217,7 +223,13 @@ pkglib_PROGRAMS += \ table_example_02 \ menu_example_01 \ thumb_example_01 \ - win_example + win_example \ + efl_thread_1 \ + efl_thread_2 \ + efl_thread_3 \ + efl_thread_4 \ + efl_thread_5 \ + efl_thread_6 # This variable will hold the list of screenshots that will be made # by "make screenshots". Each item in the list is of the form: diff --git a/legacy/elementary/src/examples/efl_thread_1.c b/legacy/elementary/src/examples/efl_thread_1.c new file mode 100644 index 0000000000..98bc5e9fe0 --- /dev/null +++ b/legacy/elementary/src/examples/efl_thread_1.c @@ -0,0 +1,74 @@ +#include +#include + +static Evas_Object *win = NULL; +static Evas_Object *rect = NULL; + +static pthread_t thread_id; + +// BEGIN - code running in my custom pthread instance +// +static void * +my_thread_run(void *arg) +{ + double t = 0.0; + + for (;;) + { + ecore_thread_main_loop_begin(); // begin critical + { // indented for illustration of "critical" block + Evas_Coord x, y; + + x = 200 + (200 * sin(t)); + y = 200 + (200 * cos(t)); + evas_object_move(rect, x - 50, y - 50); + } + ecore_thread_main_loop_end(); // end critical + usleep(1000); + t += 0.02; + } + return NULL; +} +// +// END - code running in my custom pthread instance + +static void +my_thread_new(void) +{ + pthread_attr_t attr; + + if (pthread_attr_init(&attr) != 0) + perror("pthread_attr_init"); + if (pthread_create(&thread_id, &attr, my_thread_run, NULL) != 0) + perror("pthread_create"); +} + +int +elm_main(int argc, char **argv) +{ + Evas_Object *o, *bg; + + win = elm_win_add(NULL, "efl-thread-1", ELM_WIN_BASIC); + elm_win_title_set(win, "EFL Thread 1"); + evas_object_resize(win, 400, 400); + evas_object_show(win); + + bg = elm_bg_add(win); + elm_win_resize_object_add(win, bg); + evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_show(bg); + + o = evas_object_rectangle_add(evas_object_evas_get(win)); + evas_object_color_set(o, 50, 80, 180, 255); + evas_object_resize(o, 100, 100); + evas_object_show(o); + rect = o; + + // create custom thread to do some "work on the side" + my_thread_new(); + + elm_run(); + return 0; +} + +ELM_MAIN() diff --git a/legacy/elementary/src/examples/efl_thread_2.c b/legacy/elementary/src/examples/efl_thread_2.c new file mode 100644 index 0000000000..a9da8055fc --- /dev/null +++ b/legacy/elementary/src/examples/efl_thread_2.c @@ -0,0 +1,90 @@ +#include +#include + +static Evas_Object *win = NULL; +static Evas_Object *rect = NULL; + +struct info +{ + double x, y; +}; + +static void *my_thread_mainloop_code(void *data); + +static pthread_t thread_id; + +// BEGIN - code running in my custom pthread instance +// +static void * +my_thread_run(void *arg) +{ + double t = 0.0; + + for (;;) + { + struct info *inf = malloc(sizeof(struct info)); + + if (inf) + { + inf->x = 200 + (200 * sin(t)); + inf->y = 200 + (200 * cos(t)); + ecore_main_loop_thread_safe_call_sync + (my_thread_mainloop_code, inf); + } + // and sleep and loop + usleep(1000); + t += 0.02; + } + return NULL; +} +// +// END - code running in my custom pthread instance +static void +my_thread_new(void) +{ + pthread_attr_t attr; + + if (pthread_attr_init(&attr) != 0) + perror("pthread_attr_init"); + if (pthread_create(&thread_id, &attr, my_thread_run, NULL) != 0) + perror("pthread_create"); +} + +static void * +my_thread_mainloop_code(void *data) +{ + struct info *inf = data; + evas_object_move(rect, inf->x - 50, inf->y - 50); + free(inf); + return NULL; +} + +int +elm_main(int argc, char **argv) +{ + Evas_Object *o, *bg; + + win = elm_win_add(NULL, "efl-thread-2", ELM_WIN_BASIC); + elm_win_title_set(win, "EFL Thread 2"); + evas_object_resize(win, 400, 400); + evas_object_show(win); + + bg = elm_bg_add(win); + elm_win_resize_object_add(win, bg); + evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_show(bg); + + o = evas_object_rectangle_add(evas_object_evas_get(win)); + evas_object_color_set(o, 50, 80, 180, 255); + evas_object_resize(o, 100, 100); + evas_object_show(o); + rect = o; + + // create custom thread to do some "work on the side" + my_thread_new(); + + elm_run(); + return 0; +} + +ELM_MAIN() diff --git a/legacy/elementary/src/examples/efl_thread_3.c b/legacy/elementary/src/examples/efl_thread_3.c new file mode 100644 index 0000000000..3019270d57 --- /dev/null +++ b/legacy/elementary/src/examples/efl_thread_3.c @@ -0,0 +1,93 @@ +#include +#include + +static Evas_Object *win = NULL; +static Evas_Object *rect = NULL; + +struct info +{ + double x, y; +}; + +static void my_thread_mainloop_code(void *data); + +static pthread_t thread_id; + +// BEGIN - code running in my custom pthread instance +// +static void * +my_thread_run(void *arg) +{ + double t = 0.0; + + // inside the pthread function lets loop forever incrimenting a time point + for (;;) + { + struct info *inf = malloc(sizeof(struct info)); + + if (inf) + { + inf->x = 200 + (200 * sin(t)); + inf->y = 200 + (200 * cos(t)); + // now call a function in the mainloop and pass it our allocated + // data that it will free when it gets it + ecore_main_loop_thread_safe_call_async + (my_thread_mainloop_code, inf); + } + // and sleep and loop + usleep(1000); + t += 0.02; + } + return NULL; +} +// +// END - code running in my custom pthread instance +static void +my_thread_new(void) +{ + pthread_attr_t attr; + + if (pthread_attr_init(&attr) != 0) + perror("pthread_attr_init"); + if (pthread_create(&thread_id, &attr, my_thread_run, NULL) != 0) + perror("pthread_create"); +} + +static void +my_thread_mainloop_code(void *data) +{ + struct info *inf = data; + evas_object_move(rect, inf->x - 50, inf->y - 50); + free(inf); +} + +int +elm_main(int argc, char **argv) +{ + Evas_Object *o, *bg; + + win = elm_win_add(NULL, "efl-thread-3", ELM_WIN_BASIC); + elm_win_title_set(win, "EFL Thread 3"); + evas_object_resize(win, 400, 400); + evas_object_show(win); + + bg = elm_bg_add(win); + elm_win_resize_object_add(win, bg); + evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_show(bg); + + o = evas_object_rectangle_add(evas_object_evas_get(win)); + evas_object_color_set(o, 50, 80, 180, 255); + evas_object_resize(o, 100, 100); + evas_object_show(o); + rect = o; + + // create custom thread to do some "work on the side" + my_thread_new(); + + elm_run(); + return 0; +} + +ELM_MAIN() + diff --git a/legacy/elementary/src/examples/efl_thread_4.c b/legacy/elementary/src/examples/efl_thread_4.c new file mode 100644 index 0000000000..b3fd4fda31 --- /dev/null +++ b/legacy/elementary/src/examples/efl_thread_4.c @@ -0,0 +1,116 @@ +#include +#include + +static Evas_Object *win = NULL; +static Evas_Object *rect = NULL; + +struct info +{ + double x, y; +}; + +static void my_thread_mainloop_code(void *data); + +static pthread_t thread_id; +static pthread_mutex_t th_lock; +static int th_exit = 0; + +// BEGIN - code running in my custom pthread instance +// +static void * +my_thread_run(void *arg) +{ + double t = 0.0; + + // inside the pthread function lets loop forever incrimenting a time point + for (;;) + { + struct info *inf = malloc(sizeof(struct info)); + int do_exit; + + if (inf) + { + inf->x = 200 + (200 * sin(t)); + inf->y = 200 + (200 * cos(t)); + // now call a function in the mainloop and pass it our allocated + // data that it will free when it gets it + ecore_main_loop_thread_safe_call_async + (my_thread_mainloop_code, inf); + } + // and sleep and loop + usleep(1000); + t += 0.02; + // in case someone has asked us to cancel - then cacnel this loop + // co-operatively (cancelling is co-operative) + pthread_mutex_lock(&th_lock); + do_exit = th_exit; + pthread_mutex_unlock(&th_lock); + if (do_exit) break; + } + return NULL; +} +// +// END - code running in my custom pthread instance + +static void +my_thread_new(void) +{ + pthread_attr_t attr; + + pthread_mutex_init(&th_lock, NULL); + if (pthread_attr_init(&attr) != 0) + perror("pthread_attr_init"); + if (pthread_create(&thread_id, &attr, my_thread_run, NULL) != 0) + perror("pthread_create"); +} + +static void +my_thread_mainloop_code(void *data) +{ + struct info *inf = data; + evas_object_move(rect, inf->x - 50, inf->y - 50); + free(inf); +} + +// just test cancelling the thread +static void +down(void *data, Evas *e, Evas_Object *obj, void *event_info) +{ + pthread_mutex_lock(&th_lock); + th_exit = 1; + pthread_mutex_unlock(&th_lock); +} + +int +elm_main(int argc, char **argv) +{ + Evas_Object *o, *bg; + + win = elm_win_add(NULL, "efl-thread-4", ELM_WIN_BASIC); + elm_win_title_set(win, "EFL Thread 4"); + evas_object_resize(win, 400, 400); + evas_object_show(win); + + bg = elm_bg_add(win); + elm_win_resize_object_add(win, bg); + evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_show(bg); + + o = evas_object_rectangle_add(evas_object_evas_get(win)); + evas_object_color_set(o, 50, 80, 180, 255); + evas_object_resize(o, 100, 100); + evas_object_show(o); + // new in the examples - we have a mouse down on the blue box cancel + // the thread + evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_DOWN, down, NULL); + rect = o; + + // create custom thread to do some "work on the side" + my_thread_new(); + + elm_run(); + return 0; +} + +ELM_MAIN() + diff --git a/legacy/elementary/src/examples/efl_thread_5.c b/legacy/elementary/src/examples/efl_thread_5.c new file mode 100644 index 0000000000..0edeeeed42 --- /dev/null +++ b/legacy/elementary/src/examples/efl_thread_5.c @@ -0,0 +1,99 @@ +#include + +static Ecore_Thread *th = NULL; + +static Evas_Object *win = NULL; +static Evas_Object *rect = NULL; + +struct info +{ + double x, y; +}; + +// BEGIN - code running in my custom pthread instance +// +static void +th_do(void *data, Ecore_Thread *th) +{ + double t = 0.0; + + // inside our "do" function for the ecore thread, lets do the real work + for (;;) + { + struct info *inf = malloc(sizeof(struct info)); + + if (inf) + { + inf->x = 200 + (200 * sin(t)); + inf->y = 200 + (200 * cos(t)); + // now we have recorded the timepoint we pass it as feedback + // back to the mainloop. it will free it when done + ecore_thread_feedback(th, inf); + } + // and sleep and loop + usleep(1000); + t += 0.02; + // in case someone has asked us to cancel - then cacnel this loop + // co-operatively (cancelling is co-operative) + if (ecore_thread_check(th)) break; + } +} +// +// END - code running in my custom pthread instance + +static void // when mainloop gets feedback from worker +th_feedback(void *data, Ecore_Thread *th, void *msg) +{ + struct info *inf = msg; + evas_object_move(rect, inf->x - 50, inf->y - 50); + free(inf); +} + +// BONUS (optional): called after th_do returns and has NOT been cancelled +static void th_end(void *data, Ecore_Thread *th) { printf("thread ended\n"); } +// BONUS (optional): called in mainloop AFTER thread has finished cancelling +static void th_cancel(void *data, Ecore_Thread *th) { printf("thread cancelled\n"); } + +// just test cancelling the thread worker +static void +down(void *data, Evas *e, Evas_Object *obj, void *event_info) +{ + ecore_thread_cancel(th); +} + +int +elm_main(int argc, char **argv) +{ + Evas_Object *o, *bg; + + win = elm_win_add(NULL, "efl-thread-5", ELM_WIN_BASIC); + elm_win_title_set(win, "EFL Thread 5"); + evas_object_resize(win, 400, 400); + evas_object_show(win); + + bg = elm_bg_add(win); + elm_win_resize_object_add(win, bg); + evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_show(bg); + + o = evas_object_rectangle_add(evas_object_evas_get(win)); + evas_object_color_set(o, 50, 80, 180, 255); + evas_object_resize(o, 100, 100); + evas_object_show(o); + evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_DOWN, down, NULL); + rect = o; + + // explicitly create ecore thread to do some "work on the side" and pass + // in NULL as data ptr to callbacks and true at the end means to actually + // make a new thread and not use the thread pool (there is a thread pool + // with as many thread workers as there are cpu's so this means you do not + // overload the cpu's with more work than you actually have processing + // units *IF* your threads do actually spend their time doing actual + // heavy computation) + th = ecore_thread_feedback_run(th_do, th_feedback, th_end, th_cancel, + NULL, EINA_TRUE); + elm_run(); + return 0; +} + +ELM_MAIN() diff --git a/legacy/elementary/src/examples/efl_thread_6.c b/legacy/elementary/src/examples/efl_thread_6.c new file mode 100644 index 0000000000..1fa2cabfe6 --- /dev/null +++ b/legacy/elementary/src/examples/efl_thread_6.c @@ -0,0 +1,164 @@ +#include + +static Evas_Object *win = NULL; +static Evas_Object *rect = NULL; + +struct info +{ + Evas_Object *obj; + int *pix; +}; + +// BEGIN - code running in my custom pthread instance +// +static void +mandel(int *pix, int w, int h) +{ + double x, xx, y, cx, cy, cox, coy; + int iteration, hx, hy, val, r, g, b, rr, gg, bb; + int itermax = 10000; + double magnify = 0.02; + + // this mandel calc is run in the worker threads so it's here. it is + // just here to calculate something and consume cpu to demonstrate the + // ecore thread worker queue. don't pay much attention to the below code + magnify += ((double)(rand() % 100) / 100.0) / 4.0; + cox = (double)(rand() % 100) / 100.0; + coy = (double)(rand() % 100) / 100.0; + cox /= (magnify * 3.0); + r = rand() % 255; g = rand() % 255; b = rand() % 255; + for (hy = 0; hy < h; hy++) + { + for (hx = 0; hx < w; hx++) + { + cx = (((float)hx) / ((float)w) - 0.5) / (magnify * 3.0); + cy = (((float)hy) / ((float)h) - 0.5) / (magnify * 3.0); + cx += cox; + cy += coy; + x = 0.0; + y = 0.0; + for (iteration = 1; iteration < itermax; iteration++) + { + xx = (x * x) - (y * y) + cx; + y = (2.0 * x * y) + cy; + x = xx; + if (((x * x) + (y * y)) > 100.0) iteration = 999999; + } + val = (((x * x) + (y * y)) * 2.55) / 100.0; + if (val > 255) val = 255; + if (iteration >= 99999) + { + rr = (r * val) / 255; + gg = (g * val) / 255; + bb = (b * val) / 255; + pix[(hy * w) + hx] = + (val << 24) | (rr << 16) | (gg << 8) | (bb); + } + else + pix[(hy * w) + hx] = 0xffffffff; + } + } +} + +static void +th_do(void *data, Ecore_Thread *th) +{ + struct info *inf = data; + // CANNOT TOUCH inf->obj here! just inf->pix which is 256x256 @ 32bpp + // quick and dirty to consume some cpu - do a mandelbrot calc + mandel(inf->pix, 256, 256); +} +// +// END - code running in my custom pthread instance + +static void // thread job finished - collect results and put in img obj +th_end(void *data, Ecore_Thread *th) +{ + struct info *inf = data; + + // copy data to object, free calculated data and info struc + evas_object_image_data_copy_set(inf->obj, inf->pix); + evas_object_show(inf->obj); + free(inf->pix); + free(inf); +} + +static void // if the thread is cancelled - free pix, keep obj tho +th_cancel(void *data, Ecore_Thread *th) +{ + struct info *inf = data; + + // just free pixel data and info struct + free(inf->pix); + free(inf); +} + +static Eina_Bool // animate the objects so you see all the madels move +anim(void *data) +{ + Evas_Object *o = data; + double t, z; + int w, h, v; + Evas_Coord x, y; + + // just calculate some position using the pointer value of the object as + // a seed value to make different objects go into different places over time + v = ((int)o) & 0xff; + t = ecore_loop_time_get(); + w = 100 + ((v * 100) >> 8); + h = 100 + ((v * 100) >> 8); + z = (double)(v) / 100.0; + x = (w * sin(t)); + y = (h * cos(t + z)); + // do the actual move + evas_object_move(o, 200 + x - 128, 200 + y - 128); + // keep looping - return true + return EINA_TRUE; +} + +int +elm_main(int argc, char **argv) +{ + Evas_Object *o, *bg; + int i; + + win = elm_win_add(NULL, "efl-thread-1", ELM_WIN_BASIC); + elm_win_title_set(win, "EFL Thread 1"); + evas_object_resize(win, 400, 400); + evas_object_show(win); + + bg = elm_bg_add(win); + elm_win_resize_object_add(win, bg); + evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_show(bg); + + // queue up 64 mandel generation thread jobs + for (i = 0; i < 64; i++) + { + struct info *inf; + + // create ecore thread to do some threaded job inside the worker pool + inf = malloc(sizeof(struct info)); + if (inf) + { + Evas_Object *o; + + o = evas_object_image_filled_add(evas_object_evas_get(win)); + evas_object_image_size_set(o, 256, 256); + evas_object_image_alpha_set(o, EINA_TRUE); + evas_object_resize(o, 256, 256); + inf->obj = o; + inf->pix = malloc(256 * 256 * sizeof(int)); + ecore_thread_run(th_do, th_end, th_cancel, inf); + // bonus - slide the objects around all the time with an + // animator that ticks off every frame. + ecore_animator_add(anim, o); + } + } + + elm_run(); + return 0; +} + +ELM_MAIN() +