felipealmeida pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=65d528a3798b72dbd2e01b4f37caa898af50e359

commit 65d528a3798b72dbd2e01b4f37caa898af50e359
Author: Wander Lairson Costa <wander.lair...@gmail.com>
Date:   Sat Apr 17 15:31:09 2021 -0300

    Implement eina_thread for native windows
    
    Summary:
    eina: Implement Eina_Thread for native windows
    
    The implementation design respects the fact that Eina_Thread is an
    uintptr_t. Thus we allocate the thread struct in the heap and return a
    pointer to it.
    
    As such, we store the created thread structure in the target thread
    TLS slot. For threads that were not created through eina API, in
    eina_thread_self we allocate a new structure, push it to the TLS slot
    and mark it to be freed on thread exit.
    
    Reviewers: jptiz, vtorri, cedric, walac
    
    Reviewed By: jptiz, cedric
    
    Subscribers: raster, cedric, #reviewers, #committers, lucas
    
    Tags: #efl
    
    Differential Revision: https://phab.enlightenment.org/D12037
---
 header_checks/meson.build                          |   3 +-
 src/lib/eina/Eina.h                                |   1 -
 src/lib/eina/eina_sched.c                          |  84 -----
 src/lib/eina/eina_sched.h                          |  53 ---
 src/lib/eina/eina_thread.c                         | 295 +--------------
 src/lib/eina/eina_thread.h                         |  36 ++
 .../eina/{eina_thread.c => eina_thread_posix.c}    |  82 +++--
 src/lib/eina/eina_thread_win32.c                   | 397 +++++++++++++++++++++
 src/lib/eina/eina_win32_dllmain.c                  |  18 +
 src/lib/eina/meson.build                           |   6 +-
 src/tests/eina/eina_suite.c                        |   1 +
 src/tests/eina/eina_suite.h                        |   1 +
 src/tests/eina/eina_test_thread.c                  | 124 +++++++
 src/tests/eina/meson.build                         |   1 +
 14 files changed, 649 insertions(+), 453 deletions(-)

diff --git a/header_checks/meson.build b/header_checks/meson.build
index 2f0205f28a..833b9139f6 100644
--- a/header_checks/meson.build
+++ b/header_checks/meson.build
@@ -53,7 +53,8 @@ header_checks = [
   'features.h',
   'langinfo.h',
   'locale.h',
-  'crt_externs.h'
+  'crt_externs.h',
+  'pthread.h',
 ]
 
 #### The below is logically broken
diff --git a/src/lib/eina/Eina.h b/src/lib/eina/Eina.h
index 383696d7d8..d2ce89e805 100644
--- a/src/lib/eina/Eina.h
+++ b/src/lib/eina/Eina.h
@@ -241,7 +241,6 @@ extern "C" {
 #include <eina_benchmark.h>
 #include <eina_convert.h>
 #include <eina_cpu.h>
-#include <eina_sched.h>
 #include <eina_tiler.h>
 #include <eina_hamster.h>
 #include <eina_matrixsparse.h>
diff --git a/src/lib/eina/eina_sched.c b/src/lib/eina/eina_sched.c
deleted file mode 100644
index 3864054712..0000000000
--- a/src/lib/eina/eina_sched.c
+++ /dev/null
@@ -1,84 +0,0 @@
-/* EINA - EFL data type library
- * Copyright (C) 2010 ProFUSION embedded systems
- *
- * 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 <pthread.h>
-#ifdef __linux__
-# include <sched.h>
-# include <sys/time.h>
-# include <sys/resource.h>
-# include <errno.h>
-#endif
-
-#include "eina_sched.h"
-#include "eina_log.h"
-
-#define RTNICENESS 1
-#define NICENESS 5
-
-EINA_API void
-eina_sched_prio_drop(void)
-{
-   struct sched_param param;
-   int pol, ret;
-   pthread_t pthread_id;
-
-   pthread_id = pthread_self();
-   ret = pthread_getschedparam(pthread_id, &pol, &param);
-   if (ret)
-     {
-        EINA_LOG_ERR("Unable to query sched parameters");
-        return;
-     }
-
-   if (EINA_UNLIKELY(pol == SCHED_RR || pol == SCHED_FIFO))
-     {
-        param.sched_priority -= RTNICENESS;
-
-        /* We don't change the policy */
-        if (param.sched_priority < 1)
-          {
-             EINA_LOG_INFO("RT prio < 1, setting to 1 instead");
-             param.sched_priority = 1;
-          }
-
-        pthread_setschedparam(pthread_id, pol, &param);
-     }
-# ifdef __linux__
-   else
-     {
-        int prio;
-        errno = 0;
-        prio = getpriority(PRIO_PROCESS, 0);
-        if (errno == 0)
-          {
-             prio += NICENESS;
-             if (prio > 19)
-               {
-                  EINA_LOG_INFO("Max niceness reached; keeping max (19)");
-                  prio = 19;
-               }
-
-             setpriority(PRIO_PROCESS, 0, prio);
-          }
-     }
-# endif
-}
diff --git a/src/lib/eina/eina_sched.h b/src/lib/eina/eina_sched.h
deleted file mode 100644
index 77d90a31e4..0000000000
--- a/src/lib/eina/eina_sched.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* EINA - EFL data type library
- * Copyright (C) 2010 ProFUSION embedded systems
- *
- * 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/>.
- */
-
-/**
- * @defgroup Schedule Schedule
- * @ingroup Eina_Tools_Group
- *
- * @{
- *
- * TODO: description
- *
- */
-
-#ifndef EINA_SCHED_H_
-#define EINA_SCHED_H_
-
-#include "eina_types.h"
-
-
-/**
- * @brief Lowers the priority of the current thread.
- *
- * @details It's used by worker threads so that they use up the background CPU 
and do not stall
- *          the main thread. If the current thread is running with real-time 
priority, we
- *          decrease our priority by @c RTNICENESS. This is done in a portable 
way.
- *
- *          Otherwise, (we are running with the SCHED_OTHER policy) there's no 
portable way to
- *          set the nice level on the current thread. In Linux, it does work 
and it's the
- *          only one that is implemented as of now. In this case, the nice 
level is
- *          incremented on this thread by @c NICENESS.
- */
-EINA_API void eina_sched_prio_drop(void);
-
-/**
- * @}
- */
-
-#endif /* EINA_SCHED_H_ */
diff --git a/src/lib/eina/eina_thread.c b/src/lib/eina/eina_thread.c
index 75623edb0a..abb04a1bf5 100644
--- a/src/lib/eina/eina_thread.c
+++ b/src/lib/eina/eina_thread.c
@@ -20,284 +20,15 @@
 # include "config.h"
 #endif
 
-#include <stdlib.h>
+#include <stddef.h>
 
-#include "eina_config.h"
-#include "eina_lock.h" /* it will include pthread.h with proper flags */
-#include "eina_thread.h"
-#include "eina_sched.h"
-#include "eina_cpu.h"
-
-/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
-#include "eina_safety_checks.h"
-
-#include "eina_debug_private.h"
-
-#include <pthread.h>
-#include <errno.h>
-#ifndef _WIN32
-# include <signal.h>
-#endif
-# include <string.h>
-
-#if defined(EINA_HAVE_PTHREAD_AFFINITY) || defined(EINA_HAVE_PTHREAD_SETNAME)
-#ifndef __linux__
-#include <pthread_np.h>
-#define cpu_set_t cpuset_t
-#endif
-#endif
-
-static inline void *
-_eina_thread_join(Eina_Thread t)
-{
-   void *ret = NULL;
-   int err = pthread_join((pthread_t)t, &ret);
-
-   if (err == 0) return ret;
-   return NULL;
-}
-
-static inline Eina_Bool
-_eina_thread_create(Eina_Thread *t, int affinity, void *(*func)(void *data), 
void *data)
-{
-   int err;
-   pthread_attr_t attr;
-#ifndef _WIN32
-   sigset_t oldset, newset;
-#endif
-
-   if (pthread_attr_init(&attr) != 0)
-     {
-        return EINA_FALSE;
-     }
-   if (affinity >= 0)
-     {
-#ifdef EINA_HAVE_PTHREAD_AFFINITY
-        cpu_set_t cpu;
-
-        CPU_ZERO(&cpu);
-        CPU_SET(affinity, &cpu);
-        pthread_attr_setaffinity_np(&attr, sizeof(cpu), &cpu);
-#endif
-     }
-
-   /* setup initial locks */
-#ifndef _WIN32
-   sigemptyset(&newset);
-   sigaddset(&newset, SIGPIPE);
-   sigaddset(&newset, SIGALRM);
-   sigaddset(&newset, SIGCHLD);
-   sigaddset(&newset, SIGUSR1);
-   sigaddset(&newset, SIGUSR2);
-   sigaddset(&newset, SIGHUP);
-   sigaddset(&newset, SIGQUIT);
-   sigaddset(&newset, SIGINT);
-   sigaddset(&newset, SIGTERM);
-# ifdef SIGPWR
-   sigaddset(&newset, SIGPWR);
-# endif
-   pthread_sigmask(SIG_BLOCK, &newset, &oldset);
-#endif
-   err = pthread_create((pthread_t *)t, &attr, func, data);
-#ifndef _WIN32
-   pthread_sigmask(SIG_SETMASK, &oldset, NULL);
-#endif
-   pthread_attr_destroy(&attr);
-
-   if (err == 0) return EINA_TRUE;
-
-   return EINA_FALSE;
-}
-
-static inline Eina_Bool
-_eina_thread_equal(Eina_Thread t1, Eina_Thread t2)
-{
-   return pthread_equal((pthread_t)t1, (pthread_t)t2);
-}
-
-static inline Eina_Thread
-_eina_thread_self(void)
-{
-   return (Eina_Thread)pthread_self();
-}
-
-
-typedef struct _Eina_Thread_Call Eina_Thread_Call;
-struct _Eina_Thread_Call
-{
-   Eina_Thread_Cb func;
-   const void *data;
-
-   Eina_Thread_Priority prio;
-   int affinity;
-};
-
-static void *
-_eina_internal_call(void *context)
-{
-   Eina_Thread_Call *c = context;
-   void *r;
-   pthread_t self;
-
-   // Default this thread to not cancellable as per Eina documentation
-   eina_thread_cancellable_set(EINA_FALSE, NULL);
-
-   EINA_THREAD_CLEANUP_PUSH(free, c);
-
-   self = pthread_self();
-
-   if (c->prio == EINA_THREAD_IDLE)
-     {
-        struct sched_param params;
-        int min;
-#ifdef SCHED_IDLE
-        int pol = SCHED_IDLE;
-#else
-        int pol;
-        pthread_getschedparam(self, &pol, &params);
+#ifdef HAVE_PTHREAD_H
+# include <pthread.h>
 #endif
-        min = sched_get_priority_min(pol);
-        params.sched_priority = min;
-        pthread_setschedparam(self, pol, &params);
-     }
-   else if (c->prio == EINA_THREAD_BACKGROUND)
-     {
-        struct sched_param params;
-        int min, max;
-#ifdef SCHED_BATCH
-        int pol = SCHED_BATCH;
-#else
-        int pol;
-        pthread_getschedparam(self, &pol, &params);
-#endif
-        min = sched_get_priority_min(pol);
-        max = sched_get_priority_max(pol);
-        params.sched_priority = (max - min) / 2;
-        pthread_setschedparam(self, pol, &params);
-     }
-// do nothing for normal
-//   else if (c->prio == EINA_THREAD_NORMAL)
-//     {
-//     }
-   else if (c->prio == EINA_THREAD_URGENT)
-     {
-        struct sched_param params;
-        int max, pol;
-
-        pthread_getschedparam(self, &pol, &params);
-        max = sched_get_priority_max(pol);
-        params.sched_priority += 5;
-        if (params.sched_priority > max) params.sched_priority = max;
-        pthread_setschedparam(self, pol, &params);
-     }
-
-   _eina_debug_thread_add(&self);
-   EINA_THREAD_CLEANUP_PUSH(_eina_debug_thread_del, &self);
-   r = c->func((void*) c->data, eina_thread_self());
-   EINA_THREAD_CLEANUP_POP(EINA_TRUE);
-   EINA_THREAD_CLEANUP_POP(EINA_TRUE);
 
-   return r;
-}
-
-EINA_API Eina_Thread
-eina_thread_self(void)
-{
-   return _eina_thread_self();
-}
-
-EINA_API Eina_Bool
-eina_thread_equal(Eina_Thread t1, Eina_Thread t2)
-{
-   return !!_eina_thread_equal(t1, t2);
-}
-
-EINA_API Eina_Bool
-eina_thread_create(Eina_Thread *t,
-                   Eina_Thread_Priority prio, int affinity,
-                   Eina_Thread_Cb func, const void *data)
-{
-   Eina_Thread_Call *c;
-
-   EINA_SAFETY_ON_NULL_RETURN_VAL(t, EINA_FALSE);
-   EINA_SAFETY_ON_NULL_RETURN_VAL(func, EINA_FALSE);
-
-   c = malloc(sizeof (Eina_Thread_Call));
-   if (!c) return EINA_FALSE;
-
-   c->func = func;
-   c->data = data;
-   c->prio = prio;
-   c->affinity = affinity;
-
-   // valgrind complains c is lost - but it's not - it is handed to the
-   // child thread to be freed when c->func returns in _eina_internal_call().
-   if (_eina_thread_create(t, affinity, _eina_internal_call, c))
-     return EINA_TRUE;
-
-   free(c);
-   return EINA_FALSE;
-}
-
-EINA_API void *
-eina_thread_join(Eina_Thread t)
-{
-   return _eina_thread_join(t);
-}
-
-EINA_API Eina_Bool
-eina_thread_name_set(Eina_Thread t, const char *name)
-{
-#ifdef EINA_HAVE_PTHREAD_SETNAME
-   char buf[16];
-   if (name)
-     {
-        strncpy(buf, name, 15);
-        buf[15] = 0;
-     }
-   else buf[0] = 0;
-#ifndef __linux__
-   pthread_set_name_np((pthread_t)t, buf);
-   return EINA_TRUE;
-#else
-   if (pthread_setname_np((pthread_t)t, buf) == 0) return EINA_TRUE;
-#endif
-#else
-   (void)t;
-   (void)name;
-#endif
-   return EINA_FALSE;
-}
-
-EINA_API Eina_Bool
-eina_thread_cancel(Eina_Thread t)
-{
-   if (!t) return EINA_FALSE;
-   return pthread_cancel((pthread_t)t) == 0;
-}
-
-EINA_API Eina_Bool
-eina_thread_cancellable_set(Eina_Bool cancellable, Eina_Bool *was_cancellable)
-{
-   int state = cancellable ? PTHREAD_CANCEL_ENABLE : PTHREAD_CANCEL_DISABLE;
-   int old = 0;
-   int r;
-
-   /* enforce deferred in case users changed to asynchronous themselves */
-   pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &old);
-
-   r = pthread_setcancelstate(state, &old);
-   if (was_cancellable && r == 0)
-     *was_cancellable = (old == PTHREAD_CANCEL_ENABLE);
-
-   return r == 0;
-}
-
-EINA_API void
-eina_thread_cancel_checkpoint(void)
-{
-   pthread_testcancel();
-}
+#include "eina_types.h"
+#include "eina_config.h"
+#include "eina_thread.h"
 
 EINA_API void *
 eina_thread_cancellable_run(Eina_Thread_Cancellable_Run_Cb cb, Eina_Free_Cb 
cleanup_cb, void *data)
@@ -312,17 +43,3 @@ eina_thread_cancellable_run(Eina_Thread_Cancellable_Run_Cb 
cb, Eina_Free_Cb clea
    eina_thread_cancellable_set(old, NULL);
    return ret;
 }
-
-EINA_API const void *EINA_THREAD_JOIN_CANCELED = PTHREAD_CANCELED;
-
-Eina_Bool
-eina_thread_init(void)
-{
-   return EINA_TRUE;
-}
-
-Eina_Bool
-eina_thread_shutdown(void)
-{
-   return EINA_TRUE;
-}
diff --git a/src/lib/eina/eina_thread.h b/src/lib/eina/eina_thread.h
index d0ca8138c2..9c0b93bf1f 100644
--- a/src/lib/eina/eina_thread.h
+++ b/src/lib/eina/eina_thread.h
@@ -51,6 +51,12 @@ typedef uintptr_t Eina_Thread;
  */
 typedef void *(*Eina_Thread_Cb)(void *data, Eina_Thread t);
 
+/**
+ * @typedef Eina_Thread_Cleanup_Cb
+ * Type for the definition of a thread cleanup function
+ */
+typedef void (*Eina_Thread_Cleanup_Cb) (void *data);
+
 /**
  * @typedef Eina_Thread_Priority
  * Type to enumerate different thread priorities
@@ -248,8 +254,16 @@ EINA_API void eina_thread_cancel_checkpoint(void);
  *
  * @since 1.19
  */
+#ifdef _WIN32
+EINA_API Eina_Bool
+eina_thread_cleanup_push(Eina_Thread_Cleanup_Cb fn, void *data);
+
+#define EINA_THREAD_CLEANUP_PUSH(cleanup, data) \
+  eina_thread_cleanup_push(cleanup, data)
+#else
 #define EINA_THREAD_CLEANUP_PUSH(cleanup, data) \
   pthread_cleanup_push(cleanup, data)
+#endif
 
 /**
  * @def EINA_THREAD_CLEANUP_POP(exec_cleanup)
@@ -278,8 +292,16 @@ EINA_API void eina_thread_cancel_checkpoint(void);
  *
  * @since 1.19
  */
+#ifdef _WIN32
+EINA_API void
+eina_thread_cleanup_pop(int execute);
+
+#define EINA_THREAD_CLEANUP_POP(exec_cleanup) \
+  eina_thread_cleanup_pop(exec_cleanup)
+#else
 #define EINA_THREAD_CLEANUP_POP(exec_cleanup) \
   pthread_cleanup_pop(exec_cleanup)
+#endif
 
 /**
  * @typedef Eina_Thread_Cancellable_Run_Cb
@@ -333,6 +355,20 @@ typedef void *(*Eina_Thread_Cancellable_Run_Cb)(void 
*data);
  */
 EINA_API void *eina_thread_cancellable_run(Eina_Thread_Cancellable_Run_Cb cb, 
Eina_Free_Cb cleanup_cb, void *data);
 
+/**
+ * @brief Lowers the priority of the current thread.
+ *
+ * @details It's used by worker threads so that they use up the background CPU 
and do not stall
+ *          the main thread. If the current thread is running with real-time 
priority, we
+ *          decrease our priority by @c RTNICENESS. This is done in a portable 
way.
+ *
+ *          Otherwise, (we are running with the SCHED_OTHER policy) there's no 
portable way to
+ *          set the nice level on the current thread. In Linux, it does work 
and it's the
+ *          only one that is implemented as of now. In this case, the nice 
level is
+ *          incremented on this thread by @c NICENESS.
+ */
+EINA_API void eina_sched_prio_drop(void);
+
 /**
  * @}
  */
diff --git a/src/lib/eina/eina_thread.c b/src/lib/eina/eina_thread_posix.c
similarity index 84%
copy from src/lib/eina/eina_thread.c
copy to src/lib/eina/eina_thread_posix.c
index 75623edb0a..da793bd48d 100644
--- a/src/lib/eina/eina_thread.c
+++ b/src/lib/eina/eina_thread_posix.c
@@ -25,7 +25,6 @@
 #include "eina_config.h"
 #include "eina_lock.h" /* it will include pthread.h with proper flags */
 #include "eina_thread.h"
-#include "eina_sched.h"
 #include "eina_cpu.h"
 
 /* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
@@ -47,6 +46,18 @@
 #endif
 #endif
 
+#ifdef __linux__
+# include <sched.h>
+# include <sys/time.h>
+# include <sys/resource.h>
+#endif
+
+#include "eina_log.h"
+
+#define RTNICENESS 1
+#define NICENESS 5
+
+
 static inline void *
 _eina_thread_join(Eina_Thread t)
 {
@@ -62,9 +73,7 @@ _eina_thread_create(Eina_Thread *t, int affinity, void 
*(*func)(void *data), voi
 {
    int err;
    pthread_attr_t attr;
-#ifndef _WIN32
    sigset_t oldset, newset;
-#endif
 
    if (pthread_attr_init(&attr) != 0)
      {
@@ -82,7 +91,6 @@ _eina_thread_create(Eina_Thread *t, int affinity, void 
*(*func)(void *data), voi
      }
 
    /* setup initial locks */
-#ifndef _WIN32
    sigemptyset(&newset);
    sigaddset(&newset, SIGPIPE);
    sigaddset(&newset, SIGALRM);
@@ -97,11 +105,8 @@ _eina_thread_create(Eina_Thread *t, int affinity, void 
*(*func)(void *data), voi
    sigaddset(&newset, SIGPWR);
 # endif
    pthread_sigmask(SIG_BLOCK, &newset, &oldset);
-#endif
    err = pthread_create((pthread_t *)t, &attr, func, data);
-#ifndef _WIN32
    pthread_sigmask(SIG_SETMASK, &oldset, NULL);
-#endif
    pthread_attr_destroy(&attr);
 
    if (err == 0) return EINA_TRUE;
@@ -299,29 +304,64 @@ eina_thread_cancel_checkpoint(void)
    pthread_testcancel();
 }
 
-EINA_API void *
-eina_thread_cancellable_run(Eina_Thread_Cancellable_Run_Cb cb, Eina_Free_Cb 
cleanup_cb, void *data)
+EINA_API const void *EINA_THREAD_JOIN_CANCELED = PTHREAD_CANCELED;
+
+EINA_API void
+eina_sched_prio_drop(void)
 {
-   Eina_Bool old = EINA_FALSE;
-   void *ret;
+   struct sched_param param;
+   int pol, ret;
+   pthread_t pthread_id;
 
-   EINA_THREAD_CLEANUP_PUSH(cleanup_cb, data);
-   eina_thread_cancellable_set(EINA_TRUE, &old); // is a cancellation point
-   ret = cb(data); // may not run if was previously canceled
-   EINA_THREAD_CLEANUP_POP(EINA_TRUE);
-   eina_thread_cancellable_set(old, NULL);
-   return ret;
-}
+   pthread_id = pthread_self();
+   ret = pthread_getschedparam(pthread_id, &pol, &param);
+   if (ret)
+     {
+        EINA_LOG_ERR("Unable to query sched parameters");
+        return;
+     }
 
-EINA_API const void *EINA_THREAD_JOIN_CANCELED = PTHREAD_CANCELED;
+   if (EINA_UNLIKELY(pol == SCHED_RR || pol == SCHED_FIFO))
+     {
+        param.sched_priority -= RTNICENESS;
 
-Eina_Bool
+        /* We don't change the policy */
+        if (param.sched_priority < 1)
+          {
+             EINA_LOG_INFO("RT prio < 1, setting to 1 instead");
+             param.sched_priority = 1;
+          }
+
+        pthread_setschedparam(pthread_id, pol, &param);
+     }
+# ifdef __linux__
+   else
+     {
+        int prio;
+        errno = 0;
+        prio = getpriority(PRIO_PROCESS, 0);
+        if (errno == 0)
+          {
+             prio += NICENESS;
+             if (prio > 19)
+               {
+                  EINA_LOG_INFO("Max niceness reached; keeping max (19)");
+                  prio = 19;
+               }
+
+             setpriority(PRIO_PROCESS, 0, prio);
+          }
+     }
+# endif
+}
+
+EINA_API Eina_Bool
 eina_thread_init(void)
 {
    return EINA_TRUE;
 }
 
-Eina_Bool
+EINA_API Eina_Bool
 eina_thread_shutdown(void)
 {
    return EINA_TRUE;
diff --git a/src/lib/eina/eina_thread_win32.c b/src/lib/eina/eina_thread_win32.c
new file mode 100644
index 0000000000..8f5bf3c1ff
--- /dev/null
+++ b/src/lib/eina/eina_thread_win32.c
@@ -0,0 +1,397 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2020 Expertise Solutions Cons em Inf
+ *
+ * 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 "eina_types.h"
+#include "eina_config.h"
+#include "eina_array.h"
+#include "eina_thread.h"
+#include "eina_main.h"
+#include "eina_debug_private.h"
+#include "eina_log.h"
+
+#include <assert.h>
+#include <evil_private.h>
+#include <process.h>
+
+#define RTNICENESS 1
+#define NICENESS 5
+
+/*
+ * The underlying type of Eina_Thread
+ */
+struct Thread
+{
+   CRITICAL_SECTION cancel_lock; /* mutex to protect the cancel handle */
+   char name[16]; /* the thread name */
+   HANDLE handle; /* thread handle */
+   void *data; /* on entry, the thread function argument, on exit, the return 
value */
+   Eina_Thread_Cb fn; /* the thread function */
+   Eina_Array *cleanup_fn;
+   Eina_Array *cleanup_arg;
+   unsigned id; /* thread id */
+   Eina_Bool free_on_exit; /* free the structure when thread exit */
+   volatile Eina_Bool cancel; /* the cancel event handle */
+   volatile Eina_Bool cancellable; /* is cancel enabled? */
+};
+
+typedef struct Thread Thread_t;
+
+/*
+ * This TLS stores the Eina_Thread for the current thread
+ */
+static DWORD tls_thread_self = 0;
+
+static Thread_t main_thread = { 0 };
+
+/*
+ * If we alloc'ed the Thread_t in eina_thread_self, we set
+ * free_on_exit flag to true, we then free it here
+ */
+void
+free_thread(void)
+{
+   Thread_t *t = TlsGetValue(tls_thread_self);
+   if (t && t->free_on_exit)
+     {
+        if (t) eina_array_free(t->cleanup_fn);
+        if (t) eina_array_free(t->cleanup_arg);
+        free(t);
+     }
+}
+
+static unsigned
+thread_fn(void *arg)
+{
+   Thread_t *thr = arg;
+   TlsSetValue(tls_thread_self, thr);
+   _eina_debug_thread_add(&thr);
+   EINA_THREAD_CLEANUP_PUSH(_eina_debug_thread_del, &thr);
+   thr->data = thr->fn(thr->data, (Eina_Thread) thr);
+   EINA_THREAD_CLEANUP_POP(EINA_TRUE);
+   return 0;
+}
+
+EINA_API Eina_Thread
+eina_thread_self(void)
+{
+    Thread_t *self = TlsGetValue(tls_thread_self);
+    /*
+     * If self is NULL this means
+     * 1) This function was called before eina_thread_init
+     * 2) This thread wasn't created by eina_thread_create
+     *
+     * In either case we alloc a new Thread struct and return
+     * it.
+     */
+    if (!self)
+      {
+         self = calloc(1, sizeof(*self));
+         self->handle = GetCurrentThread();
+         self->id = GetCurrentThreadId();
+         self->free_on_exit = EINA_TRUE;
+         self->cleanup_fn = eina_array_new(4);
+         self->cleanup_arg = eina_array_new(4);
+         if (tls_thread_self)
+            TlsSetValue(tls_thread_self, self);
+      }
+    return (Eina_Thread) self;
+}
+
+EINA_API Eina_Bool
+eina_thread_equal(Eina_Thread t1, Eina_Thread t2)
+{
+   return ((Thread_t *) t1)->id == ((Thread_t *) t2)->id;
+}
+
+EINA_API Eina_Bool
+eina_thread_create(Eina_Thread *t, Eina_Thread_Priority prio,
+                   int affinity, Eina_Thread_Cb func, const void *data)
+{
+   Thread_t *thr = calloc(1, sizeof(Thread_t));
+   if (!thr)
+      return EINA_FALSE;
+
+   thr->data = (void *) data;
+   thr->fn = func;
+
+   thr->handle = (HANDLE) _beginthreadex(NULL, 0, thread_fn, thr, 
CREATE_SUSPENDED, &thr->id);
+   if (!thr->handle)
+      goto fail;
+
+   int priority;
+   switch (prio)
+     {
+        case EINA_THREAD_URGENT:
+           priority = THREAD_PRIORITY_HIGHEST;
+           break;
+        case EINA_THREAD_BACKGROUND:
+           priority = THREAD_PRIORITY_BELOW_NORMAL;
+           break;
+        case EINA_THREAD_IDLE:
+           priority = THREAD_PRIORITY_IDLE;
+           break;
+        default:
+           priority = THREAD_PRIORITY_NORMAL;
+     }
+
+   if (!SetThreadPriority(thr->handle, priority))
+      goto fail;
+
+   if ((affinity >= 0) && (!SetThreadAffinityMask(thr->handle, 1 << affinity)))
+      goto fail;
+
+   thr->id = GetThreadId(thr->handle);
+   if (!thr->id)
+      goto fail;
+
+   thr->cleanup_fn = eina_array_new(4);
+   thr->cleanup_arg = eina_array_new(4);
+   if ((!thr->cleanup_fn) || (!thr->cleanup_arg))
+      goto fail;
+
+   InitializeCriticalSection(&thr->cancel_lock);
+
+   if (!ResumeThread(thr->handle))
+      goto cs_fail;
+
+   GetModuleFileNameA(NULL, thr->name, sizeof(thr->name));
+   *t = (Eina_Thread) thr;
+   return EINA_TRUE;
+
+cs_fail:
+   DeleteCriticalSection(&thr->cancel_lock);
+fail:
+   if (thr)
+     {
+        if (thr->handle) CloseHandle(thr->handle);
+        if (thr->cleanup_fn) eina_array_free(thr->cleanup_fn);
+        if (thr->cleanup_arg) eina_array_free(thr->cleanup_arg);
+        free(thr);
+     }
+   return EINA_FALSE;
+}
+
+EINA_API void *
+eina_thread_join(Eina_Thread t)
+{
+   void *data;
+   Thread_t *thr = (Thread_t *) t;
+
+   if (WAIT_OBJECT_0 == WaitForSingleObject(thr->handle, INFINITE))
+      data = thr->data;
+   else
+      data = NULL;
+
+   DeleteCriticalSection(&thr->cancel_lock);
+   CloseHandle(thr->handle);
+   eina_array_free(thr->cleanup_fn);
+   eina_array_free(thr->cleanup_arg);
+   free(thr);
+
+   return data;
+}
+
+EINA_API Eina_Bool
+eina_thread_name_set(Eina_Thread t, const char *name)
+{
+   Thread_t *thr = (Thread_t *) t;
+   strncpy(thr->name, name, sizeof(thr->name));
+   thr->name[sizeof(thr->name)-1] = '\0';
+   return EINA_TRUE;
+}
+
+EINA_API Eina_Bool
+eina_thread_cancel(Eina_Thread t)
+{
+    Eina_Bool ret = EINA_FALSE;
+    Thread_t *thr = (Thread_t *) t;
+
+    if (thr)
+      {
+         EnterCriticalSection(&thr->cancel_lock);
+         if (thr->cancellable)
+           {
+              thr->cancel = EINA_TRUE;
+              ret = EINA_TRUE;
+           }
+         LeaveCriticalSection(&thr->cancel_lock);
+      }
+    return ret;
+}
+
+EINA_API Eina_Bool
+eina_thread_cancellable_set(Eina_Bool cancellable, Eina_Bool *was_cancellable)
+{
+   Thread_t *t = (Thread_t *) eina_thread_self();
+
+   EnterCriticalSection(&t->cancel_lock);
+   if (was_cancellable) *was_cancellable = t->cancellable;
+   t->cancellable = cancellable;
+   LeaveCriticalSection(&t->cancel_lock);
+
+   return EINA_TRUE;
+}
+
+EINA_API void
+eina_thread_cancel_checkpoint(void)
+{
+   Eina_Bool cancel;
+   Thread_t *t = (Thread_t *) eina_thread_self();
+
+   EnterCriticalSection(&t->cancel_lock);
+   cancel = t->cancellable && t->cancel;
+   LeaveCriticalSection(&t->cancel_lock);
+
+   if (cancel)
+     {
+        t->data = (void *) EINA_THREAD_JOIN_CANCELED;
+        while (eina_array_count(t->cleanup_fn))
+          {
+             Eina_Thread_Cleanup_Cb fn = (Eina_Thread_Cleanup_Cb) 
eina_array_pop(t->cleanup_fn);
+             void *arg = eina_array_pop(t->cleanup_arg);
+
+             if (fn)
+               fn(arg);
+          }
+
+        ExitThread(0);
+     }
+}
+
+EINA_API Eina_Bool
+eina_thread_cleanup_push(Eina_Thread_Cleanup_Cb fn, void *data)
+{
+   Thread_t *t = TlsGetValue(tls_thread_self);
+   assert(t);
+
+   if (!eina_array_push(t->cleanup_fn, fn))
+      return EINA_FALSE;
+
+   if (!eina_array_push(t->cleanup_arg, data))
+     {
+        eina_array_pop(t->cleanup_fn);
+        return EINA_FALSE;
+     }
+
+   return EINA_TRUE;
+}
+
+EINA_API void
+eina_thread_cleanup_pop(int execute)
+{
+   Thread_t *t = TlsGetValue(tls_thread_self);
+   assert(t);
+
+   if (eina_array_count(t->cleanup_fn))
+     {
+        Eina_Thread_Cleanup_Cb fn = (Eina_Thread_Cleanup_Cb) 
eina_array_pop(t->cleanup_fn);
+        void *arg = eina_array_pop(t->cleanup_arg);
+
+        if (execute && fn)
+           fn(arg);
+     }
+}
+
+EINA_API const void *EINA_THREAD_JOIN_CANCELED = (void *) -1L;
+
+void
+eina_sched_prio_drop(void)
+{
+   Thread_t *thread;
+   int sched_priority;
+
+   thread = (Thread_t *) eina_thread_self();
+
+   sched_priority = GetThreadPriority(thread->handle);
+
+   if (EINA_UNLIKELY(sched_priority == THREAD_PRIORITY_TIME_CRITICAL))
+     {
+        sched_priority -= RTNICENESS;
+
+        /* We don't change the policy */
+        if (sched_priority < 1)
+          {
+             EINA_LOG_INFO("RT prio < 1, setting to 1 instead");
+             sched_priority = 1;
+          }
+        if (!SetThreadPriority(thread->handle, sched_priority))
+          {
+             EINA_LOG_ERR("Unable to query sched parameters");
+          }
+     }
+   else
+     {
+        sched_priority += NICENESS;
+
+        /* We don't change the policy */
+        if (sched_priority > THREAD_PRIORITY_TIME_CRITICAL)
+          {
+             EINA_LOG_INFO("Max niceness reached; keeping max 
(THREAD_PRIORITY_TIME_CRITICAL)");
+             sched_priority = THREAD_PRIORITY_TIME_CRITICAL;
+          }
+        if (!SetThreadPriority(thread->handle, sched_priority))
+          {
+             EINA_LOG_ERR("Unable to query sched parameters");
+          }
+     }
+}
+
+EINA_API Eina_Bool
+eina_thread_init(void)
+{
+   if (!eina_main_loop_is())
+      return EINA_FALSE;
+
+   tls_thread_self = TlsAlloc();
+   if (TLS_OUT_OF_INDEXES == tls_thread_self)
+      return EINA_FALSE;
+
+   if (!TlsSetValue(tls_thread_self, &main_thread))
+     {
+        assert(0);
+        TlsFree(tls_thread_self);
+        return EINA_FALSE;
+     }
+
+   main_thread.cancellable = EINA_FALSE;
+   main_thread.cancel = EINA_FALSE;
+   main_thread.handle = GetCurrentThread();
+   main_thread.id = GetCurrentThreadId();
+
+   InitializeCriticalSection(&main_thread.cancel_lock);
+   main_thread.cleanup_fn = eina_array_new(2);
+   main_thread.cleanup_arg = eina_array_new(2);
+
+   GetModuleFileNameA(NULL, main_thread.name, 
sizeof(main_thread.name)/sizeof(main_thread.name[0]));
+
+   return EINA_TRUE;
+}
+
+EINA_API Eina_Bool
+eina_thread_shutdown(void)
+{
+   DeleteCriticalSection(&main_thread.cancel_lock);
+   eina_array_free(main_thread.cleanup_fn);
+   eina_array_free(main_thread.cleanup_arg);
+   TlsFree(tls_thread_self);
+   return EINA_TRUE;
+}
diff --git a/src/lib/eina/eina_win32_dllmain.c 
b/src/lib/eina/eina_win32_dllmain.c
new file mode 100644
index 0000000000..3285aebebb
--- /dev/null
+++ b/src/lib/eina/eina_win32_dllmain.c
@@ -0,0 +1,18 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "eina_config.h"
+#include "eina_types.h"
+#include <evil_private.h>
+
+void free_thread(void);
+
+BOOL WINAPI
+DllMain(HINSTANCE inst EINA_UNUSED, WORD reason, PVOID reserved EINA_UNUSED)
+{
+   if (DLL_THREAD_DETACH == reason)
+      free_thread();
+
+   return TRUE;
+}
diff --git a/src/lib/eina/meson.build b/src/lib/eina/meson.build
index 8d5d4383d1..afe945d754 100644
--- a/src/lib/eina/meson.build
+++ b/src/lib/eina/meson.build
@@ -66,7 +66,6 @@ public_sub_headers = [
 'eina_main.h',
 'eina_cpu.h',
 'eina_inline_cpu.x',
-'eina_sched.h',
 'eina_tiler.h',
 'eina_hamster.h',
 'eina_matrixsparse.h',
@@ -168,7 +167,6 @@ eina_src = files([
 'eina_rbtree.c',
 'eina_rectangle.c',
 'eina_safety_checks.c',
-'eina_sched.c',
 'eina_share_common.c',
 'eina_simple_xml_parser.c',
 'eina_str.c',
@@ -200,9 +198,9 @@ eina_src = files([
 ]) + eina_mp_sources
 
 if sys_windows == true
-  eina_src += files('eina_file_win32.c')
+  eina_src += files('eina_file_win32.c', 'eina_win32_dllmain.c', 
'eina_thread_win32.c')
 else
-  eina_src += files('eina_file_posix.c')
+  eina_src += files('eina_file_posix.c', 'eina_thread_posix.c')
 endif
 
 eina_config = configuration_data()
diff --git a/src/tests/eina/eina_suite.c b/src/tests/eina/eina_suite.c
index 01ed82a532..7561878c8b 100644
--- a/src/tests/eina/eina_suite.c
+++ b/src/tests/eina/eina_suite.c
@@ -91,6 +91,7 @@ static const Efl_Test_Case etc[] = {
    { "Vpath", eina_test_vpath },
    { "debug", eina_test_debug },
    { "Abstract Content", eina_test_abstract_content },
+   { "thread", eina_test_thread },
    { NULL, NULL }
 };
 
diff --git a/src/tests/eina/eina_suite.h b/src/tests/eina/eina_suite.h
index 84d6e60516..c9e5476ae7 100644
--- a/src/tests/eina/eina_suite.h
+++ b/src/tests/eina/eina_suite.h
@@ -79,5 +79,6 @@ void eina_test_slstr(TCase *tc);
 void eina_test_vpath(TCase *tc);
 void eina_test_debug(TCase *tc);
 void eina_test_abstract_content(TCase *tc);
+void eina_test_thread(TCase *tc);
 
 #endif /* EINA_SUITE_H_ */
diff --git a/src/tests/eina/eina_test_thread.c 
b/src/tests/eina/eina_test_thread.c
new file mode 100644
index 0000000000..2b35907db7
--- /dev/null
+++ b/src/tests/eina/eina_test_thread.c
@@ -0,0 +1,124 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2020 Expertise Solutions Cons em Inf
+ *
+ * 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/>.
+ */
+
+#include <check.h>
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef HAVE_UNISTD
+# include <unistd.h>
+#endif
+
+#ifdef _WIN32
+# include <evil_private.h> /* mkdir */
+#endif
+
+#include <Eina.h>
+#include "eina_suite.h"
+
+static void
+thread_cleanup_fn(void *arg)
+{
+   *(int *) arg  = 1;
+}
+
+static void *
+thread_fn_execute(void *arg, Eina_Thread t EINA_UNUSED)
+{
+   EINA_THREAD_CLEANUP_PUSH(thread_cleanup_fn, arg);
+   EINA_THREAD_CLEANUP_POP(1);
+   return NULL;
+}
+
+static void *
+thread_fn_skip(void *arg, Eina_Thread t EINA_UNUSED)
+{
+   EINA_THREAD_CLEANUP_PUSH(thread_cleanup_fn, arg);
+   EINA_THREAD_CLEANUP_POP(0);
+   return NULL;
+}
+
+static void *
+thread_fn_cancel(void *arg, Eina_Thread t EINA_UNUSED)
+{
+   Eina_Condition *cond = arg;
+
+   ck_assert(eina_thread_cancellable_set(EINA_TRUE, NULL));
+   ck_assert(eina_condition_signal(cond));
+
+   for (size_t i = 0; i < 100; ++i)
+     {
+        eina_thread_cancel_checkpoint();
+#ifdef _WIN32
+        Sleep(100);
+#else
+        usleep(100 * 1000);
+#endif
+     }
+
+   return NULL;
+}
+
+EFL_START_TEST(eina_thread_test_cleanup_execute)
+{
+   Eina_Thread t;
+   int flag = 0;
+   ck_assert(eina_thread_create(&t, EINA_THREAD_NORMAL, -1, thread_fn_execute, 
&flag));
+   eina_thread_join(t);
+   ck_assert_uint_eq(flag, 1);
+}
+EFL_END_TEST
+
+EFL_START_TEST(eina_thread_test_cleanup_skip)
+{
+   Eina_Thread t;
+   int flag = 2;
+   ck_assert(eina_thread_create(&t, EINA_THREAD_NORMAL, -1, thread_fn_skip, 
&flag));
+   eina_thread_join(t);
+   ck_assert_uint_eq(flag, 2);
+}
+EFL_END_TEST
+
+EFL_START_TEST(eina_thread_test_cancel)
+{
+   Eina_Thread t;
+   Eina_Lock mutex;
+   Eina_Condition cond;
+
+   ck_assert(eina_lock_new(&mutex));
+   ck_assert(eina_condition_new(&cond, &mutex));
+
+   ck_assert(eina_thread_create(&t, EINA_THREAD_NORMAL, -1, thread_fn_cancel, 
&cond));
+   ck_assert(eina_lock_take(&mutex));
+   ck_assert(eina_condition_wait(&cond));
+   ck_assert(eina_thread_cancel(t));
+   ck_assert_ptr_eq(eina_thread_join(t), EINA_THREAD_JOIN_CANCELED);
+
+   eina_condition_free(&cond);
+   eina_lock_free(&mutex);
+}
+EFL_END_TEST
+
+void
+eina_test_thread(TCase *tc)
+{
+   tcase_add_test(tc, eina_thread_test_cleanup_skip);
+   tcase_add_test(tc, eina_thread_test_cleanup_execute);
+   tcase_add_test(tc, eina_thread_test_cancel);
+}
diff --git a/src/tests/eina/meson.build b/src/tests/eina/meson.build
index 18c8f91ced..0d09819e74 100644
--- a/src/tests/eina/meson.build
+++ b/src/tests/eina/meson.build
@@ -56,6 +56,7 @@ eina_test_src = files(
 'eina_test_slstr.c',
 'eina_test_vpath.c',
 'eina_test_abstract_content.c',
+'eina_test_thread.c',
 )
 
 

-- 


Reply via email to