eina: add Eina_Thread API.
authorcedric <cedric>
Fri, 19 Oct 2012 05:48:16 +0000 (05:48 +0000)
committercedric <cedric@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Fri, 19 Oct 2012 05:48:16 +0000 (05:48 +0000)
git-svn-id: http://svn.enlightenment.org/svn/e/trunk/eina@78226 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

ChangeLog
NEWS
src/include/Eina.h
src/include/Makefile.am
src/include/eina_thread.h [new file with mode: 0644]
src/lib/Makefile.am
src/lib/eina_main.c
src/lib/eina_thread.c [new file with mode: 0644]

index 0fd926f..7ebb53b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
 
        * 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 (file)
--- 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.
index 584bccd..71e8b59 100644 (file)
@@ -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"
index 2bc629f..16323cf 100644 (file)
@@ -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 (file)
index 0000000..e615e27
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+ */
+
+#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 <pthread.h>
+
+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
index 115c9d4..0e017c3 100644 (file)
@@ -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 \
index e6236b9..fb2bb0d 100644 (file)
@@ -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 (file)
index 0000000..e7a5fcd
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#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 <windows.h>
+#  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 <pthread.h>
+
+#  ifdef __linux__
+#   include <sched.h>
+#   include <sys/resource.h>
+#   include <unistd.h>
+#   include <sys/syscall.h>
+#   include <errno.h>
+#  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)
+{
+}