From 1261f21c8ea6796812d63e170409d21e78d01860 Mon Sep 17 00:00:00 2001 From: cedric Date: Fri, 19 Oct 2012 05:48:16 +0000 Subject: [PATCH] eina: add Eina_Thread API. git-svn-id: http://svn.enlightenment.org/svn/e/trunk/eina@78226 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33 --- ChangeLog | 4 + NEWS | 1 + src/include/Eina.h | 1 + src/include/Makefile.am | 1 + src/include/eina_thread.h | 82 ++++++++++++++ src/lib/Makefile.am | 1 + src/lib/eina_main.c | 4 + src/lib/eina_thread.c | 279 ++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 373 insertions(+) create mode 100644 src/include/eina_thread.h create mode 100644 src/lib/eina_thread.c diff --git a/ChangeLog b/ChangeLog index 0fd926f..7ebb53b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -367,3 +367,7 @@ * eina_stringshare_add_length return NULL when func args are wrong. +2012-10-19 Cedric Bail + + * Add eina_thread API. + diff --git a/NEWS b/NEWS index 0f7da58..ad5d69c 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,7 @@ Changes since Eina 1.7.0: Additions: * Add DOCTYPE children parsing in eina_simple_xml * Add eina_barrier thread API + * Add eina_thread API. Improvements: * Speedup Eina Rbtree Iterator by recycling memory instead of massively calling malloc/free. diff --git a/src/include/Eina.h b/src/include/Eina.h index 584bccd..71e8b59 100644 --- a/src/include/Eina.h +++ b/src/include/Eina.h @@ -225,6 +225,7 @@ extern "C" { #include "eina_cpu.h" #include "eina_sched.h" #include "eina_tiler.h" +#include "eina_thread.h" #include "eina_hamster.h" #include "eina_matrixsparse.h" #include "eina_str.h" diff --git a/src/include/Makefile.am b/src/include/Makefile.am index 2bc629f..16323cf 100644 --- a/src/include/Makefile.am +++ b/src/include/Makefile.am @@ -43,6 +43,7 @@ eina_inline_mempool.x \ eina_inline_rectangle.x \ eina_inline_trash.x \ eina_trash.h \ +eina_thread.h \ eina_iterator.h \ eina_main.h \ eina_cpu.h \ diff --git a/src/include/eina_thread.h b/src/include/eina_thread.h new file mode 100644 index 0000000..e615e27 --- /dev/null +++ b/src/include/eina_thread.h @@ -0,0 +1,82 @@ +/* EINA - EFL data type library + * Copyright (C) 2012 Cedric Bail + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; + * if not, see . + */ + +#ifndef EINA_THREAD_H_ +#define EINA_THREAD_H_ + +#include "eina_config.h" +#include "eina_types.h" +#include "eina_error.h" + +/** + * @addtogroup Eina_Tools_Group Tools + * + * @{ + */ + +/** + * @defgroup Eina_Thread_Group Thread + * + * @{ + */ + +#ifdef EINA_HAVE_THREADS +# ifdef _WIN32_WCE + +typedef unsigned long int Eina_Thread; + +# elif defined(_WIN32) + +typedef unsigned long int Eina_Thread; + +# else +# include + +typedef pthread_t Eina_Thread; + +# endif +#else +# error "Build without thread is not supported any more" +#endif + +typedef void *(*Eina_Thread_Cb)(void *data, Eina_Thread t); + +typedef enum _Eina_Thread_Priority +{ + EINA_THREAD_URGENT, + EINA_THREAD_NORMAL, + EINA_THREAD_BACKGROUND, + EINA_THREAD_IDLE +} Eina_Thread_Priority; + +EAPI Eina_Thread eina_thread_self(void); +EAPI Eina_Bool eina_thread_equal(Eina_Thread t1, Eina_Thread t2); +EAPI Eina_Bool eina_thread_create(Eina_Thread *t, + Eina_Thread_Priority prio, Eina_Bool affinity, + Eina_Thread_Cb func, const void *data); +EAPI void *eina_thread_join(Eina_Thread t); + +/** + * @} + */ + +/** + * @} + */ + +#endif diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 115c9d4..0e017c3 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -49,6 +49,7 @@ eina_strbuf.c \ eina_strbuf_common.c \ eina_stringshare.c \ eina_tiler.c \ +eina_thread.c \ eina_unicode.c \ eina_ustrbuf.c \ eina_ustringshare.c \ diff --git a/src/lib/eina_main.c b/src/lib/eina_main.c index e6236b9..fb2bb0d 100644 --- a/src/lib/eina_main.c +++ b/src/lib/eina_main.c @@ -156,6 +156,8 @@ EAPI Eina_Inlist *_eina_tracking = NULL; S(file); S(prefix); S(value); + S(tmpstr); + S(thread); /* no model for now S(model); */ @@ -196,6 +198,8 @@ static const struct eina_desc_setup _eina_desc_setup[] = { S(file), S(prefix), S(value), + S(tmpstr), + S(thread) /* no model for now S(model) */ diff --git a/src/lib/eina_thread.c b/src/lib/eina_thread.c new file mode 100644 index 0000000..e7a5fcd --- /dev/null +++ b/src/lib/eina_thread.c @@ -0,0 +1,279 @@ +/* EINA - EFL data type library + * Copyright (C) 2012 Cedric Bail + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; + * if not, see . + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#ifdef HAVE_EVIL +# include +#endif + +#include "eina_config.h" +#include "eina_thread.h" +#include "eina_sched.h" + +#ifdef EINA_HAVE_THREADS +# ifdef _WIN32_WCE + +# elif defined(_WIN32) + +# define WIN32_LEAN_AND_MEAN +# include +# undef WIN32_LEAN_AND_MEAN + +typedef struct _Eina_Thread_Win32 Eina_Thread_Win32; +struct _Eina_Thread_Win32 +{ + HANDLE thread; + Eina_Thread_Cb func; + void *data; + void *ret; + + Eina_Thread index; +}; + +/* FIXME: For the moment Eina_Thread is considered not + thread safe, wondering if it's worth it */ +static unsigned long int _current_index = 1; /* start from one as the main loop == 0 */ +static Eina_List *_thread_pool = NULL; +static Eina_List *_thread_running = NULL; + +static Eina_Thread_Win32 * +_eina_thread_win32_find(Eina_Thread index) +{ + Eina_Thread_Win32 *tw; + Eina_List *l; + + EINA_LIST_FOREACH(_thread_running, l, tw) + if (tw->index == index) + return tw; + return NULL; +} + +static Eina_Thread +_eina_thread_win32_self(void) +{ + HANDLE t; + + t = GetCurrentThread(); + EINA_LIST_FOREACH(_thread_running, l, tw) + if (tw->thread == t) + return tw->index; + + /* We assume main loop == 0 on Windows */ + return 0; +} + +static Eina_Bool +_eina_thread_win32_equal(Eina_Thread t1, Eina_Thread t2) +{ + if (t1 == t2) return EINA_TRUE; + return EINA_FALSE; +} + +static DWORD WINAPI +_eina_thread_win32_cb(LPVOID lpParam) +{ + Eina_Thread_Win32 *tw = lpParam; + + tw->ret = tw->func(tw->data, tw->index); + + return 0; +} + +static Eina_Bool +_eina_thread_win32_create(Eina_Thread *t, + Eina_Thread_Cb func, + const void *data) +{ + Eina_Thread_Win32 *tw; + Eina_List *l; + + tw = eina_list_data_get(_thread_pool); + _thread_pool = eina_list_remove_list(_thread_pool, _thread_pool); + + if (!tw) + { + tw = malloc(sizeof (Eina_Thread_Win32)); + if (!tw) goto on_error; + + do { + tw->index = _current_index++; + } while (tw->index == 0); /* prevent having a "false" main loop */ + } + + tw->func = f; + tw->data = d; + + tw->thread = CreateThread(NULL, 0, _eina_thread_win32_cb, tw, 0, NULL); + if (!tw->thread) goto on_error; + + _thread_running = eina_list_append(_thread_running, tw); + + *t = tw->index; + return EINA_TRUE; + + on_error: + _thread_pool = eina_list_append(_thread_pool, tw); + return EINA_FALSE; +} + +static void * +_eina_thread_win32_join(Eina_Thread t) +{ + Eina_Thread_Win32 *tw; + void *ret; + + tw = _eina_thread_win32_find(index); + if (!tw) return NULL; + + WaitForSingleObject(tw->thread, INFINITE); + CloseHandle(tw->thread); + + ret = tw->ret; + + tw->ret = NULL; + tw->thread = NULL; + tw->func = NULL; + tw->data = NULL; + + _thread_running = eina_list_remove(_thread_running, tw); + _thread_pool = eina_list_append(_thread_pool, _thread_pool); + + return ret; +} + +# define PHE(x, y) _eina_thread_win32_equal(x, y) +# define PHS() _eina_thread_win32_self() +# define PHC(x, f, d) _eina_thread_win32_create(x, f, d) +# define PHJ(x) _eina_thread_win32_join(x) + +# else +# include + +# ifdef __linux__ +# include +# include +# include +# include +# include +# endif + +static void * +_eina_thread_join(Eina_Thread t) +{ + void *ret = NULL; + + if (!pthread_join(t, &ret)) + return ret; + return NULL; +} + +# define PHE(x, y) pthread_equal(x, y) +# define PHS() pthread_self() +# define PHC(x, f, d) pthread_create(x, NULL, (void*) f, d) +# define PHJ(x) _eina_thread_join(x) + +# endif +#else +# error "Not supported any more" +#endif + +typedef struct _Eina_Thread_Call Eina_Thread_Call; +struct _Eina_Thread_Call +{ + Eina_Thread_Cb func; + const void *data; + + Eina_Thread_Priority prio; + Eina_Bool affinity; +}; + +#include "eina_thread.h" + +static void * +_eina_internal_call(void *context) +{ + Eina_Thread_Call *c = context; + void *r; + + if (c->prio == EINA_THREAD_BACKGROUND || + c->prio == EINA_THREAD_IDLE) + eina_sched_prio_drop(); + + /* FIXME: set priority and affinity */ + r = c->func((void*) c->data, eina_thread_self()); + + free(c); + + return r; +} + +EAPI Eina_Thread +eina_thread_self(void) +{ + return PHS(); +} + +EAPI Eina_Bool +eina_thread_equal(Eina_Thread t1, Eina_Thread t2) +{ + return !!(PHE(t1, t2)); +} + +EAPI Eina_Bool +eina_thread_create(Eina_Thread *t, + Eina_Thread_Priority prio, Eina_Bool affinity, + Eina_Thread_Cb func, const void *data) +{ + Eina_Thread_Call *c; + + c = malloc(sizeof (Eina_Thread_Call)); + if (!c) return EINA_FALSE; + + c->func = func; + c->data = data; + c->prio = prio; + c->affinity = affinity; + + if (PHC(t, _eina_internal_call, c) == 0) + return EINA_TRUE; + + free(c); + + return EINA_FALSE; +} + +EAPI void * +eina_thread_join(Eina_Thread t) +{ + return PHJ(t); +} + +void +eina_thread_init(void) +{ +} + +void +eina_thread_shutdown(void) +{ +} -- 2.7.4