eina: remove Windows specific thread implementation and rely on posix compliant library instead.

This commit is contained in:
Adrien Nader 2015-02-11 12:15:43 +01:00 committed by Cedric BAIL
parent c0683bc2dd
commit 2cb0c1cadc
7 changed files with 9 additions and 905 deletions

View File

@ -25,17 +25,7 @@ gl_LOCK
AC_DEFINE([EFL_HAVE_THREADS], [1], [Define to mention that POSIX or Win32 threads are supported])
case "$host_os" in
mingw*)
_efl_have_win32_threads="yes"
efl_have_setaffinity="yes"
AC_DEFINE([EFL_HAVE_WIN32_THREADS], [1], [Define to mention that Win32 threads are supported])
;;
*)
_efl_have_posix_threads="${gl_use_threads}"
AC_DEFINE([EFL_HAVE_POSIX_THREADS], [1], [Define to mention that POSIX threads are supported])
;;
esac
_efl_have_posix_threads="${gl_use_threads}"
dnl System specific CFLAGS
if test "x${_efl_have_posix_threads}" = "xyes"; then

View File

@ -35,9 +35,7 @@
# elif defined (__linux__) || defined(__GLIBC__)
# include <sched.h>
# endif
# ifdef EFL_HAVE_POSIX_THREADS
# include <pthread.h>
# endif
# include <pthread.h>
# define TH_MAX 8
#endif

View File

@ -1,610 +0,0 @@
/* EINA - EFL data type library
* Copyright (C) 2011 Vincent Torri
*
* 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_INLINE_LOCK_WIN32_X_
#define EINA_INLINE_LOCK_WIN32_X_
#ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#undef WIN32_LEAN_AND_MEAN
/** @privatesection @{ */
typedef CRITICAL_SECTION Eina_Lock;
typedef struct _Eina_Condition Eina_Condition;
typedef struct _Eina_RWLock Eina_RWLock;
typedef DWORD Eina_TLS;
typedef HANDLE Eina_Semaphore;
typedef Eina_Lock Eina_Spinlock;
#if _WIN32_WINNT >= 0x0600
struct _Eina_Condition
{
CRITICAL_SECTION *mutex; /**< The locking mechanism for this condition variable */
CONDITION_VARIABLE condition; /**< The condition variable */
};
struct _Eina_RWLock
{
SRWLOCK mutex; /**< The locking mechanism */
Eina_Bool is_read_mode : 1; /**< Indicates if the lock is a read lock */
};
#else
struct _Eina_Condition
{
int waiters_count; /**< The count of threads that are waiting on this condition */
CRITICAL_SECTION waiters_count_lock; /**< The locking mechanism for the waiters_count member */
CRITICAL_SECTION *mutex; /**< The locking mechanism for the condition */
HANDLE semaphore; /**< Semaphore used to coordinate waiters */
HANDLE waiters_done; /**< Event to trigger when all the waiters are done */
Eina_Bool was_broadcast; /**< Indicates whether this condition has signalled its waiters */
};
struct _Eina_RWLock
{
LONG readers_count; /**< The number of readers waiting for locks */
LONG writers_count; /**< The number of writers waiting for locks */
int readers; /**< The number of readers that have locks */
int writers; /**< The number of writers that have locks */
Eina_Lock mutex; /**< The locking mechanism */
Eina_Condition cond_read; /**< The condition for readers */
Eina_Condition cond_write; /**< The condition for writers */
};
#endif
/** @} privatesection */
EAPI extern Eina_Bool _eina_threads_activated;
EAPI extern Eina_Bool _eina_thread_tls_cb_register(Eina_TLS key, Eina_TLS_Delete_Cb cb);
EAPI extern Eina_Bool _eina_thread_tls_cb_unregister(Eina_TLS key);
EAPI extern Eina_Bool _eina_thread_tls_key_add(Eina_TLS key);
static inline Eina_Bool
eina_lock_new(Eina_Lock *mutex)
{
InitializeCriticalSection(mutex);
return EINA_TRUE;
}
static inline void
eina_lock_free(Eina_Lock *mutex)
{
DeleteCriticalSection(mutex);
}
static inline Eina_Lock_Result
eina_lock_take(Eina_Lock *mutex)
{
#ifdef EINA_HAVE_ON_OFF_THREADS
if (!_eina_threads_activated) return EINA_LOCK_SUCCEED;
#endif
EnterCriticalSection(mutex);
return EINA_LOCK_SUCCEED;
}
static inline Eina_Lock_Result
eina_lock_take_try(Eina_Lock *mutex)
{
#ifdef EINA_HAVE_ON_OFF_THREADS
if (!_eina_threads_activated) return EINA_LOCK_SUCCEED;
#endif
return TryEnterCriticalSection(mutex) == 0 ? EINA_LOCK_FAIL : EINA_LOCK_SUCCEED;
}
static inline Eina_Lock_Result
eina_lock_release(Eina_Lock *mutex)
{
#ifdef EINA_HAVE_ON_OFF_THREADS
if (!_eina_threads_activated) return EINA_LOCK_SUCCEED;
#endif
LeaveCriticalSection(mutex);
return EINA_LOCK_SUCCEED;
}
static inline void
eina_lock_debug(const Eina_Lock *mutex)
{
(void)mutex;
}
static inline Eina_Bool
eina_condition_new(Eina_Condition *cond, Eina_Lock *mutex)
{
cond->mutex = mutex;
#if _WIN32_WINNT >= 0x0600
InitializeConditionVariable(&cond->condition);
#else
cond->waiters_count = 0;
cond->was_broadcast = EINA_FALSE;
cond->semaphore = CreateSemaphore(NULL, // no security
0, // initially 0
0x7fffffff, // max count
NULL); // unnamed
if (!cond->semaphore)
return EINA_FALSE;
InitializeCriticalSection(&cond->waiters_count_lock);
cond->waiters_done = CreateEvent(NULL, // no security
FALSE, // auto-reset
FALSE, // non-signaled initially
NULL); // unnamed
if (!cond->waiters_done)
{
CloseHandle(cond->semaphore);
return EINA_FALSE;
}
#endif
return EINA_TRUE;
}
static inline void
eina_condition_free(Eina_Condition *cond)
{
#if _WIN32_WINNT >= 0x0600
/* Nothing to do */
(void)cond;
#else
CloseHandle(cond->waiters_done);
DeleteCriticalSection(&cond->waiters_count_lock);
CloseHandle(cond->semaphore);
#endif
}
static inline Eina_Bool
_eina_condition_internal_timedwait(Eina_Condition *cond, DWORD t)
{
#if _WIN32_WINNT >= 0x0600
SleepConditionVariableCS(&cond->condition, cond->mutex, t);
#else
DWORD ret;
Eina_Bool last_waiter;
/* Avoid race conditions. */
EnterCriticalSection(&cond->waiters_count_lock);
cond->waiters_count++;
LeaveCriticalSection(&cond->waiters_count_lock);
/*
* This call atomically releases the mutex and waits on the
* semaphore until <pthread_cond_signal> or <pthread_cond_broadcast>
* are called by another thread.
*/
ret = SignalObjectAndWait(cond->mutex, cond->semaphore, t, FALSE);
if (ret == WAIT_FAILED)
return EINA_FALSE;
/* Reacquire lock to avoid race conditions. */
EnterCriticalSection(&cond->waiters_count_lock);
/* We're no longer waiting... */
cond->waiters_count--;
/* Check to see if we're the last waiter after <pthread_cond_broadcast>. */
last_waiter = (cond->was_broadcast) && (cond->waiters_count == 0);
LeaveCriticalSection(&cond->waiters_count_lock);
/*
* If we're the last waiter thread during this particular broadcast
* then let all the other threads proceed.
*/
if (last_waiter)
{
/*
* This call atomically signals the <waiters_done_> event and waits until
* it can acquire the <external_mutex>. This is required to ensure fairness.
*/
ret = SignalObjectAndWait(cond->waiters_done, cond->mutex, t, FALSE);
if (ret == WAIT_FAILED)
return EINA_FALSE;
}
else
{
/*
* Always regain the external mutex since that's the guarantee we
* give to our callers.
*/
ret = WaitForSingleObject(cond->mutex, t);
if (ret == WAIT_FAILED)
return EINA_FALSE;
}
#endif
return EINA_TRUE;
}
static inline Eina_Bool
eina_condition_timedwait(Eina_Condition *cond, double val)
{
return _eina_condition_internal_timedwait(cond, (DWORD)(val * 1000));
}
static inline Eina_Bool
eina_condition_wait(Eina_Condition *cond)
{
return _eina_condition_internal_timedwait(cond, INFINITE);
}
static inline Eina_Bool
eina_condition_broadcast(Eina_Condition *cond)
{
#if _WIN32_WINNT >= 0x0600
WakeAllConditionVariable(&cond->condition);
return EINA_TRUE;
#else
Eina_Bool have_waiters;
/*
* This is needed to ensure that <waiters_count_> and <was_broadcast_> are
* consistent relative to each other.
*/
EnterCriticalSection(&cond->waiters_count_lock);
have_waiters = EINA_FALSE;
if (cond->waiters_count > 0)
{
/*
* We are broadcasting, even if there is just one waiter...
* Record that we are broadcasting, which helps optimize
* <pthread_cond_wait> for the non-broadcast case.
*/
cond->was_broadcast = EINA_TRUE;
have_waiters = EINA_TRUE;
}
if (have_waiters)
{
DWORD ret;
/* Wake up all the waiters atomically. */
ret = ReleaseSemaphore(cond->semaphore, cond->waiters_count, 0);
LeaveCriticalSection(&cond->waiters_count_lock);
if (!ret) return EINA_FALSE;
/*
* Wait for all the awakened threads to acquire the counting
* semaphore.
*/
ret = WaitForSingleObject(cond->waiters_done, INFINITE);
if (ret == WAIT_FAILED)
return EINA_FALSE;
/*
* This assignment is okay, even without the <waiters_count_lock_> held
* because no other waiter threads can wake up to access it.
*/
cond->was_broadcast = EINA_FALSE;
}
else
LeaveCriticalSection(&cond->waiters_count_lock);
return EINA_TRUE;
#endif
}
static inline Eina_Bool
eina_condition_signal(Eina_Condition *cond)
{
#if _WIN32_WINNT >= 0x0600
WakeConditionVariable(&cond->condition);
#else
Eina_Bool have_waiters;
EnterCriticalSection(&cond->waiters_count_lock);
have_waiters = (cond->waiters_count > 0);
LeaveCriticalSection(&cond->waiters_count_lock);
/* If there aren't any waiters, then this is a no-op. */
if (have_waiters)
{
if (!ReleaseSemaphore(cond->semaphore, 1, 0))
return EINA_FALSE;
}
#endif
return EINA_TRUE;
}
static inline Eina_Bool
eina_rwlock_new(Eina_RWLock *mutex)
{
#if _WIN32_WINNT >= 0x0600
InitializeSRWLock(&mutex->mutex);
return EINA_TRUE;
#else
if (!eina_lock_new(&(mutex->mutex))) return EINA_FALSE;
if (!eina_condition_new(&(mutex->cond_read), &(mutex->mutex)))
goto on_error1;
if (!eina_condition_new(&(mutex->cond_write), &(mutex->mutex)))
goto on_error2;
mutex->readers_count = 0;
mutex->writers_count = 0;
mutex->readers = 0;
mutex->writers = 0;
return EINA_TRUE;
on_error2:
eina_condition_free(&(mutex->cond_read));
on_error1:
eina_lock_free(&(mutex->mutex));
return EINA_FALSE;
#endif
}
static inline void
eina_rwlock_free(Eina_RWLock *mutex)
{
#if _WIN32_WINNT >= 0x0600
(void)mutex;
#else
eina_condition_free(&(mutex->cond_read));
eina_condition_free(&(mutex->cond_write));
eina_lock_free(&(mutex->mutex));
#endif
}
static inline Eina_Lock_Result
eina_rwlock_take_read(Eina_RWLock *mutex)
{
#if _WIN32_WINNT >= 0x0600
AcquireSRWLockShared(&mutex->mutex);
mutex->is_read_mode = EINA_TRUE;
#else
DWORD res = 0;
if (eina_lock_take(&(mutex->mutex)) == EINA_LOCK_FAIL)
return EINA_LOCK_FAIL;
if (mutex->writers)
{
mutex->readers_count++;
while (mutex->writers)
{
EnterCriticalSection(&mutex->cond_write.waiters_count_lock);
mutex->cond_read.waiters_count++;
LeaveCriticalSection(&mutex->cond_write.waiters_count_lock);
res = WaitForSingleObject(mutex->cond_write.semaphore, INFINITE);
if (res != WAIT_OBJECT_0) break;
}
mutex->readers_count--;
}
if (res == 0)
mutex->readers++;
eina_lock_release(&(mutex->mutex));
#endif
return EINA_LOCK_SUCCEED;
}
static inline Eina_Lock_Result
eina_rwlock_take_write(Eina_RWLock *mutex)
{
#if _WIN32_WINNT >= 0x0600
AcquireSRWLockExclusive(&mutex->mutex);
mutex->is_read_mode = EINA_FALSE;
#else
DWORD res = 0;
if (eina_lock_take(&(mutex->mutex)) == EINA_LOCK_FAIL)
return EINA_LOCK_FAIL;
if (mutex->writers || mutex->readers > 0)
{
mutex->writers_count++;
while (mutex->writers || mutex->readers > 0)
{
EnterCriticalSection(&mutex->cond_write.waiters_count_lock);
mutex->cond_read.waiters_count++;
LeaveCriticalSection(&mutex->cond_write.waiters_count_lock);
res = WaitForSingleObject(mutex->cond_write.semaphore, INFINITE);
if (res != WAIT_OBJECT_0) break;
}
mutex->writers_count--;
}
if (res == 0) mutex->writers = 1;
eina_lock_release(&(mutex->mutex));
#endif
return EINA_LOCK_SUCCEED;
}
static inline Eina_Lock_Result
eina_rwlock_release(Eina_RWLock *mutex)
{
#if _WIN32_WINNT >= 0x0600
if (mutex->is_read_mode)
ReleaseSRWLockShared(&mutex->mutex);
else
ReleaseSRWLockExclusive(&mutex->mutex);
#else
if (eina_lock_take(&(mutex->mutex)) == EINA_LOCK_FAIL)
return EINA_LOCK_FAIL;
if (mutex->writers)
{
mutex->writers = 0;
if (mutex->readers_count == 1)
{
EnterCriticalSection(&mutex->cond_read.waiters_count_lock);
if (mutex->cond_read.waiters_count > 0)
ReleaseSemaphore(mutex->cond_read.semaphore, 1, 0);
LeaveCriticalSection(&mutex->cond_read.waiters_count_lock);
}
else if (mutex->readers_count > 0)
eina_condition_broadcast(&(mutex->cond_read));
else if (mutex->writers_count > 0)
{
EnterCriticalSection (&mutex->cond_write.waiters_count_lock);
if (mutex->cond_write.waiters_count > 0)
ReleaseSemaphore(mutex->cond_write.semaphore, 1, 0);
LeaveCriticalSection (&mutex->cond_write.waiters_count_lock);
}
}
else if (mutex->readers > 0)
{
mutex->readers--;
if (mutex->readers == 0 && mutex->writers_count > 0)
{
EnterCriticalSection (&mutex->cond_write.waiters_count_lock);
if (mutex->cond_write.waiters_count > 0)
ReleaseSemaphore(mutex->cond_write.semaphore, 1, 0);
LeaveCriticalSection (&mutex->cond_write.waiters_count_lock);
}
}
eina_lock_release(&(mutex->mutex));
#endif
return EINA_LOCK_SUCCEED;
}
static inline Eina_Bool
eina_tls_cb_new(Eina_TLS *key, Eina_TLS_Delete_Cb delete_cb)
{
if ((*key = TlsAlloc()) == TLS_OUT_OF_INDEXES)
return EINA_FALSE;
if (delete_cb)
{
if (!_eina_thread_tls_cb_register(*key, delete_cb))
{
TlsFree(*key);
return EINA_FALSE;
}
}
return EINA_TRUE;
}
static inline Eina_Bool
eina_tls_new(Eina_TLS *key)
{
return eina_tls_cb_new(key, NULL);
}
static inline void
eina_tls_free(Eina_TLS key)
{
_eina_thread_tls_cb_unregister(key);
TlsFree(key);
}
static inline void *
eina_tls_get(Eina_TLS key)
{
return (void*)TlsGetValue(key);
}
static inline Eina_Bool
eina_tls_set(Eina_TLS key, const void *data)
{
if (TlsSetValue(key, (LPVOID)data) == 0)
return EINA_FALSE;
_eina_thread_tls_key_add(key);
return EINA_TRUE;
}
static inline Eina_Bool
eina_semaphore_new(Eina_Semaphore *sem, int count_init)
{
if (!sem || (count_init <= 0))
return EINA_FALSE;
*sem = CreateSemaphore(NULL, count_init, 32767, NULL);
if (!*sem)
return EINA_FALSE;
return EINA_TRUE;
}
static inline Eina_Bool
eina_semaphore_free(Eina_Semaphore *sem)
{
if (!sem)
return EINA_FALSE;
CloseHandle(*sem);
return EINA_TRUE;
}
static inline Eina_Bool
eina_semaphore_lock(Eina_Semaphore *sem)
{
DWORD res;
if (!sem)
return EINA_FALSE;
res = WaitForSingleObject(*sem, 0L);
if (res == WAIT_OBJECT_0)
return EINA_TRUE;
return EINA_FALSE;
}
static inline Eina_Bool
eina_semaphore_release(Eina_Semaphore *sem, int count_release)
{
if (!sem)
return EINA_FALSE;
return ReleaseSemaphore(*sem, count_release, NULL) ? EINA_TRUE : EINA_FALSE;
}
// FIXME: Implement proper spinlock = http://www.codeproject.com/Articles/184046/Spin-Lock-in-C
static inline Eina_Bool
eina_spinlock_new(Eina_Spinlock *spinlock)
{
return eina_lock_new(spinlock);
}
static inline Eina_Lock_Result
eina_spinlock_take(Eina_Spinlock *spinlock)
{
return eina_lock_take(spinlock);
}
static inline Eina_Lock_Result
eina_spinlock_take_try(Eina_Spinlock *spinlock)
{
return eina_lock_take_try(spinlock);
}
static inline Eina_Lock_Result
eina_spinlock_release(Eina_Spinlock *spinlock)
{
return eina_lock_release(spinlock);
}
static inline void
eina_spinlock_free(Eina_Spinlock *spinlock)
{
eina_lock_free(spinlock);
}
#include "eina_inline_lock_barrier.x"
#endif

View File

@ -97,11 +97,7 @@ typedef enum
*/
typedef void (*Eina_TLS_Delete_Cb)(void *ptr);
#ifdef _WIN32
# include "eina_inline_lock_win32.x"
#else
# include "eina_inline_lock_posix.x"
#endif
/**
* @brief A type definition for warning that a function was called from

View File

@ -103,11 +103,7 @@ EAPI Eina_Error EINA_ERROR_NOT_MAIN_LOOP = 0;
EAPI unsigned int eina_seed = 0;
#ifdef EFL_HAVE_THREADS
# ifdef _WIN32
EAPI DWORD _eina_main_loop;
# else
EAPI pthread_t _eina_main_loop;
# endif
static pid_t _eina_pid;
#endif
@ -117,10 +113,8 @@ static int _mt_enabled = 0;
#ifdef EFL_HAVE_THREADS
EAPI int _eina_threads_debug = 0;
# if !defined(_WIN32)
EAPI pthread_mutex_t _eina_tracking_lock;
EAPI Eina_Inlist *_eina_tracking = NULL;
# endif
#endif
/* place module init/shutdown functions here to avoid other modules
@ -280,11 +274,7 @@ eina_init(void)
}
#ifdef EFL_HAVE_THREADS
# ifdef _WIN32
_eina_main_loop = GetCurrentThreadId();
# else
_eina_main_loop = pthread_self();
# endif
_eina_pid = getpid();
#endif
@ -426,24 +416,10 @@ eina_main_loop_is(void)
{
#ifdef EFL_HAVE_THREADS
pid_t pid;
# ifdef _WIN32
if (_eina_main_loop == GetCurrentThreadId())
if (pthread_equal(_eina_main_loop, pthread_self()))
return EINA_TRUE;
# else
if (pthread_equal(_eina_main_loop, pthread_self()))
return EINA_TRUE;
# endif
pid = getpid();
# ifdef _WIN32
if (pid != _eina_pid)
{
_eina_pid = pid;
_eina_main_loop = GetCurrentThreadId();
return EINA_TRUE;
}
#else
if (pid != _eina_pid)
{
/* This is in case of a fork, but don't like the solution */
@ -451,7 +427,6 @@ eina_main_loop_is(void)
_eina_main_loop = pthread_self();
return EINA_TRUE;
}
#endif
#endif
return EINA_FALSE;
@ -463,11 +438,7 @@ eina_main_loop_define(void)
{
#ifdef EFL_HAVE_THREADS
_eina_pid = getpid();
# ifdef _WIN32
_eina_main_loop = GetCurrentThreadId();
# else
_eina_main_loop = pthread_self();
# endif
#endif
}

View File

@ -20,14 +20,12 @@
# include "config.h"
#endif
#ifdef EFL_HAVE_POSIX_THREADS
# include <pthread.h>
# ifdef __linux__
# include <sched.h>
# include <sys/time.h>
# include <sys/resource.h>
# include <errno.h>
# endif
#include <pthread.h>
#ifdef __linux__
# include <sched.h>
# include <sys/time.h>
# include <sys/resource.h>
# include <errno.h>
#endif
#ifdef EFL_HAVE_WIN32_THREADS
@ -47,7 +45,6 @@
EAPI void
eina_sched_prio_drop(void)
{
#ifdef EFL_HAVE_POSIX_THREADS
struct sched_param param;
int pol, ret;
pthread_t pthread_id;
@ -92,11 +89,4 @@ eina_sched_prio_drop(void)
}
}
# endif
#elif defined EFL_HAVE_WIN32_THREADS
if (!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL))
EINA_LOG_ERR("Can not set thread priority");
#else
EINA_LOG_ERR("Eina does not have support for threads enabled"
"or it doesn't support setting scheduler priorities");
#endif
}

View File

@ -25,238 +25,10 @@
#include "eina_config.h"
#include "eina_thread.h"
#include "eina_sched.h"
#ifdef _WIN32
# include "eina_list.h"
# include "eina_lock.h"
#endif
/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
#include "eina_safety_checks.h"
#ifdef _WIN32
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# undef WIN32_LEAN_AND_MEAN
#include <process.h>
typedef struct _Eina_TLS_Cbs_Win32 Eina_TLS_Cbs_Win32;
struct _Eina_TLS_Cbs_Win32
{
Eina_TLS key;
Eina_TLS_Delete_Cb cb;
};
typedef struct _Eina_Thread_Win32 Eina_Thread_Win32;
struct _Eina_Thread_Win32
{
HANDLE thread;
void *(*func)(void *data);
void *data;
void *ret;
Eina_List *tls_keys;
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_List *_tls_keys_cbs = NULL;
static inline Eina_TLS_Cbs_Win32 *
_eina_thread_tls_cb_find(Eina_TLS key)
{
Eina_TLS_Cbs_Win32 *cb;
Eina_List *l;
EINA_LIST_FOREACH(_tls_keys_cbs, l, cb)
if (cb->key == key)
return cb;
return NULL;
}
static inline void
_eina_thread_tls_keys_clean(Eina_Thread_Win32 *tw)
{
void *data;
Eina_TLS_Cbs_Win32 *cb;
EINA_LIST_FREE(tw->tls_keys, data)
{
Eina_TLS key = (Eina_TLS)(uintptr_t)data;
cb = _eina_thread_tls_cb_find(key);
if (cb)
cb->cb(eina_tls_get(key));
}
tw->tls_keys = NULL;
}
EAPI Eina_Bool
_eina_thread_tls_cb_register(Eina_TLS key, Eina_TLS_Delete_Cb cb)
{
Eina_TLS_Cbs_Win32 *tls_cb;
if (!cb) return EINA_FALSE;
tls_cb = malloc(sizeof(Eina_TLS_Cbs_Win32));
if (!tls_cb) return EINA_FALSE;
tls_cb->key = key;
tls_cb->cb = cb;
_tls_keys_cbs = eina_list_append(_tls_keys_cbs, tls_cb);
return EINA_TRUE;
}
EAPI Eina_Bool
_eina_thread_tls_cb_unregister(Eina_TLS key)
{
Eina_TLS_Cbs_Win32 *cb = _eina_thread_tls_cb_find(key);
if (!cb) return EINA_FALSE;
_tls_keys_cbs = eina_list_remove(_tls_keys_cbs, cb);
free(cb);
return EINA_TRUE;
}
EAPI Eina_Bool
_eina_thread_tls_key_add(Eina_TLS key)
{
HANDLE t;
Eina_Thread_Win32 *tw;
Eina_List *l;
t = GetCurrentThread();
EINA_LIST_FOREACH(_thread_running, l, tw)
if (tw->thread == t)
{
void *data = (void *)(uintptr_t)key;
if (!eina_list_data_find(tw->tls_keys, data))
tw->tls_keys = eina_list_append(tw->tls_keys, data);
return EINA_TRUE;
}
return EINA_FALSE;
}
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 inline Eina_Thread
_eina_thread_self(void)
{
HANDLE t;
Eina_Thread_Win32 *tw;
Eina_List *l;
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 inline Eina_Bool
_eina_thread_equal(Eina_Thread t1, Eina_Thread t2)
{
if (t1 == t2) return EINA_TRUE;
return EINA_FALSE;
}
static unsigned int WINAPI
_eina_thread_win32_cb(LPVOID lpParam)
{
Eina_Thread_Win32 *tw = lpParam;
tw->ret = tw->func(tw->data);
return 0;
}
static inline Eina_Bool
_eina_thread_create(Eina_Thread *t,
int affinity,
void *(*func)(void *data),
const void *data)
{
Eina_Thread_Win32 *tw;
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 = func;
tw->data = (void *)data;
tw->tls_keys = NULL;
tw->thread = (HANDLE)_beginthreadex(NULL, 0, _eina_thread_win32_cb, tw, 0, NULL);
if (!tw->thread) goto on_error;
/* affinity is an hint, if we fail, we continue without */
if (affinity >= 0)
SetThreadAffinityMask(tw->thread, 1 << affinity);
_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 inline void *
_eina_thread_join(Eina_Thread t)
{
Eina_Thread_Win32 *tw;
void *ret;
tw = _eina_thread_win32_find(t);
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;
_eina_thread_tls_keys_clean(tw);
_thread_running = eina_list_remove(_thread_running, tw);
_thread_pool = eina_list_append(_thread_pool, _thread_pool);
return ret;
}
#elif defined(EFL_HAVE_POSIX_THREADS)
# include <pthread.h>
# include <errno.h>
@ -312,9 +84,6 @@ _eina_thread_self(void)
return (Eina_Thread)pthread_self();
}
#else
# error "Not supported any more"
#endif
typedef struct _Eina_Thread_Call Eina_Thread_Call;
struct _Eina_Thread_Call