ecore_thread_example.c
/*
* gcc -o ecore_thread_example ecore_thread_example.c `pkg-config --cflags --libs ecore eina`
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <Ecore.h>
#include <Ecore_Getopt.h>
typedef struct
{
Ecore_Thread *thread_3;
int msgs_received;
int max_msgs;
Eina_Lock mutex;
Eina_Condition condition;
} App_Data;
typedef struct
{
Eina_List *list;
} Thread_Data;
typedef struct
{
char *name;
char *base;
Eina_Lock mutex;
} Feedback_Thread_Data;
typedef struct
{
int all_done;
Eina_List *list;
} App_Msg;
static void
_local_data_free(void *data)
{
Thread_Data *td = data;
char *str;
EINA_LIST_FREE(td->list, str)
{
printf("Freeing string: %s\n", str);
free(str);
}
free(td);
}
static void
_short_job(void *data EINA_UNUSED, Ecore_Thread *th)
{
Thread_Data *td;
int i;
td = ecore_thread_local_data_find(th, "data");
if (!td)
{
td = calloc(1, sizeof(Thread_Data));
if (!td)
{
ecore_thread_cancel(th);
return;
}
ecore_thread_local_data_add(th, "data", td, _local_data_free,
EINA_FALSE);
}
for (i = 0; i < 10; i++)
{
char buf[200];
if (ecore_thread_check(th))
{
ecore_thread_local_data_del(th, "data");
break;
}
snprintf(buf, sizeof(buf), "Thread %p: String number %d", th, i);
td->list = eina_list_append(td->list, strdup(buf));
sleep(1);
}
}
static void
_feedback_job(void *data EINA_UNUSED, Ecore_Thread *th)
{
time_t t;
int i, count;
Feedback_Thread_Data *ftd = NULL;
Eina_Iterator *it;
App_Msg *msg;
char *name;
count = (int)(uintptr_t)ecore_thread_global_data_find("count");
for (i = 0; i < count; i++)
{
char buf[32];
snprintf(buf, sizeof(buf), "data%d", i);
ftd = ecore_thread_global_data_find(buf);
if (!ftd)
continue;
if (eina_lock_take_try(&ftd->mutex))
break;
else
ftd = NULL;
}
if (!ftd)
return;
it = eina_file_ls(ftd->base);
if (!it)
goto the_end;
msg = calloc(1, sizeof(App_Msg));
t = time(NULL);
EINA_ITERATOR_FOREACH(it, name)
{
if (time(NULL) >= (t + 2))
{
eina_stringshare_del(name);
break;
}
if (eina_stringshare_strlen(name) >= 10)
msg->list = eina_list_append(msg->list, strdup(name));
eina_stringshare_del(name);
}
eina_iterator_free(it);
ecore_thread_feedback(th, msg);
the_end:
ecore_thread_global_data_del(ftd->name);
free(ftd->name);
free(ftd->base);
eina_lock_release(&ftd->mutex);
eina_lock_free(&ftd->mutex);
free(ftd);
ecore_thread_reschedule(th);
}
static void
_out_of_pool_job(void *data, Ecore_Thread *th)
{
App_Data *ad = data;
App_Msg *msg;
while (1)
{
int msgs;
eina_condition_wait(&ad->condition);
msgs = ad->msgs_received;
eina_lock_release(&ad->mutex);
if (msgs == ad->max_msgs)
{
msg = calloc(1, sizeof(App_Msg));
msg->all_done = 1;
ecore_thread_feedback(th, msg);
return;
}
}
}
static void
_print_status(void)
{
int active, pending_total, pending_feedback, pending_short, available;
active = ecore_thread_active_get();
pending_total = ecore_thread_pending_total_get();
pending_feedback = ecore_thread_pending_feedback_get();
pending_short = ecore_thread_pending_get();
available = ecore_thread_available_get();
printf("Status:\n\t* Active threads: %d\n"
"\t* Available threads: %d\n"
"\t* Pending short jobs: %d\n"
"\t* Pending feedback jobs: %d\n"
"\t* Pending total: %d\n", active, available, pending_short,
pending_feedback, pending_total);
}
static void
_feedback_job_msg_cb(void *data, Ecore_Thread *th, void *msg_data)
{
App_Data *ad = data;
App_Msg *msg = msg_data;
char *str;
if (msg->all_done)
{
ecore_main_loop_quit();
free(msg);
return;
}
_print_status();
if (!msg->list)
printf("Received an empty list from thread %p\n", th);
else
{
int i = 0;
printf("Received %d elements from threads %p (printing first 5):\n",
eina_list_count(msg->list), th);
EINA_LIST_FREE(msg->list, str)
{
if (i <= 5)
printf("\t%s\n", str);
free(str);
i++;
}
}
eina_lock_take(&ad->mutex);
ad->msgs_received++;
eina_condition_signal(&ad->condition);
eina_lock_release(&ad->mutex);
free(msg);
}
static void
_thread_end_cb(void *data, Ecore_Thread *th)
{
App_Data *ad = data;
printf("Normal termination for thread %p.\n", th);
if (th == ad->thread_3)
ad->thread_3 = NULL;
}
static void
_thread_cancel_cb(void *data, Ecore_Thread *th)
{
App_Data *ad = data;
printf("Thread %p got cancelled.\n", th);
if (th == ad->thread_3)
ad->thread_3 = NULL;
}
static Eina_Bool
_cancel_timer_cb(void *data)
{
App_Data *ad = data;
if (ad->thread_3 && !ecore_thread_check(ad->thread_3))
ecore_thread_cancel(ad->thread_3);
return EINA_FALSE;
}
static Eina_Bool
_status_timer_cb(void *data EINA_UNUSED)
{
_print_status();
return EINA_TRUE;
}
static const Ecore_Getopt optdesc = {
"ecore_thread_example",
NULL,
"0.0",
"(C) 2011 Enlightenment",
"Public domain?",
"Example program for Ecore_Thread",
0,
{
ECORE_GETOPT_STORE_INT('t', "threads", "Max number of threads to run"),
ECORE_GETOPT_STORE_INT('m', "msgs", "Max number of messages to receive"),
ECORE_GETOPT_APPEND_METAVAR('p', "path", "Add path for feedback job",
"STRING", ECORE_GETOPT_TYPE_STR),
ECORE_GETOPT_HELP('h', "help"),
ECORE_GETOPT_SENTINEL
}
};
int
main(int argc, char *argv[])
{
int i, max_threads = 0, max_msgs = 0;
Eina_Bool opt_quit = EINA_FALSE;
Eina_List *path_list = NULL;
App_Data appdata;
Ecore_Getopt_Value values[] = {
ECORE_GETOPT_VALUE_INT(max_threads),
ECORE_GETOPT_VALUE_INT(max_msgs),
ECORE_GETOPT_VALUE_LIST(path_list),
ECORE_GETOPT_VALUE_BOOL(opt_quit),
ECORE_GETOPT_VALUE_NONE
};
ecore_init();
i = ecore_thread_max_get();
printf("Initial max threads: %d\n", i);
memset(&appdata, 0, sizeof(App_Data));
appdata.max_msgs = 1;
if (ecore_getopt_parse(&optdesc, values, argc, argv) < 0)
{
printf("Argument parsing failed\n");
return 1;
}
if (opt_quit)
return 0;
if (max_threads)
{
ecore_thread_max_set(max_threads);
printf("Max threads: %d\n", ecore_thread_max_get());
}
if (max_msgs)
appdata.max_msgs = max_msgs;
if (!path_list)
{
Feedback_Thread_Data *ftd;
ecore_thread_global_data_add("count", (void *)3, NULL, EINA_FALSE);
ftd = calloc(1, sizeof(Feedback_Thread_Data));
ftd->name = strdup("data0");
#ifdef _WIN32
ftd->base = strdup("c:/windows/System32");
#else
ftd->base = strdup("/usr/bin");
#endif
eina_lock_new(&ftd->mutex);
ecore_thread_global_data_add(ftd->name, ftd, NULL, EINA_TRUE);
ftd = calloc(1, sizeof(Feedback_Thread_Data));
ftd->name = strdup("data1");
#ifdef _WIN32
ftd->base = strdup("c:/windows/Fonts");
#else
ftd->base = strdup("/usr/lib");
#endif
eina_lock_new(&ftd->mutex);
ecore_thread_global_data_add(ftd->name, ftd, NULL, EINA_TRUE);
ftd = calloc(1, sizeof(Feedback_Thread_Data));
ftd->name = strdup("data2");
#ifdef _WIN32
ftd->base = strdup("c:/windows/Help");
#else
ftd->base = strdup("/usr/lib");
#endif
eina_lock_new(&ftd->mutex);
ecore_thread_global_data_add(ftd->name, ftd, NULL, EINA_TRUE);
}
else
{
Feedback_Thread_Data *ftd;
char *str;
ecore_thread_global_data_add("count",
(void *)(uintptr_t)eina_list_count(path_list), NULL,
EINA_FALSE);
i = 0;
EINA_LIST_FREE(path_list, str)
{
char buf[32];
snprintf(buf, sizeof(buf), "data%d", i);
ftd = calloc(1, sizeof(Feedback_Thread_Data));
ftd->name = strdup(buf);
ftd->base = strdup(str);
eina_lock_new(&ftd->mutex);
ecore_thread_global_data_add(ftd->name, ftd, NULL, EINA_TRUE);
free(str);
i++;
}
}
eina_lock_new(&appdata.mutex);
eina_condition_new(&appdata.condition, &appdata.mutex);
ecore_thread_feedback_run(_out_of_pool_job, _feedback_job_msg_cb, NULL,
NULL, &appdata, EINA_TRUE);
ecore_thread_run(_short_job, _thread_end_cb, _thread_cancel_cb, &appdata);
ecore_thread_feedback_run(_feedback_job, _feedback_job_msg_cb,
_thread_end_cb, _thread_cancel_cb, &appdata,
EINA_FALSE);
appdata.thread_3 = ecore_thread_run(_short_job, _thread_end_cb,
_thread_cancel_cb, &appdata);
ecore_thread_feedback_run(_feedback_job, _feedback_job_msg_cb,
_thread_end_cb, _thread_cancel_cb, &appdata,
EINA_FALSE);
ecore_timer_add(1.0, _cancel_timer_cb, &appdata);
ecore_timer_add(2.0, _status_timer_cb, NULL);
_print_status();
ecore_main_loop_begin();
eina_condition_free(&appdata.condition);
eina_lock_free(&appdata.mutex);
ecore_shutdown();
return 0;
}
ECORE_GETOPT_VALUE_NONE
#define ECORE_GETOPT_VALUE_NONE
Definition for options that store a NULL value.
Definition: Ecore_Getopt.h:1018
ECORE_GETOPT_VALUE_INT
#define ECORE_GETOPT_VALUE_INT(val)
Definition for options that store a single value in a variable of type int.
Definition: Ecore_Getopt.h:955
ECORE_GETOPT_VALUE_LIST
#define ECORE_GETOPT_VALUE_LIST(val)
Definition for options that store a single value in a variable of type list.
Definition: Ecore_Getopt.h:1011
ECORE_GETOPT_APPEND_METAVAR
#define ECORE_GETOPT_APPEND_METAVAR(shortname, longname, help, metavar, type)
Definition for filling Ecore_Getopt_Desc table with an append action and a metavar.
Definition: Ecore_Getopt.h:788
ECORE_GETOPT_VALUE_BOOL
#define ECORE_GETOPT_VALUE_BOOL(val)
Definition for options that store a single value in a variable of type boolean.
Definition: Ecore_Getopt.h:941
ecore_getopt_parse
EAPI int ecore_getopt_parse(const Ecore_Getopt *parser, Ecore_Getopt_Value *values, int argc, char **argv)
Parses command line parameters.
Definition: ecore_getopt.c:2032
ECORE_GETOPT_HELP
#define ECORE_GETOPT_HELP(shortname, longname)
Definition for filling Ecore_Getopt_Desc table with a help action.
Definition: Ecore_Getopt.h:859
ECORE_GETOPT_STORE_INT
#define ECORE_GETOPT_STORE_INT(shortname, longname, help)
Definition for macro that fill Ecore_Getopt_Desc table with an option of type int.
Definition: Ecore_Getopt.h:279
ECORE_GETOPT_SENTINEL
#define ECORE_GETOPT_SENTINEL
Definition for filling Ecore_Getopt_Desc table with a sentinel to indicate the end of descriptions.
Definition: Ecore_Getopt.h:927
ECORE_GETOPT_TYPE_STR
@ ECORE_GETOPT_TYPE_STR
Value of type string.
Definition: Ecore_Getopt.h:87
ecore_shutdown
EAPI int ecore_shutdown(void)
Shuts down connections, signal handlers sockets etc.
Definition: ecore.c:371
ecore_init
EAPI int ecore_init(void)
Sets up connections, signal handlers, sockets etc.
Definition: ecore.c:230
ecore_main_loop_quit
void ecore_main_loop_quit(void)
Quits the main loop once all the events currently on the queue have been processed.
Definition: ecore_main.c:1321
ecore_main_loop_begin
void ecore_main_loop_begin(void)
Runs the application main loop.
Definition: ecore_main.c:1311
ecore_thread_global_data_find
void * ecore_thread_global_data_find(const char *key)
Gets data stored in the hash shared by all threads.
Definition: ecore_thread.c:1438
Ecore_Thread
struct _Ecore_Thread Ecore_Thread
A handle for threaded jobs.
Definition: Ecore_Common.h:1729
ecore_thread_local_data_find
void * ecore_thread_local_data_find(Ecore_Thread *thread, const char *key)
Gets data stored in the hash local to the given thread.
Definition: ecore_thread.c:1320
ecore_thread_pending_get
int ecore_thread_pending_get(void)
Gets the number of short jobs waiting for a thread to run.
Definition: ecore_thread.c:1169
ecore_thread_feedback_run
Ecore_Thread * ecore_thread_feedback_run(Ecore_Thread_Cb func_heavy, Ecore_Thread_Notify_Cb func_notify, Ecore_Thread_Cb func_end, Ecore_Thread_Cb func_cancel, const void *data, Eina_Bool try_no_queue)
Launches a thread to run a task that can talk back to the main thread.
Definition: ecore_thread.c:911
ecore_thread_global_data_add
Eina_Bool ecore_thread_global_data_add(const char *key, void *value, Eina_Free_Cb cb, Eina_Bool direct)
Adds some data to a hash shared by all threads.
Definition: ecore_thread.c:1360
ecore_thread_local_data_add
Eina_Bool ecore_thread_local_data_add(Ecore_Thread *thread, const char *key, void *value, Eina_Free_Cb cb, Eina_Bool direct)
Adds some data to a hash local to the thread.
Definition: ecore_thread.c:1241
ecore_thread_available_get
int ecore_thread_available_get(void)
Gets the number of threads available for running tasks.
Definition: ecore_thread.c:1230
ecore_thread_check
Eina_Bool ecore_thread_check(Ecore_Thread *thread)
Checks if a thread is pending cancellation.
Definition: ecore_thread.c:892
ecore_thread_global_data_del
Eina_Bool ecore_thread_global_data_del(const char *key)
Deletes from the shared hash the data corresponding to the given key.
Definition: ecore_thread.c:1456
ecore_thread_feedback
Eina_Bool ecore_thread_feedback(Ecore_Thread *thread, const void *msg_data)
Sends data from the worker thread to the main loop.
Definition: ecore_thread.c:1037
ecore_thread_pending_feedback_get
int ecore_thread_pending_feedback_get(void)
Gets the number of feedback jobs waiting for a thread to run.
Definition: ecore_thread.c:1181
ecore_thread_run
Ecore_Thread * ecore_thread_run(Ecore_Thread_Cb func_blocking, Ecore_Thread_Cb func_end, Ecore_Thread_Cb func_cancel, const void *data)
Schedules a task to run in a parallel thread to avoid locking the main loop.
Definition: ecore_thread.c:658
ecore_thread_max_set
void ecore_thread_max_set(int num)
Sets the maximum number of threads allowed to run simultaneously.
Definition: ecore_thread.c:1212
ecore_thread_max_get
int ecore_thread_max_get(void)
Gets the maximum number of threads that can run simultaneously.
Definition: ecore_thread.c:1205
ecore_thread_local_data_del
Eina_Bool ecore_thread_local_data_del(Ecore_Thread *thread, const char *key)
Deletes from the thread's hash the data corresponding to the given key.
Definition: ecore_thread.c:1341
ecore_thread_active_get
int ecore_thread_active_get(void)
Gets the number of active threads running jobs.
Definition: ecore_thread.c:1162
ecore_thread_reschedule
Eina_Bool ecore_thread_reschedule(Ecore_Thread *thread)
Asks for the function in the thread to be called again at a later time.
Definition: ecore_thread.c:1149
ecore_thread_cancel
Eina_Bool ecore_thread_cancel(Ecore_Thread *thread)
Cancels a running thread.
Definition: ecore_thread.c:741
ecore_thread_pending_total_get
int ecore_thread_pending_total_get(void)
Gets the total number of pending jobs.
Definition: ecore_thread.c:1193
ecore_timer_add
Ecore_Timer * ecore_timer_add(double in, Ecore_Task_Cb func, const void *data)
Creates a timer to call the given function in the given period of time.
Definition: ecore_timer.c:189
eina_file_ls
EINA_API Eina_Iterator * eina_file_ls(const char *dir)
Gets an iterator to list the content of a directory.
Definition: eina_file_posix.c:631
eina_iterator_free
EINA_API void eina_iterator_free(Eina_Iterator *iterator)
Frees an iterator.
Definition: eina_iterator.c:98
EINA_ITERATOR_FOREACH
#define EINA_ITERATOR_FOREACH(itr, data)
Definition for the macro to iterate over all elements easily.
Definition: eina_iterator.h:448
eina_list_count
static unsigned int eina_list_count(const Eina_List *list)
Gets the count of the number of items in a list.
eina_list_append
EINA_API Eina_List * eina_list_append(Eina_List *list, const void *data)
Appends the given data to the given linked list.
Definition: eina_list.c:584
EINA_LIST_FREE
#define EINA_LIST_FREE(list, data)
Definition for the macro to remove each list node while having access to each node's data.
Definition: eina_list.h:1629
eina_lock_take_try
static Eina_Lock_Result eina_lock_take_try(Eina_Lock *mutex)
Attempts to take a lock if possible.
eina_condition_wait
static Eina_Bool eina_condition_wait(Eina_Condition *cond)
Causes a thread to wait until signaled by the condition.
eina_lock_take
static Eina_Lock_Result eina_lock_take(Eina_Lock *mutex)
Attempts to take a lock.
Eina_Lock
struct _Eina_Lock Eina_Lock
An opaque type for working with locks.
Definition: eina_inline_lock_posix.x:78
eina_condition_signal
static Eina_Bool eina_condition_signal(Eina_Condition *cond)
Signals a thread waiting for a condition.
eina_lock_release
static Eina_Lock_Result eina_lock_release(Eina_Lock *mutex)
Releases a lock.
Eina_Condition
struct _Eina_Condition Eina_Condition
An opaque type that represents a condition variable.
Definition: eina_inline_lock_posix.x:80
eina_condition_free
static void eina_condition_free(Eina_Condition *cond)
Deallocates a condition variable.
eina_lock_new
static Eina_Bool eina_lock_new(Eina_Lock *mutex)
Initializes a new Eina_Lock.
eina_condition_new
static Eina_Bool eina_condition_new(Eina_Condition *cond, Eina_Lock *mutex)
Initializes a new condition variable.
eina_lock_free
static void eina_lock_free(Eina_Lock *mutex)
Deallocates an Eina_Lock.
eina_stringshare_del
EINA_API void eina_stringshare_del(Eina_Stringshare *str)
Notes that the given string has lost an instance.
Definition: eina_stringshare.c:533
eina_stringshare_strlen
EINA_API int eina_stringshare_strlen(Eina_Stringshare *str)
Notes that the given string must be shared.
Definition: eina_stringshare.c:726
EINA_TRUE
#define EINA_TRUE
boolean value TRUE (numerical value 1)
Definition: eina_types.h:539
EINA_FALSE
#define EINA_FALSE
boolean value FALSE (numerical value 0)
Definition: eina_types.h:533
Eina_Bool
unsigned char Eina_Bool
Type to mimic a boolean.
Definition: eina_types.h:527
EINA_UNUSED
#define EINA_UNUSED
Used to indicate that a function parameter is purposely unused.
Definition: eina_types.h:339
_Ecore_Getopt
Structure that contains information on all command line options.
Definition: Ecore_Getopt.h:212
_Eina_Iterator
structure of an iterator
Definition: eina_iterator.h:159
_Eina_List
Type for a generic double linked list.
Definition: eina_list.h:318
_Ecore_Getopt_Value
Union listing the types of parameters that can take Getopt values.
Definition: Ecore_Getopt.h:130