Windows:eina: Add Thread synchronization (#34)

This should add all needed functions/structures for thread synchronization besides:
- eina_condition initialization;
- cond_timedwait.
This commit is contained in:
Lucas 2020-04-30 14:11:51 -03:00 committed by GitHub
parent 728e1afde9
commit ea6d1c40ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 1231 additions and 654 deletions

View File

@ -49,7 +49,7 @@
// broken on OSX in that a HUP signal will maybe cause a crash... but compiling
// with -pg would have guaranteed always caused a crash before anyway.
// given OSX only supports "old-style" signals like:
//
//
// #define SIGHUP 1 /* hangup */
// #define SIGINT 2 /* interrupt */
// #define SIGQUIT 3 /* quit */
@ -90,7 +90,7 @@
// #endif
// #define SIGUSR1 30 /* user defined signal 1 */
// #define SIGUSR2 31 /* user defined signal 2 */
//
//
// (excerpt from OSX's signal.h - found at:
// http://github.com/st3fan/osx-10.9/blob/master/xnu-2422.1.72/bsd/sys/signal.h
// pasting here due to how difficult it was to find a signal list for OSX)

View File

@ -1,26 +0,0 @@
typedef struct _Eina_Barrier Eina_Barrier;
/** @private */
struct _Eina_Barrier
{
int needed; /**< The number of waiting threads that will cause the barrier to signal and reset. */
int called; /**< The number of threads that are waiting on this barrier. */
Eina_Lock cond_lock; /**< The lock for the barrier */
Eina_Condition cond; /**< The condition variable for the barrier */
};
static inline Eina_Bool
eina_barrier_wait(Eina_Barrier *barrier)
{
eina_lock_take(&(barrier->cond_lock));
barrier->called++;
if (barrier->called == barrier->needed)
{
barrier->called = 0;
eina_condition_broadcast(&(barrier->cond));
}
else
eina_condition_wait(&(barrier->cond));
eina_lock_release(&(barrier->cond_lock));
return EINA_TRUE;
}

View File

@ -25,7 +25,26 @@
#endif
#define _XOPEN_SOURCE 600
#ifdef EINA_HAVE_POSIX_SPINLOCK
#ifdef EINA_HAVE_OSX_SPINLOCK
/*
* macOS 10.12 introduced the os_unfair_lock API which
* deprecates OSSpinLock, while keeping compatible.
*
* The Spinlock API is not inlined because it would imply including
* stdbool.h, which is not wanted: it would introduce new macros,
* and break compilation of existing programs.
*/
# if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200
# include <os/lock.h>
# define SPINLOCK_GET(LCK) ((os_unfair_lock_t)(LCK))
# else
# include <libkern/OSAtomic.h>
# define SPINLOCK_GET(LCK) ((OSSpinLock *)(LCK))
# define os_unfair_lock_lock(LCK) OSSpinLockLock(LCK)
# define os_unfair_lock_unlock(LCK) OSSpinLockUnlock(LCK)
# define os_unfair_lock_trylock(LCK) OSSpinLockTry(LCK)
# endif
#elif defined(EINA_HAVE_PTHREAD_SPINLOCK)
# include <sched.h>
#endif
@ -80,7 +99,7 @@ typedef struct _Eina_RWLock Eina_RWLock;
typedef struct _Eina_Condition Eina_Condition;
typedef pthread_key_t Eina_TLS;
#if defined(EINA_HAVE_POSIX_SPINLOCK)
#ifdef EINA_HAVE_PTHREAD_SPINLOCK
typedef pthread_spinlock_t Eina_Spinlock;
#elif defined(EINA_HAVE_OSX_SPINLOCK)
typedef uintptr_t Eina_Spinlock;
@ -99,17 +118,15 @@ EAPI void eina_lock_debug(const Eina_Lock *mutex);
/** @privatesection @{ */
struct _Eina_Lock
{
#ifdef EINA_HAVE_DEBUG_THREADS
EINA_INLIST; /**< Keeps track of the threads waiting for the lock */
#endif
pthread_mutex_t mutex; /**< The mutex that handles the locking */
#ifdef EINA_HAVE_DEBUG_THREADS
EINA_INLIST; /**< Keeps track of the threads waiting for the lock */
pthread_t lock_thread_id; /**< The ID of the thread that currently has the lock */
Eina_Lock_Bt_Func lock_bt[EINA_LOCK_DEBUG_BT_NUM]; /**< The function that will produce a backtrace on the thread that has the lock */
int lock_bt_num; /**< Number of addresses in the backtrace */
Eina_Bool locked : 1; /**< Indicates locked or not locked */
Eina_Bool recursive : 1; /**< Indicates recursive lock */
#endif
#endif /* EINA_HAVE_DEBUG_THREADS */
};
struct _Eina_Condition
@ -139,51 +156,29 @@ EAPI extern pthread_mutex_t _eina_tracking_lock;
EAPI extern Eina_Inlist *_eina_tracking;
#endif
EAPI Eina_Bool _eina_lock_new(Eina_Lock *mutex, Eina_Bool recursive);
EAPI void _eina_lock_free(Eina_Lock *mutex);
EAPI Eina_Bool _eina_condition_new(Eina_Condition *cond, Eina_Lock *mutex);
EAPI void _eina_condition_free(Eina_Condition *cond);
EAPI Eina_Bool _eina_rwlock_new(Eina_RWLock *mutex);
EAPI void _eina_rwlock_free(Eina_RWLock *mutex);
EAPI Eina_Bool _eina_spinlock_new(Eina_Spinlock *spinlock);
EAPI void _eina_spinlock_free(Eina_Spinlock *spinlock);
EAPI Eina_Bool _eina_semaphore_new(Eina_Semaphore *sem, int count_init);
EAPI Eina_Bool _eina_semaphore_free(Eina_Semaphore *sem);
#ifdef EINA_HAVE_OSX_SPINLOCK
EAPI Eina_Lock_Result _eina_spinlock_macos_take(Eina_Spinlock *spinlock);
EAPI Eina_Lock_Result _eina_spinlock_macos_take_try(Eina_Spinlock *spinlock);
EAPI Eina_Lock_Result _eina_spinlock_macos_release(Eina_Spinlock *spinlock);
#endif
static inline Eina_Bool
eina_lock_new(Eina_Lock *mutex)
_eina_lock_new(Eina_Lock *mutex, Eina_Bool recursive)
{
Eina_Bool ret = _eina_lock_new(mutex, EINA_FALSE);
#ifdef EINA_HAVE_DEBUG_THREADS
mutex->recursive = EINA_FALSE;
mutex->lock_thread_id = 0;
mutex->lock_bt_num = 0;
mutex->locked = 0;
#endif
return ret;
}
pthread_mutexattr_t attr;
Eina_Bool ok = EINA_FALSE;
static inline Eina_Bool
eina_lock_recursive_new(Eina_Lock *mutex)
{
Eina_Bool ret = _eina_lock_new(mutex, EINA_TRUE);
if (pthread_mutexattr_init(&attr) != 0) return EINA_FALSE;
if (recursive)
{
if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0) goto fail_release;
}
#ifdef EINA_HAVE_DEBUG_THREADS
mutex->recursive = EINA_TRUE;
mutex->lock_thread_id = 0;
mutex->lock_bt_num = 0;
mutex->locked = 0;
else if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK) != 0) goto fail_release;
#endif
return ret;
if (pthread_mutex_init(&(mutex->mutex), &attr) != 0) goto fail_release;
ok = EINA_TRUE;
fail_release:
pthread_mutexattr_destroy(&attr);
return ok;
}
static inline void
eina_lock_free(Eina_Lock *mutex)
_eina_lock_free(Eina_Lock *mutex)
{
#ifdef EINA_HAVE_DEBUG_THREADS
if (mutex->locked)
@ -194,11 +189,15 @@ eina_lock_free(Eina_Lock *mutex)
pthread_mutex_unlock(&_eina_tracking_lock);
}
#endif
_eina_lock_free(mutex);
int ok;
ok = pthread_mutex_destroy(&(mutex->mutex));
if (ok != 0) EINA_LOCK_ABORT_DEBUG(ok, mutex_destroy, mutex);
}
static inline Eina_Lock_Result
eina_lock_take_try(Eina_Lock *mutex)
_eina_lock_take_try(Eina_Lock *mutex)
{
Eina_Lock_Result ret = EINA_LOCK_FAIL;
int ok;
@ -240,7 +239,7 @@ eina_lock_take_try(Eina_Lock *mutex)
}
static inline Eina_Lock_Result
eina_lock_take(Eina_Lock *mutex)
_eina_lock_take(Eina_Lock *mutex)
{
Eina_Lock_Result ret = EINA_LOCK_FAIL;
int ok;
@ -313,7 +312,7 @@ eina_lock_take(Eina_Lock *mutex)
}
static inline Eina_Lock_Result
eina_lock_release(Eina_Lock *mutex)
_eina_lock_release(Eina_Lock *mutex)
{
Eina_Lock_Result ret = EINA_LOCK_FAIL;
int ok;
@ -347,19 +346,59 @@ eina_lock_release(Eina_Lock *mutex)
}
static inline Eina_Bool
eina_condition_new(Eina_Condition *cond, Eina_Lock *mutex)
_eina_condition_new(Eina_Condition *cond, Eina_Lock *mutex)
{
return _eina_condition_new(cond, mutex);
pthread_condattr_t attr;
int ok;
#ifdef EINA_HAVE_DEBUG_THREADS
assert(mutex != NULL);
#endif
cond->lock = mutex;
pthread_condattr_init(&attr);
/* OSX doesn't provide clockid_t or clock_gettime. */
#if defined(__clockid_t_defined)
cond->clkid = (clockid_t) 0;
/* We try here to chose the best clock for cond_timedwait */
# if defined(CLOCK_MONOTONIC_RAW)
if (!pthread_condattr_setclock(&attr, CLOCK_MONOTONIC_RAW))
cond->clkid = CLOCK_MONOTONIC_RAW;
# endif
# if defined(CLOCK_MONOTONIC)
if (!cond->clkid && !pthread_condattr_setclock(&attr, CLOCK_MONOTONIC))
cond->clkid = CLOCK_MONOTONIC;
# endif
# if defined(CLOCK_REALTIME)
if (!cond->clkid && !pthread_condattr_setclock(&attr, CLOCK_REALTIME))
cond->clkid = CLOCK_REALTIME;
# endif
#endif
ok = pthread_cond_init(&cond->condition, &attr);
if (ok != 0)
{
pthread_condattr_destroy(&attr);
#ifdef EINA_HAVE_DEBUG_THREADS
if (ok == EBUSY)
fprintf(stderr, "EINA ERROR: eina_condition_new on already initialized Eina_Condition\n");
#endif
return EINA_FALSE;
}
pthread_condattr_destroy(&attr);
return EINA_TRUE;
}
static inline void
eina_condition_free(Eina_Condition *cond)
_eina_condition_free(Eina_Condition *cond)
{
_eina_condition_free(cond);
pthread_cond_destroy(&(cond->condition));
}
static inline Eina_Bool
eina_condition_wait(Eina_Condition *cond)
_eina_condition_wait(Eina_Condition *cond)
{
Eina_Bool r = EINA_FALSE;
int ok;
@ -390,7 +429,7 @@ eina_condition_wait(Eina_Condition *cond)
}
static inline Eina_Bool
eina_condition_timedwait(Eina_Condition *cond, double t)
_eina_condition_timedwait(Eina_Condition *cond, double t)
{
struct timespec ts;
time_t sec;
@ -456,7 +495,7 @@ eina_condition_timedwait(Eina_Condition *cond, double t)
}
static inline Eina_Bool
eina_condition_broadcast(Eina_Condition *cond)
_eina_condition_broadcast(Eina_Condition *cond)
{
int ok;
@ -472,7 +511,7 @@ eina_condition_broadcast(Eina_Condition *cond)
}
static inline Eina_Bool
eina_condition_signal(Eina_Condition *cond)
_eina_condition_signal(Eina_Condition *cond)
{
int ok;
@ -488,19 +527,25 @@ eina_condition_signal(Eina_Condition *cond)
}
static inline Eina_Bool
eina_rwlock_new(Eina_RWLock *mutex)
_eina_rwlock_new(Eina_RWLock *mutex)
{
return _eina_rwlock_new(mutex);
int ok;
ok = pthread_rwlock_init(&(mutex->mutex), NULL);
if (ok == 0) return EINA_TRUE;
else if ((ok == EAGAIN) || (ok == ENOMEM)) return EINA_FALSE;
else EINA_LOCK_ABORT_DEBUG(ok, rwlock_init, mutex);
return EINA_FALSE;
}
static inline void
eina_rwlock_free(Eina_RWLock *mutex)
_eina_rwlock_free(Eina_RWLock *mutex)
{
_eina_rwlock_free(mutex);
pthread_rwlock_destroy(&(mutex->mutex));
}
static inline Eina_Lock_Result
eina_rwlock_take_read(Eina_RWLock *mutex)
_eina_rwlock_take_read(Eina_RWLock *mutex)
{
int ok;
@ -520,7 +565,7 @@ eina_rwlock_take_read(Eina_RWLock *mutex)
}
static inline Eina_Lock_Result
eina_rwlock_take_write(Eina_RWLock *mutex)
_eina_rwlock_take_write(Eina_RWLock *mutex)
{
int ok;
@ -540,7 +585,7 @@ eina_rwlock_take_write(Eina_RWLock *mutex)
}
static inline Eina_Lock_Result
eina_rwlock_release(Eina_RWLock *mutex)
_eina_rwlock_release(Eina_RWLock *mutex)
{
int ok;
@ -559,92 +604,167 @@ eina_rwlock_release(Eina_RWLock *mutex)
}
static inline Eina_Bool
eina_tls_cb_new(Eina_TLS *key, Eina_TLS_Delete_Cb delete_cb)
_eina_tls_cb_new(Eina_TLS *key, Eina_TLS_Delete_Cb delete_cb)
{
if (pthread_key_create(key, delete_cb) == 0) return EINA_TRUE;
return EINA_FALSE;
}
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_tls_free(Eina_TLS key)
{
pthread_key_delete(key);
}
static inline void *
eina_tls_get(Eina_TLS key)
_eina_tls_get(Eina_TLS key)
{
return pthread_getspecific(key);
}
static inline Eina_Bool
eina_tls_set(Eina_TLS key, const void *data)
_eina_tls_set(Eina_TLS key, const void *data)
{
if (pthread_setspecific(key, data) == 0) return EINA_TRUE;
return EINA_FALSE;
}
#ifdef EINA_HAVE_PTHREAD_BARRIER
typedef struct _Eina_Barrier Eina_Barrier;
#ifdef EINA_HAVE_PTHREAD_BARRIER
struct _Eina_Barrier
{
pthread_barrier_t barrier;
};
#else
struct _Eina_Barrier
{
int needed; /**< The number of waiting threads that will cause the barrier to signal and reset. */
int called; /**< The number of threads that are waiting on this barrier. */
Eina_Lock cond_lock; /**< The lock for the barrier */
Eina_Condition cond; /**< The condition variable for the barrier */
};
#endif
static inline Eina_Bool
eina_barrier_wait(Eina_Barrier *barrier)
_eina_barrier_new(Eina_Barrier *barrier, int needed)
{
#ifdef EINA_HAVE_PTHREAD_BARRIER
int ok = pthread_barrier_init(&(barrier->barrier), NULL, needed);
if (ok == 0) return EINA_TRUE;
else if ((ok == EAGAIN) || (ok == ENOMEM)) return EINA_FALSE;
else EINA_LOCK_ABORT_DEBUG(ok, barrier_init, barrier);
return EINA_FALSE;
#else
barrier->needed = needed;
barrier->called = 0;
if (eina_lock_new(&(barrier->cond_lock)))
{
if (eina_condition_new(&(barrier->cond), &(barrier->cond_lock)))
return EINA_TRUE;
}
return EINA_FALSE;
#endif
}
static inline void
_eina_barrier_free(Eina_Barrier *barrier)
{
#ifdef EINA_HAVE_PTHREAD_BARRIER
int ok = pthread_barrier_destroy(&(barrier->barrier));
if (ok != 0) EINA_LOCK_ABORT_DEBUG(ok, barrier_destroy, barrier);
#else
eina_condition_free(&(barrier->cond));
eina_lock_free(&(barrier->cond_lock));
barrier->needed = 0;
barrier->called = 0;
#endif
}
static inline Eina_Bool
_eina_barrier_wait(Eina_Barrier *barrier)
{
#ifdef EINA_HAVE_PTHREAD_BARRIER
int ok = pthread_barrier_wait(&(barrier->barrier));
if (ok == 0) return EINA_TRUE;
else if (ok == PTHREAD_BARRIER_SERIAL_THREAD) return EINA_TRUE;
else EINA_LOCK_ABORT_DEBUG(ok, barrier_wait, barrier);
return EINA_TRUE;
}
#else
#include "eina_inline_lock_barrier.x"
eina_lock_take(&(barrier->cond_lock));
barrier->called++;
if (barrier->called == barrier->needed)
{
barrier->called = 0;
eina_condition_broadcast(&(barrier->cond));
}
else
eina_condition_wait(&(barrier->cond));
eina_lock_release(&(barrier->cond_lock));
return EINA_TRUE;
#endif
EAPI Eina_Bool _eina_barrier_new(Eina_Barrier *barrier, int needed);
EAPI void _eina_barrier_free(Eina_Barrier *barrier);
}
static inline Eina_Bool
eina_barrier_new(Eina_Barrier *barrier, int needed)
_eina_spinlock_new(Eina_Spinlock *spinlock)
{
return _eina_barrier_new(barrier, needed);
#if defined(EINA_HAVE_PTHREAD_SPINLOCK)
int ok = pthread_spin_init(spinlock, PTHREAD_PROCESS_PRIVATE);
if (ok == 0) return EINA_TRUE;
else if ((ok == EAGAIN) || (ok == ENOMEM)) return EINA_FALSE;
else EINA_LOCK_ABORT_DEBUG(ok, spin_init, spinlock);
return EINA_FALSE;
#elif defined(EINA_HAVE_OSX_SPINLOCK)
*spinlock = 0;
return EINA_TRUE;
#else
return eina_lock_new(spinlock);
#endif
}
static inline void
eina_barrier_free(Eina_Barrier *barrier)
_eina_spinlock_free(Eina_Spinlock *spinlock)
{
_eina_barrier_free(barrier);
#if defined(EINA_HAVE_PTHREAD_SPINLOCK)
int ok = pthread_spin_destroy(spinlock);
if (ok != 0) EINA_LOCK_ABORT_DEBUG(ok, spin_destroy, spinlock);
#elif defined(EINA_HAVE_OSX_SPINLOCK)
/* Not applicable */
(void) spinlock;
#else
eina_lock_free(spinlock);
#endif
}
static inline Eina_Bool
eina_spinlock_new(Eina_Spinlock *spinlock)
#ifdef EINA_HAVE_OSX_SPINLOCK
static inline Eina_Lock_Result
_eina_spinlock_macos_take(Eina_Spinlock *spinlock)
{
return _eina_spinlock_new(spinlock);
}
static inline void
eina_spinlock_free(Eina_Spinlock *spinlock)
{
_eina_spinlock_free(spinlock);
os_unfair_lock_lock(SPINLOCK_GET(spinlock));
return EINA_LOCK_SUCCEED;
}
static inline Eina_Lock_Result
eina_spinlock_take_try(Eina_Spinlock *spinlock)
_eina_spinlock_macos_take_try(Eina_Spinlock *spinlock)
{
#if defined(EINA_HAVE_POSIX_SPINLOCK)
return (os_unfair_lock_trylock(SPINLOCK_GET(spinlock)) == true)
? EINA_LOCK_SUCCEED
: EINA_LOCK_FAIL;
}
static inline Eina_Lock_Result
_eina_spinlock_macos_release(Eina_Spinlock *spinlock)
{
os_unfair_lock_unlock(SPINLOCK_GET(spinlock));
return EINA_LOCK_SUCCEED;
}
#endif /* EINA_HAVE_OSX_SPINLOCK */
static inline Eina_Lock_Result
_eina_spinlock_take_try(Eina_Spinlock *spinlock)
{
#if defined(EINA_HAVE_PTHREAD_SPINLOCK)
int t = pthread_spin_trylock(spinlock);
if (t == 0) return EINA_LOCK_SUCCEED;
else if (t == EBUSY) return EINA_LOCK_FAIL;
@ -658,9 +778,9 @@ eina_spinlock_take_try(Eina_Spinlock *spinlock)
}
static inline Eina_Lock_Result
eina_spinlock_take(Eina_Spinlock *spinlock)
_eina_spinlock_take(Eina_Spinlock *spinlock)
{
#if defined(EINA_HAVE_POSIX_SPINLOCK)
#if defined(EINA_HAVE_PTHREAD_SPINLOCK)
int t;
#ifdef EINA_HAVE_DEBUG_THREADS
@ -683,9 +803,9 @@ eina_spinlock_take(Eina_Spinlock *spinlock)
}
static inline Eina_Lock_Result
eina_spinlock_release(Eina_Spinlock *spinlock)
_eina_spinlock_release(Eina_Spinlock *spinlock)
{
#if defined(EINA_HAVE_POSIX_SPINLOCK)
#if defined(EINA_HAVE_PTHREAD_SPINLOCK)
int ok = pthread_spin_unlock(spinlock);
if (ok == 0) return EINA_LOCK_SUCCEED;
else if (ok == EPERM) return EINA_LOCK_FAIL;
@ -699,19 +819,37 @@ eina_spinlock_release(Eina_Spinlock *spinlock)
}
static inline Eina_Bool
eina_semaphore_new(Eina_Semaphore *sem, int count_init)
_eina_semaphore_new(Eina_Semaphore *sem, int count_init)
{
return _eina_semaphore_new(sem, count_init);
if (sem && (count_init >= 0))
{
#if defined(EINA_HAVE_OSX_SEMAPHORE)
kern_return_t kr = semaphore_create(mach_task_self(), sem, SYNC_POLICY_FIFO, count_init);
return (kr == KERN_SUCCESS) ? EINA_TRUE : EINA_FALSE;
#else
return (sem_init(sem, 0, count_init) == 0) ? EINA_TRUE : EINA_FALSE;
#endif
}
return EINA_FALSE;
}
static inline Eina_Bool
eina_semaphore_free(Eina_Semaphore *sem)
_eina_semaphore_free(Eina_Semaphore *sem)
{
return _eina_semaphore_free(sem);
if (sem)
{
#if defined(EINA_HAVE_OSX_SEMAPHORE)
return (semaphore_destroy(mach_task_self(), *sem) == KERN_SUCCESS)
? EINA_TRUE : EINA_FALSE;
#else
return (sem_destroy(sem) == 0) ? EINA_TRUE : EINA_FALSE;
#endif
}
return EINA_FALSE;
}
static inline Eina_Bool
eina_semaphore_lock(Eina_Semaphore *sem)
_eina_semaphore_lock(Eina_Semaphore *sem)
{
if (sem)
{
@ -735,7 +873,7 @@ err:
}
static inline Eina_Bool
eina_semaphore_release(Eina_Semaphore *sem, int count_release EINA_UNUSED)
_eina_semaphore_release(Eina_Semaphore *sem, int count_release EINA_UNUSED)
{
if (sem)
#if defined(EINA_HAVE_OSX_SEMAPHORE)

View File

@ -0,0 +1,747 @@
/* EINA - EFL data type library
* Copyright (C) 2020 Lucas Cavalcante de Sousa
*
* 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>
#include <synchapi.h>
#undef WIN32_LEAN_AND_MEAN
#include "unimplemented.h"
#include <errno.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#ifdef EINA_HAVE_DEBUG_THREADS
#include <assert.h>
#include <execinfo.h>
#define EINA_LOCK_DEBUG_BT_NUM 64
typedef void (*Eina_Lock_Bt_Func) ();
#include "eina_inlist.h"
#endif
EAPI void _eina_lock_debug_abort(int err, const char *fn, const volatile void *ptr);
EAPI void _eina_lock_debug_deadlock(const char *fn, const volatile void *ptr);
#define EINA_LOCK_ABORT_DEBUG(err, fn, ptr) \
_eina_lock_debug_abort(err, #fn, ptr)
#define EINA_LOCK_DEADLOCK_DEBUG(fn, ptr) \
_eina_lock_debug_deadlock(#fn, ptr)
/* For cond_timedwait */
#include <time.h>
#include <sys/time.h>
#include <eina_error.h>
typedef struct _Eina_Lock Eina_Lock;
typedef struct _Eina_RWLock Eina_RWLock;
typedef struct _Eina_Condition Eina_Condition;
typedef struct _Eina_Barrier Eina_Barrier;
typedef LPDWORD Eina_TLS;
typedef HANDLE Eina_Semaphore;
#ifdef EINA_HAVE_WIN32_SPINLOCK
typedef PCRITICAL_SECTION Eina_Spinlock;
#else
typedef Eina_Lock Eina_Spinlock;
#endif
EAPI void eina_lock_debug(const Eina_Lock *mutex);
/** @privatesection @{ */
typedef HANDLE _Eina_Thread;
typedef PCRITICAL_SECTION _Eina_Mutex_t;
typedef CONDITION_VARIABLE _Eina_Condition_t;
typedef PSRWLOCK _Eina_RWLock_t;
struct _Eina_Lock
{
_Eina_Mutex_t mutex; /**< The mutex that handles the locking */
#ifdef EINA_HAVE_DEBUG_THREADS
EINA_INLIST; /**< Keeps track of the threads waiting for the lock */
_Eina_Thread lock_thread_id; /**< The ID of the thread that currently has the lock */
Eina_Lock_Bt_Func lock_bt[EINA_LOCK_DEBUG_BT_NUM]; /**< The function that will produce a backtrace on the thread that has the lock */
int lock_bt_num; /**< Number of addresses in the backtrace */
Eina_Bool locked : 1; /**< Indicates locked or not locked */
Eina_Bool recursive : 1; /**< Indicates recursive lock */
#endif /* EINA_HAVE_DEBUG_THREADS */
};
struct _Eina_Condition
{
Eina_Lock *lock; /**< The lock for this condition */
_Eina_Condition_t condition; /**< The condition variable */
#if defined(__clockid_t_defined)
clockid_t clkid; /**< The attached clock for timedwait */
#endif
};
enum _Eina_RWLock_Mode {
_Eina_RWLock_Mode_Shared,
_Eina_RWLock_Mode_Exclusive,
_Eina_RWLock_Mode_None
};
struct _Eina_RWLock
{
_Eina_RWLock_t mutex; /**< The mutex that handles the locking */
#ifdef EINA_HAVE_DEBUG_THREADS
_Eina_Thread lock_thread_wid; /**< The ID of the thread that currently has the lock */
#endif
enum _Eina_RWLock_Mode mode; /**< The mode the SRWLock is (Shared, Exclusive or None)*/
};
/** @} privatesection */
EAPI extern Eina_Bool _eina_threads_activated;
#ifdef EINA_HAVE_DEBUG_THREADS
EAPI extern int _eina_threads_debug;
EAPI extern _Eina_Thread _eina_main_loop;
EAPI extern Eina_Lock _eina_tracking_lock;
EAPI extern Eina_Inlist *_eina_tracking;
#endif
EAPI Eina_Bool eina_lock_new(Eina_Lock *mutex);
EAPI void eina_lock_free(Eina_Lock *mutex);
EAPI Eina_Lock_Result eina_lock_take(Eina_Lock *mutex);
EAPI Eina_Lock_Result eina_lock_take_try(Eina_Lock *mutex);
EAPI Eina_Lock_Result eina_lock_release(Eina_Lock *mutex);
EAPI Eina_Bool eina_condition_new(Eina_Condition *cond, Eina_Lock *mutex);
EAPI void eina_condition_free(Eina_Condition *cond);
EAPI Eina_Bool eina_condition_wait(Eina_Condition *cond);
EAPI Eina_Bool eina_condition_broadcast(Eina_Condition *cond);
static inline Eina_Bool
_eina_lock_new(Eina_Lock *mutex, Eina_Bool recursive)
{
InitializeCriticalSection((mutex->mutex));
DWORD ok = GetLastError();
if (ok == ERROR_SUCCESS) return EINA_TRUE;
return EINA_FALSE;
}
static inline void
_eina_lock_free(Eina_Lock *mutex)
{
#ifdef EINA_HAVE_DEBUG_THREADS
if (mutex->locked)
{
EnterCriticalSection(_eina_tracking_lock);
_eina_tracking = eina_inlist_remove(_eina_tracking,
EINA_INLIST_GET(mutex));
LeaveCriticalSection(_eina_tracking_lock);
}
#endif
DWORD ok;
DeleteCriticalSection((mutex->mutex));
ok = GetLastError();
if (ok != ERROR_SUCCESS) EINA_LOCK_ABORT_DEBUG((int)ok, mutex_destroy
, mutex);
}
static inline Eina_Lock_Result
_eina_lock_take_try(Eina_Lock *mutex)
{
Eina_Lock_Result ret = EINA_LOCK_FAIL;
#ifdef EINA_HAVE_ON_OFF_THREADS
if (!_eina_threads_activated) return EINA_LOCK_SUCCEED;
#endif
int ok = TryEnterCriticalSection((mutex->mutex));
DWORD err = GetLastError();
if (ok != 0) ret = EINA_LOCK_SUCCEED;
else if (err == ERROR_POSSIBLE_DEADLOCK)
{
eina_lock_debug(mutex);
ret = EINA_LOCK_DEADLOCK;
}
else if (err != ERROR_TIMEOUT) EINA_LOCK_ABORT_DEBUG((int)err, trylock, mutex);
#ifdef EINA_HAVE_DEBUG_THREADS
if (ret == EINA_LOCK_SUCCEED)
{
/* recursive locks can't make use of any of this */
if (mutex->recursive) return ret;
mutex->locked = 1;
mutex->lock_thread_id = GetCurrentThreadId();
/* backtrace() can somehow generate EINVAL even though this is not documented anywhere? */
int err = errno;
mutex->lock_bt_num = backtrace((void **)(mutex->lock_bt), EINA_LOCK_DEBUG_BT_NUM);
errno = err;
EnterCriticalSection(_eina_tracking_lock);
_eina_tracking = eina_inlist_append(_eina_tracking,
EINA_INLIST_GET(mutex));
LeaveCriticalSection(_eina_tracking_lock);
}
#endif
return ret;
}
static inline Eina_Lock_Result
_eina_lock_take(Eina_Lock *mutex)
{
Eina_Lock_Result ret = EINA_LOCK_FAIL;
DWORD ok;
#ifdef EINA_HAVE_ON_OFF_THREADS
if (!_eina_threads_activated) return EINA_LOCK_SUCCEED;
#endif
#ifdef EINA_HAVE_DEBUG_THREADS
if (eina_lock_take_try(mutex) == EINA_LOCK_SUCCEED) return EINA_LOCK_SUCCEED;
if (_eina_threads_debug >= 100)
{
struct timeval t0, t1;
int dt;
gettimeofday(&t0, NULL);
ok = EnterCriticalSection((mutex->mutex));
gettimeofday(&t1, NULL);
dt = (t1.tv_sec - t0.tv_sec) * 1000000;
if (t1.tv_usec > t0.tv_usec) dt += (t1.tv_usec - t0.tv_usec);
else dt -= t0.tv_usec - t1.tv_usec;
if (dt > _eina_threads_debug) abort();
}
else
{
#endif
EnterCriticalSection((mutex->mutex));
ok = GetLastError();
#ifdef EINA_HAVE_DEBUG_THREADS
}
#endif
if (ok == ERROR_SUCCESS) ret = EINA_LOCK_SUCCEED;
else if (ok == ERROR_POSSIBLE_DEADLOCK)
{
eina_lock_debug(mutex);
ret = EINA_LOCK_DEADLOCK;
#ifdef EINA_HAVE_DEBUG_THREADS
if (_eina_threads_debug) abort();
#endif
}
else if (ok != ERROR_TIMEOUT) EINA_LOCK_ABORT_DEBUG((int)ok, lock, mutex);
#ifdef EINA_HAVE_DEBUG_THREADS
/* recursive locks can't make use of any of this */
if (mutex->recursive) return ret;
mutex->locked = 1;
mutex->lock_thread_id = GetCurrentThreadId();
/* backtrace() can somehow generate EINVAL even though this is not documented anywhere? */
int err = errno;
mutex->lock_bt_num = backtrace((void **)(mutex->lock_bt), EINA_LOCK_DEBUG_BT_NUM);
errno = err;
EnterCriticalSection(_eina_tracking_lock);
_eina_tracking = eina_inlist_append(_eina_tracking,
EINA_INLIST_GET(mutex));
LeaveCriticalSection(_eina_tracking_lock);
#endif
return ret;
}
static inline Eina_Lock_Result
_eina_lock_release(Eina_Lock *mutex)
{
Eina_Lock_Result ret = EINA_LOCK_FAIL;
#ifdef EINA_HAVE_ON_OFF_THREADS
if (!_eina_threads_activated) return EINA_LOCK_SUCCEED;
#endif
#ifdef EINA_HAVE_DEBUG_THREADS
/* recursive locks can't make use of any of this */
if (!mutex->recursive)
{
mutex->locked = 0;
mutex->lock_thread_id = 0;
memset(mutex->lock_bt, 0, EINA_LOCK_DEBUG_BT_NUM * sizeof(Eina_Lock_Bt_Func));
mutex->lock_bt_num = 0;
EnterCriticalSection(_eina_tracking_lock);
_eina_tracking = eina_inlist_remove(_eina_tracking,
EINA_INLIST_GET(mutex));
LeaveCriticalSection(_eina_tracking_lock);
}
#endif
LeaveCriticalSection((mutex->mutex));
DWORD ok = GetLastError();
if (ok == ERROR_SUCCESS) ret = EINA_LOCK_SUCCEED;
else if (ok != ERROR_ACCESS_DENIED) ret = EINA_LOCK_FAIL;
else EINA_LOCK_ABORT_DEBUG((int)ok, unlock, mutex);
return ret;
}
UNIMPLEMENTED static inline Eina_Bool
_eina_condition_new(Eina_Condition *cond, Eina_Lock *mutex)
{
// TODO
#warning eina_condition_new is not implemented
return EINA_TRUE;
}
static inline void
_eina_condition_free(Eina_Condition *cond)
{
return;
}
static inline Eina_Bool
_eina_condition_wait(Eina_Condition *cond)
{
Eina_Bool r = EINA_FALSE;
#ifdef EINA_HAVE_DEBUG_THREADS
assert(_eina_threads_activated);
assert(cond->lock != NULL);
EnterCriticalSection(_eina_tracking_lock);
_eina_tracking = eina_inlist_remove(_eina_tracking,
EINA_INLIST_GET(cond->lock));
LeaveCriticalSection(_eina_tracking_lock);
#endif
int ok = SleepConditionVariableCS(&(cond->condition)
, (cond->lock->mutex), INFINITE);
DWORD err = GetLastError();
if (ok != 0) r = EINA_TRUE;
else if (err != ERROR_ACCESS_DENIED) r = EINA_FALSE;
else EINA_LOCK_ABORT_DEBUG((int)ok, cond_wait, cond);
#ifdef EINA_HAVE_DEBUG_THREADS
EnterCriticalSection(_eina_tracking_lock);
_eina_tracking = eina_inlist_append(_eina_tracking
, EINA_INLIST_GET(cond->lock));
LeaveCriticalSection(_eina_tracking_lock);
#endif
return r;
}
UNIMPLEMENTED static inline Eina_Bool
_eina_condition_timedwait(Eina_Condition *cond, double t)
{
//** TODO **//
#warning eina_condition_timedwait is not implemented
return EINA_TRUE;
}
static inline Eina_Bool
_eina_condition_broadcast(Eina_Condition *cond)
{
#ifdef EINA_HAVE_DEBUG_THREADS
assert(cond->lock != NULL);
#endif
WakeAllConditionVariable(&(cond->condition));
DWORD ok = GetLastError();
if (ok == ERROR_SUCCESS) return EINA_TRUE;
EINA_LOCK_ABORT_DEBUG((int)ok, cond_broadcast, cond);
return EINA_FALSE;
}
static inline Eina_Bool
_eina_condition_signal(Eina_Condition *cond)
{
#ifdef EINA_HAVE_DEBUG_THREADS
assert(cond->lock != NULL);
#endif
WakeConditionVariable(&(cond->condition));
DWORD ok = GetLastError();
if (ok == ERROR_SUCCESS) return EINA_TRUE;
EINA_LOCK_ABORT_DEBUG((int)ok, cond_signal, cond);
return EINA_FALSE;
}
static inline Eina_Bool
_eina_rwlock_new(Eina_RWLock *mutex)
{
InitializeSRWLock((mutex->mutex));
DWORD ok = GetLastError();
if (ok == ERROR_SUCCESS) return EINA_TRUE;
else if ((ok == ERROR_NOT_ENOUGH_MEMORY) || (ok == ERROR_ACCESS_DENIED)
|| (ok == ERROR_OUTOFMEMORY))
{
return EINA_FALSE;
}
else EINA_LOCK_ABORT_DEBUG(ok, rwlock_init, mutex);
return EINA_FALSE;
}
static inline void
_eina_rwlock_free(Eina_RWLock *mutex)
{
return;
}
static inline Eina_Lock_Result
_eina_rwlock_take_read(Eina_RWLock *mutex)
{
#ifdef EINA_HAVE_ON_OFF_THREADS
if (!_eina_threads_activated) return EINA_LOCK_SUCCEED;
#endif
AcquireSRWLockShared((mutex->mutex));
DWORD ok = GetLastError();
if (ok == ERROR_SUCCESS)
{
mutex->mode = _Eina_RWLock_Mode_Shared;
return EINA_LOCK_SUCCEED;
}
else if (ok == ERROR_NOT_ENOUGH_MEMORY || ok == ERROR_OUTOFMEMORY)
{
return EINA_LOCK_FAIL;
}
else if (ok == ERROR_POSSIBLE_DEADLOCK)
{
EINA_LOCK_DEADLOCK_DEBUG(rwlock_rdlock, mutex);
}
else EINA_LOCK_ABORT_DEBUG((int)ok, rwlock_rdlock, mutex);
return EINA_LOCK_FAIL;
}
static inline Eina_Lock_Result
_eina_rwlock_take_write(Eina_RWLock *mutex)
{
#ifdef EINA_HAVE_ON_OFF_THREADS
if (!_eina_threads_activated) return EINA_LOCK_SUCCEED;
#endif
AcquireSRWLockExclusive((mutex->mutex));
DWORD ok = GetLastError();
if (ok == ERROR_SUCCESS)
{
mutex->mode = _Eina_RWLock_Mode_Exclusive;
return EINA_LOCK_SUCCEED;
}
else if (ok == ERROR_NOT_ENOUGH_MEMORY || ok == ERROR_OUTOFMEMORY)
{
return EINA_LOCK_FAIL;
}
else if (ok == ERROR_POSSIBLE_DEADLOCK)
{
EINA_LOCK_DEADLOCK_DEBUG(rwlock_rdlock, mutex);
}
else EINA_LOCK_ABORT_DEBUG((int)ok, rwlock_rdlock, mutex);
return EINA_LOCK_FAIL;
}
static inline Eina_Lock_Result
_eina_rwlock_release(Eina_RWLock *mutex)
{
DWORD ok;
#ifdef EINA_HAVE_ON_OFF_THREADS
if (!_eina_threads_activated) return EINA_LOCK_SUCCEED;
#endif
if (mutex->mode == _Eina_RWLock_Mode_Exclusive)
{
mutex->mode = _Eina_RWLock_Mode_None;
ReleaseSRWLockExclusive((mutex->mutex));
ok = GetLastError();
if (ok == ERROR_SUCCESS) return EINA_LOCK_SUCCEED;
mutex->mode = _Eina_RWLock_Mode_Exclusive;
}
else if (mutex->mode == _Eina_RWLock_Mode_Shared)
{
mutex->mode = _Eina_RWLock_Mode_None;
ReleaseSRWLockShared((mutex->mutex));
ok = GetLastError();
if (ok == ERROR_SUCCESS) return EINA_LOCK_SUCCEED;
mutex->mode = _Eina_RWLock_Mode_Shared;
}
if (ok == ERROR_ACCESS_DENIED) return EINA_LOCK_FAIL;
EINA_LOCK_ABORT_DEBUG((int)ok, rwlock_unlock, mutex);
return EINA_LOCK_FAIL;
}
static inline Eina_Bool
_eina_tls_cb_new(Eina_TLS *key, Eina_TLS_Delete_Cb delete_cb)
{
* key = TlsAlloc();
DWORD ok = GetLastError();
if (key != TLS_OUT_OF_INDEXES || ok != ERROR_SUCCESS) return EINA_TRUE;
else return EINA_FALSE;
}
static inline void
_eina_tls_free(Eina_TLS key)
{
TlsFree(key);
}
static inline void *
_eina_tls_get(Eina_TLS key)
{
return TlsGetValue(key);
}
static inline Eina_Bool
_eina_tls_set(Eina_TLS key, const void *data)
{
int ok = TlsSetValue(key, (void *) data);
DWORD err = GetLastError();
if (ok != 0 && err == ERROR_SUCCESS) return EINA_TRUE;
else return EINA_TRUE;
}
#ifdef EINA_HAVE_WIN32_BARRIER
struct _Eina_Barrier
{
LPSYNCHRONIZATION_BARRIER barrier;
};
#else
struct _Eina_Barrier
{
int needed; /**< The number of waiting threads that will cause the barrier to signal and reset. */
int called; /**< The number of threads that are waiting on this barrier. */
Eina_Lock cond_lock; /**< The lock for the barrier */
Eina_Condition cond; /**< The condition variable for the barrier */
};
#endif
static inline Eina_Bool
_eina_barrier_new(Eina_Barrier *barrier, int needed)
{
#ifdef EINA_HAVE_WIN32_BARRIER
InitializeSynchronizationBarrier(&(barrier->barrier), (LONG) needed, 0);
DWORD ok = GetLastError();
if (ok == ERROR_SUCCESS) return EINA_TRUE;
else if ((ok == ERROR_NOT_ENOUGH_MEMORY) || (ok == ERROR_ACCESS_DENIED)
|| (ok == ERROR_OUTOFMEMORY))
{
return EINA_FALSE;
}
else EINA_LOCK_ABORT_DEBUG(ok, barrier_init, barrier);
return EINA_FALSE;
#else
barrier->needed = needed;
barrier->called = 0;
if (eina_lock_new(&(barrier->cond_lock)))
{
if (eina_condition_new(&(barrier->cond), &(barrier->cond_lock)))
return EINA_TRUE;
}
return EINA_FALSE;
#endif
}
static inline void
_eina_barrier_free(Eina_Barrier *barrier)
{
#ifdef EINA_HAVE_WIN32_BARRIER
DeleteSynchronizationBarrier(&(barrier->barrier));
DWORD ok = GetLastError();
if (ok != ERROR_SUCCESS) EINA_LOCK_ABORT_DEBUG(ok, barrier_destroy, barrier);
#else
eina_condition_free(&(barrier->cond));
eina_lock_free(&(barrier->cond_lock));
barrier->needed = 0;
barrier->called = 0;
#endif
}
static inline Eina_Bool
_eina_barrier_wait(Eina_Barrier *barrier)
{
#ifdef EINA_HAVE_WIN32_BARRIER
EnterSyncronizationBarrier(&(barrier->barrier)
, SYNCHRONIZATION_BARRIER_FLAGS_BLOCK_ONLY);
DWORD ok = GetLastError();
if (ok == ERROR_SUCCESS) return EINA_TRUE;
else EINA_LOCK_ABORT_DEBUG((int)ok, barrier_wait, barrier);
return EINA_TRUE;
#else
eina_lock_take(&(barrier->cond_lock));
barrier->called++;
if (barrier->called == barrier->needed)
{
barrier->called = 0;
eina_condition_broadcast(&(barrier->cond));
}
else eina_condition_wait(&(barrier->cond));
eina_lock_release(&(barrier->cond_lock));
return EINA_TRUE;
#endif
}
static inline Eina_Bool
_eina_spinlock_new(Eina_Spinlock *spinlock)
{
#ifdef EINA_HAVE_WIN32_SPINLOCK
int ok = InitializeCriticalSectionAndSpinCount(spinlock, INFINITE);
DWORD err = GetLastError();
if (ok != 0) return EINA_TRUE;
else if ((err == ERROR_NOT_ENOUGH_MEMORY) || (err == ERROR_ACCESS_DENIED)
|| (err == ERROR_OUTOFMEMORY))
{
return EINA_FALSE;
}
else EINA_LOCK_ABORT_DEBUG((int)err, spin_init, spinlock);
return EINA_FALSE;
#else
return eina_lock_new(spinlock);
#endif
}
static inline void
_eina_spinlock_free(Eina_Spinlock *spinlock)
{
#ifdef EINA_HAVE_WIN32_SPINLOCK
DeleteCriticalSection(spinlock);
DWORD ok = GetLastError();
if (ok != ERROR_SUCCESS) EINA_LOCK_ABORT_DEBUG(ok, spin_destroy, spinlock);
#else
eina_lock_free(spinlock);
#endif
}
static inline Eina_Lock_Result
_eina_spinlock_take_try(Eina_Spinlock *spinlock)
{
#ifdef EINA_HAVE_WIN32_SPINLOCK
int ok = TryEnterCriticalSection(spinlock);
DWORD err = GetLastError();
if (err == ERROR_SUCCESS) return EINA_LOCK_SUCCEED;
else if (ok == 0 || err == ERROR_TIMEOUT) EINA_LOCK_FAIL;
else EINA_LOCK_ABORT_DEBUG((int)err, trylock, mutex);
return EINA_LOCK_FAIL
#else
return eina_lock_take_try(spinlock);
#endif
}
static inline Eina_Lock_Result
_eina_spinlock_take(Eina_Spinlock *spinlock)
{
#ifdef EINA_HAVE_WIN32_SPINLOCK
# ifdef EINA_HAVE_DEBUG_THREADS
if (eina_spinlock_take_try(spinlock) == EINA_LOCK_SUCCEED)
return EINA_LOCK_SUCCEED;
# endif
for (;;)
{
int ok = EnterCriticalSection(spinlock);
if (ok != 0) break;
else {
DWORD err = GetLastError();
EINA_LOCK_ABORT_DEBUG((int)err, spin_lock, spinlock);
}
}
return EINA_LOCK_SUCCEED;
#else
return eina_lock_take(spinlock);
#endif
}
static inline Eina_Lock_Result
_eina_spinlock_release(Eina_Spinlock *spinlock)
{
#if defined(EINA_HAVE_WIN32_SPINLOCK)
LeaveCriticalSection(spinlock);
DWORD ok = GetLastError();
if (ok == ERROR_SUCCESS) return EINA_LOCK_SUCCEED;
else if (ok == ERROR_ACCESS_DENIED) return EINA_LOCK_FAIL;
else EINA_LOCK_ABORT_DEBUG((int)ok, spin_unlock, spinlock);
return EINA_LOCK_FAIL;
#else
return eina_lock_release(spinlock);
#endif
}
static inline Eina_Bool
_eina_semaphore_new(Eina_Semaphore *sem, int count_init)
{
if (sem && (count_init >= 0))
{
sem = CreateSemaphoreA(NULL, count_init, count_init, NULL);
DWORD ok = GetLastError();
if (ok == ERROR_SUCCESS) return EINA_TRUE;
}
return EINA_FALSE;
}
static inline Eina_Bool
_eina_semaphore_free(Eina_Semaphore *sem)
{
if (sem)
{
CloseHandle(sem);
DWORD ok = GetLastError();
if (ok == ERROR_SUCCESS) return EINA_TRUE;
}
return EINA_FALSE;
}
static inline Eina_Bool
_eina_semaphore_lock(Eina_Semaphore *sem)
{
if (sem)
{
for (;;)
{
WaitForSingleObject(sem, INFINITE);
DWORD ok = GetLastError();
if (ok == ERROR_SUCCESS)
return EINA_TRUE;
else if (ok == WAIT_OBJECT_0 || ok == WAIT_TIMEOUT)
continue;
else if (errno == ERROR_POSSIBLE_DEADLOCK)
{
EINA_LOCK_DEADLOCK_DEBUG(sem_wait, sem);
return EINA_FALSE;
}
}
}
return EINA_FALSE;
}
static inline Eina_Bool
_eina_semaphore_release(Eina_Semaphore *sem, int count_release EINA_UNUSED)
{
if (sem)
return (ReleaseSemaphore(sem, 1, NULL) != 0) ? EINA_TRUE : EINA_FALSE;
return EINA_FALSE;
}
#endif

View File

@ -7,51 +7,6 @@
#include "eina_config.h"
#include "Eina.h"
#ifdef EINA_HAVE_OSX_SPINLOCK
/*
* macOS 10.12 introduced the os_unfair_lock API which
* deprecates OSSpinLock, while keeping compatible.
*
* The Spinlock API is not inlined because it would imply including
* stdbool.h, which is not wanted: it would introduce new macros,
* and break compilation of existing programs.
*/
# if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200
# include <os/lock.h>
# define SPINLOCK_GET(LCK) ((os_unfair_lock_t)(LCK))
# else
# include <libkern/OSAtomic.h>
# define SPINLOCK_GET(LCK) ((OSSpinLock *)(LCK))
# define os_unfair_lock_lock(LCK) OSSpinLockLock(LCK)
# define os_unfair_lock_unlock(LCK) OSSpinLockUnlock(LCK)
# define os_unfair_lock_trylock(LCK) OSSpinLockTry(LCK)
# endif
EAPI Eina_Lock_Result
_eina_spinlock_macos_take(Eina_Spinlock *spinlock)
{
os_unfair_lock_lock(SPINLOCK_GET(spinlock));
return EINA_LOCK_SUCCEED;
}
EAPI Eina_Lock_Result
_eina_spinlock_macos_take_try(Eina_Spinlock *spinlock)
{
return (os_unfair_lock_trylock(SPINLOCK_GET(spinlock)) == true)
? EINA_LOCK_SUCCEED
: EINA_LOCK_FAIL;
}
EAPI Eina_Lock_Result
_eina_spinlock_macos_release(Eina_Spinlock *spinlock)
{
os_unfair_lock_unlock(SPINLOCK_GET(spinlock));
return EINA_LOCK_SUCCEED;
}
#endif /* EINA_HAVE_OSX_SPINLOCK */
Eina_Bool fork_resetting;
EAPI void
@ -85,198 +40,220 @@ eina_lock_debug(const Eina_Lock *mutex)
#endif
}
EAPI Eina_Bool
_eina_lock_new(Eina_Lock *mutex, Eina_Bool recursive)
EAPI Eina_Bool eina_lock_new(Eina_Lock *mutex)
{
pthread_mutexattr_t attr;
Eina_Bool ok = EINA_FALSE;
if (pthread_mutexattr_init(&attr) != 0) return EINA_FALSE;
if (recursive)
{
if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0) goto fail_release;
}
Eina_Bool ret = _eina_lock_new(mutex, EINA_FALSE);
#ifdef EINA_HAVE_DEBUG_THREADS
else if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK) != 0) goto fail_release;
mutex->recursive = EINA_FALSE;
mutex->lock_thread_id = 0;
mutex->lock_bt_num = 0;
mutex->locked = 0;
#endif
if (pthread_mutex_init(&(mutex->mutex), &attr) != 0) goto fail_release;
ok = EINA_TRUE;
fail_release:
pthread_mutexattr_destroy(&attr);
return ok;
}
EAPI void
_eina_lock_free(Eina_Lock *mutex)
{
int ok;
ok = pthread_mutex_destroy(&(mutex->mutex));
if (ok != 0) EINA_LOCK_ABORT_DEBUG(ok, mutex_destroy, mutex);
return ret;
}
EAPI Eina_Bool
_eina_condition_new(Eina_Condition *cond, Eina_Lock *mutex)
eina_lock_recursive_new(Eina_Lock *mutex)
{
pthread_condattr_t attr;
int ok;
Eina_Bool ret = _eina_lock_new(mutex, EINA_TRUE);
#ifdef EINA_HAVE_DEBUG_THREADS
assert(mutex != NULL);
mutex->recursive = EINA_TRUE;
mutex->lock_thread_id = 0;
mutex->lock_bt_num = 0;
mutex->locked = 0;
#endif
cond->lock = mutex;
pthread_condattr_init(&attr);
/* OSX doesn't provide clockid_t or clock_gettime. */
#if defined(__clockid_t_defined)
cond->clkid = (clockid_t) 0;
/* We try here to chose the best clock for cond_timedwait */
# if defined(CLOCK_MONOTONIC_RAW)
if (!pthread_condattr_setclock(&attr, CLOCK_MONOTONIC_RAW))
cond->clkid = CLOCK_MONOTONIC_RAW;
# endif
# if defined(CLOCK_MONOTONIC)
if (!cond->clkid && !pthread_condattr_setclock(&attr, CLOCK_MONOTONIC))
cond->clkid = CLOCK_MONOTONIC;
# endif
# if defined(CLOCK_REALTIME)
if (!cond->clkid && !pthread_condattr_setclock(&attr, CLOCK_REALTIME))
cond->clkid = CLOCK_REALTIME;
# endif
#endif
ok = pthread_cond_init(&cond->condition, &attr);
if (ok != 0)
{
pthread_condattr_destroy(&attr);
#ifdef EINA_HAVE_DEBUG_THREADS
if (ok == EBUSY)
fprintf(stderr, "EINA ERROR: eina_condition_new on already initialized Eina_Condition\n");
#endif
return EINA_FALSE;
}
pthread_condattr_destroy(&attr);
return EINA_TRUE;
return ret;
}
EAPI void
_eina_condition_free(Eina_Condition *cond)
eina_lock_free(Eina_Lock *mutex)
{
pthread_cond_destroy(&(cond->condition));
_eina_lock_free(mutex);
}
EAPI Eina_Lock_Result
eina_lock_take_try(Eina_Lock *mutex)
{
return _eina_lock_take_try(mutex);
}
EAPI Eina_Lock_Result
eina_lock_take(Eina_Lock *mutex)
{
return _eina_lock_take(mutex);
}
EAPI Eina_Lock_Result
eina_lock_release(Eina_Lock *mutex)
{
return _eina_lock_release(mutex);
}
EAPI Eina_Bool
_eina_rwlock_new(Eina_RWLock *mutex)
eina_condition_new(Eina_Condition *cond, Eina_Lock *mutex)
{
int ok;
ok = pthread_rwlock_init(&(mutex->mutex), NULL);
if (ok == 0) return EINA_TRUE;
else if ((ok == EAGAIN) || (ok == ENOMEM)) return EINA_FALSE;
else EINA_LOCK_ABORT_DEBUG(ok, rwlock_init, mutex);
return EINA_FALSE;
return _eina_condition_new(cond, mutex);
}
EAPI void
_eina_rwlock_free(Eina_RWLock *mutex)
eina_condition_free(Eina_Condition *cond)
{
pthread_rwlock_destroy(&(mutex->mutex));
_eina_condition_free(cond);
}
EAPI Eina_Bool
_eina_barrier_new(Eina_Barrier *barrier, int needed)
eina_condition_wait(Eina_Condition *cond)
{
#ifdef EINA_HAVE_PTHREAD_BARRIER
int ok = pthread_barrier_init(&(barrier->barrier), NULL, needed);
if (ok == 0) return EINA_TRUE;
else if ((ok == EAGAIN) || (ok == ENOMEM)) return EINA_FALSE;
else EINA_LOCK_ABORT_DEBUG(ok, barrier_init, barrier);
return EINA_FALSE;
#else
barrier->needed = needed;
barrier->called = 0;
if (eina_lock_new(&(barrier->cond_lock)))
{
if (eina_condition_new(&(barrier->cond), &(barrier->cond_lock)))
return EINA_TRUE;
}
return EINA_FALSE;
#endif
return _eina_condition_wait(cond);
}
EAPI Eina_Bool
eina_condition_timedwait(Eina_Condition *cond, double t)
{
return _eina_condition_timedwait(cond, t);
}
EAPI Eina_Bool
eina_condition_broadcast(Eina_Condition *cond)
{
return _eina_condition_broadcast(cond);
}
EAPI Eina_Bool
eina_condition_signal(Eina_Condition *cond)
{
return _eina_condition_signal(cond);
}
EAPI Eina_Bool
eina_rwlock_new(Eina_RWLock *mutex)
{
return _eina_rwlock_new(mutex);
}
EAPI void
_eina_barrier_free(Eina_Barrier *barrier)
eina_rwlock_free(Eina_RWLock *mutex)
{
#ifdef EINA_HAVE_PTHREAD_BARRIER
int ok = pthread_barrier_destroy(&(barrier->barrier));
if (ok != 0) EINA_LOCK_ABORT_DEBUG(ok, barrier_destroy, barrier);
#else
eina_condition_free(&(barrier->cond));
eina_lock_free(&(barrier->cond_lock));
barrier->needed = 0;
barrier->called = 0;
#endif
_eina_rwlock_free(mutex);
}
EAPI Eina_Lock_Result
eina_rwlock_take_read(Eina_RWLock *mutex)
{
return _eina_rwlock_take_read(mutex);
}
EAPI Eina_Lock_Result
eina_rwlock_take_write(Eina_RWLock *mutex)
{
return _eina_rwlock_take_write(mutex);
}
EAPI Eina_Lock_Result
eina_rwlock_release(Eina_RWLock *mutex)
{
return _eina_rwlock_release(mutex);
}
EAPI Eina_Bool
_eina_spinlock_new(Eina_Spinlock *spinlock)
eina_tls_cb_new(Eina_TLS *key, Eina_TLS_Delete_Cb delete_cb)
{
#if defined(EINA_HAVE_POSIX_SPINLOCK)
int ok = pthread_spin_init(spinlock, PTHREAD_PROCESS_PRIVATE);
if (ok == 0) return EINA_TRUE;
else if ((ok == EAGAIN) || (ok == ENOMEM)) return EINA_FALSE;
else EINA_LOCK_ABORT_DEBUG(ok, spin_init, spinlock);
return EINA_FALSE;
#elif defined(EINA_HAVE_OSX_SPINLOCK)
*spinlock = 0;
return EINA_TRUE;
#else
return eina_lock_new(spinlock);
#endif
return _eina_tls_cb_new(key, delete_cb);
}
EAPI Eina_Bool
eina_tls_new(Eina_TLS *key)
{
return _eina_tls_cb_new(key, NULL);
}
EAPI void
_eina_spinlock_free(Eina_Spinlock *spinlock)
eina_tls_free(Eina_TLS key)
{
#if defined(EINA_HAVE_POSIX_SPINLOCK)
int ok = pthread_spin_destroy(spinlock);
if (ok != 0) EINA_LOCK_ABORT_DEBUG(ok, spin_destroy, spinlock);
#elif defined(EINA_HAVE_OSX_SPINLOCK)
/* Not applicable */
(void) spinlock;
#else
eina_lock_free(spinlock);
#endif
_eina_tls_free(key);
}
EAPI void *
eina_tls_get(Eina_TLS key)
{
return _eina_tls_get(key);
}
EAPI Eina_Bool
_eina_semaphore_new(Eina_Semaphore *sem, int count_init)
eina_tls_set(Eina_TLS key, const void *data)
{
if (sem && (count_init >= 0))
{
#if defined(EINA_HAVE_OSX_SEMAPHORE)
kern_return_t kr = semaphore_create(mach_task_self(), sem, SYNC_POLICY_FIFO, count_init);
return (kr == KERN_SUCCESS) ? EINA_TRUE : EINA_FALSE;
#else
return (sem_init(sem, 0, count_init) == 0) ? EINA_TRUE : EINA_FALSE;
#endif
}
return EINA_FALSE;
return _eina_tls_set(key, data);
}
EAPI Eina_Bool
_eina_semaphore_free(Eina_Semaphore *sem)
eina_barrier_new(Eina_Barrier *barrier, int needed)
{
if (sem)
{
#if defined(EINA_HAVE_OSX_SEMAPHORE)
return (semaphore_destroy(mach_task_self(), *sem) == KERN_SUCCESS)
? EINA_TRUE : EINA_FALSE;
#else
return (sem_destroy(sem) == 0) ? EINA_TRUE : EINA_FALSE;
#endif
}
return EINA_FALSE;
return _eina_barrier_new(barrier, needed);
}
EAPI void
eina_barrier_free(Eina_Barrier *barrier)
{
_eina_barrier_free(barrier);
}
EAPI Eina_Bool
eina_barrier_wait(Eina_Barrier *barrier)
{
return _eina_barrier_wait(barrier);
}
EAPI Eina_Bool
eina_spinlock_new(Eina_Spinlock *spinlock)
{
return _eina_spinlock_new(spinlock);
}
EAPI void
eina_spinlock_free(Eina_Spinlock *spinlock)
{
_eina_spinlock_free(spinlock);
}
EAPI Eina_Lock_Result
eina_spinlock_take_try(Eina_Spinlock *spinlock)
{
return _eina_spinlock_take_try(spinlock);
}
EAPI Eina_Lock_Result
eina_spinlock_take(Eina_Spinlock *spinlock)
{
return _eina_spinlock_take(spinlock);
}
EAPI Eina_Lock_Result
eina_spinlock_release(Eina_Spinlock *spinlock)
{
return _eina_spinlock_release(spinlock);
}
EAPI Eina_Bool
eina_semaphore_new(Eina_Semaphore *sem, int count_init)
{
return _eina_semaphore_new(sem, count_init);
}
EAPI Eina_Bool
eina_semaphore_free(Eina_Semaphore *sem)
{
return _eina_semaphore_free(sem);
}
EAPI Eina_Bool
eina_semaphore_lock(Eina_Semaphore *sem)
{
return _eina_semaphore_lock(sem);
}
EAPI Eina_Bool
eina_semaphore_release(Eina_Semaphore *sem, int count_release EINA_UNUSED)
{
return _eina_semaphore_release(sem, count_release);
}

View File

@ -97,7 +97,11 @@ typedef enum
*/
typedef void (*Eina_TLS_Delete_Cb)(void *ptr);
#include "eina_inline_lock_posix.x"
#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
@ -117,7 +121,7 @@ EAPI extern Eina_Error EINA_ERROR_NOT_MAIN_LOOP;
*
* @see eina_lock_free()
*/
static inline Eina_Bool eina_lock_new(Eina_Lock *mutex);
EAPI Eina_Bool eina_lock_new(Eina_Lock *mutex);
/**
* @brief Initializes a new #Eina_Lock that is recursive.
@ -133,7 +137,7 @@ static inline Eina_Bool eina_lock_new(Eina_Lock *mutex);
* @see eina_lock_free()
* @since 1.19
*/
static inline Eina_Bool eina_lock_recursive_new(Eina_Lock *mutex);
EAPI Eina_Bool eina_lock_recursive_new(Eina_Lock *mutex);
/**
* @brief Deallocates an #Eina_Lock.
@ -144,7 +148,7 @@ static inline Eina_Bool eina_lock_recursive_new(Eina_Lock *mutex);
*
* @see eina_lock_new()
*/
static inline void eina_lock_free(Eina_Lock *mutex);
EAPI void eina_lock_free(Eina_Lock *mutex);
/**
* @brief Attempts to take a lock.
@ -162,7 +166,7 @@ static inline void eina_lock_free(Eina_Lock *mutex);
* @see eina_lock_take_try()
* @see eina_lock_release()
*/
static inline Eina_Lock_Result eina_lock_take(Eina_Lock *mutex);
EAPI Eina_Lock_Result eina_lock_take(Eina_Lock *mutex);
/**
* @brief Attempts to take a lock if possible.
@ -178,7 +182,7 @@ static inline Eina_Lock_Result eina_lock_take(Eina_Lock *mutex);
* @see eina_lock_take()
* @see eina_lock_release()
*/
static inline Eina_Lock_Result eina_lock_take_try(Eina_Lock *mutex);
EAPI Eina_Lock_Result eina_lock_take_try(Eina_Lock *mutex);
/**
* @brief Releases a lock.
@ -194,7 +198,7 @@ static inline Eina_Lock_Result eina_lock_take_try(Eina_Lock *mutex);
* @see eina_lock_take()
* @see eina_lock_take_try()
*/
static inline Eina_Lock_Result eina_lock_release(Eina_Lock *mutex);
EAPI Eina_Lock_Result eina_lock_release(Eina_Lock *mutex);
/**
* @brief Prints debug information about a lock.
@ -226,7 +230,7 @@ EAPI void eina_lock_debug(const Eina_Lock *mutex);
*
* @see eina_condition_free()
*/
static inline Eina_Bool eina_condition_new(Eina_Condition *cond, Eina_Lock *mutex);
EAPI Eina_Bool eina_condition_new(Eina_Condition *cond, Eina_Lock *mutex);
/**
* @brief Deallocates a condition variable.
@ -237,7 +241,7 @@ static inline Eina_Bool eina_condition_new(Eina_Condition *cond, Eina_Lock *mute
*
* @see eina_condition_new()
*/
static inline void eina_condition_free(Eina_Condition *cond);
EAPI void eina_condition_free(Eina_Condition *cond);
/**
* @brief Causes a thread to wait until signaled by the condition.
@ -249,7 +253,7 @@ static inline void eina_condition_free(Eina_Condition *cond);
*
* @see eina_condition_timedwait()
*/
static inline Eina_Bool eina_condition_wait(Eina_Condition *cond);
EAPI Eina_Bool eina_condition_wait(Eina_Condition *cond);
/**
* @brief Causes a thread to wait until signaled by the condition or a
@ -265,7 +269,7 @@ static inline Eina_Bool eina_condition_wait(Eina_Condition *cond);
*
* @see eina_condition_wait()
*/
static inline Eina_Bool eina_condition_timedwait(Eina_Condition *cond, double t);
EAPI Eina_Bool eina_condition_timedwait(Eina_Condition *cond, double t);
/**
* @brief Signals all threads waiting for a condition.
@ -279,7 +283,7 @@ static inline Eina_Bool eina_condition_timedwait(Eina_Condition *cond, double t)
*
* @see eina_condition_signal()
*/
static inline Eina_Bool eina_condition_broadcast(Eina_Condition *cond);
EAPI Eina_Bool eina_condition_broadcast(Eina_Condition *cond);
/**
* @brief Signals a thread waiting for a condition.
@ -296,7 +300,7 @@ static inline Eina_Bool eina_condition_broadcast(Eina_Condition *cond);
*
* @see eina_condition_broadcast()
*/
static inline Eina_Bool eina_condition_signal(Eina_Condition *cond);
EAPI Eina_Bool eina_condition_signal(Eina_Condition *cond);
/**
@ -311,7 +315,7 @@ static inline Eina_Bool eina_condition_signal(Eina_Condition *cond);
*
* @see eina_rwlock_free()
*/
static inline Eina_Bool eina_rwlock_new(Eina_RWLock *mutex);
EAPI Eina_Bool eina_rwlock_new(Eina_RWLock *mutex);
/**
* @brief Deallocates an #Eina_RWLock.
@ -322,7 +326,7 @@ static inline Eina_Bool eina_rwlock_new(Eina_RWLock *mutex);
*
* @see eina_rwlock_new()
*/
static inline void eina_rwlock_free(Eina_RWLock *mutex);
EAPI void eina_rwlock_free(Eina_RWLock *mutex);
/**
* @brief Attempts to take a read lock.
@ -338,7 +342,7 @@ static inline void eina_rwlock_free(Eina_RWLock *mutex);
*
* @see eina_rwlock_release()
*/
static inline Eina_Lock_Result eina_rwlock_take_read(Eina_RWLock *mutex);
EAPI Eina_Lock_Result eina_rwlock_take_read(Eina_RWLock *mutex);
/**
* @brief Attempts to take a write lock.
@ -354,7 +358,7 @@ static inline Eina_Lock_Result eina_rwlock_take_read(Eina_RWLock *mutex);
*
* @see eina_rwlock_release()
*/
static inline Eina_Lock_Result eina_rwlock_take_write(Eina_RWLock *mutex);
EAPI Eina_Lock_Result eina_rwlock_take_write(Eina_RWLock *mutex);
/**
* @brief Releases a lock.
@ -368,7 +372,7 @@ static inline Eina_Lock_Result eina_rwlock_take_write(Eina_RWLock *mutex);
* @see eina_rwlock_take_read()
* @see eina_rwlock_take_write()
*/
static inline Eina_Lock_Result eina_rwlock_release(Eina_RWLock *mutex);
EAPI Eina_Lock_Result eina_rwlock_release(Eina_RWLock *mutex);
/**
* @brief Initializes a new #Eina_TLS, or thread level storage, to store thread
@ -386,7 +390,7 @@ static inline Eina_Lock_Result eina_rwlock_release(Eina_RWLock *mutex);
* @see eina_tls_cb_new()
* @see eina_tls_free()
*/
static inline Eina_Bool eina_tls_new(Eina_TLS *key);
EAPI Eina_Bool eina_tls_new(Eina_TLS *key);
/**
* @brief Initializes a new #Eina_TLS, or thread level storage, to store thread
@ -403,7 +407,7 @@ static inline Eina_Bool eina_tls_new(Eina_TLS *key);
* @see eina_tls_new()
* @see eina_tls_free()
*/
static inline Eina_Bool eina_tls_cb_new(Eina_TLS *key, Eina_TLS_Delete_Cb delete_cb);
EAPI Eina_Bool eina_tls_cb_new(Eina_TLS *key, Eina_TLS_Delete_Cb delete_cb);
/**
* @brief Frees an allocated #Eina_TLS.
@ -415,7 +419,7 @@ static inline Eina_Bool eina_tls_cb_new(Eina_TLS *key, Eina_TLS_Delete_Cb delete
* @see eina_tls_new()
* @see eina_tls_cb_new()
*/
static inline void eina_tls_free(Eina_TLS key);
EAPI void eina_tls_free(Eina_TLS key);
/**
* @brief Gets the value in #Eina_TLS for this thread.
@ -428,7 +432,7 @@ static inline void eina_tls_free(Eina_TLS key);
*
* @see eina_tls_set()
*/
static inline void *eina_tls_get(Eina_TLS key);
EAPI void *eina_tls_get(Eina_TLS key);
/**
* @brief Sets the value in Eina_TLS for this thread.
@ -442,7 +446,7 @@ static inline void *eina_tls_get(Eina_TLS key);
*
* @see eina_tls_get()
*/
static inline Eina_Bool eina_tls_set(Eina_TLS key, const void *data);
EAPI Eina_Bool eina_tls_set(Eina_TLS key, const void *data);
/**
* @brief Initializes a new #Eina_Semaphore.
@ -456,7 +460,7 @@ static inline Eina_Bool eina_tls_set(Eina_TLS key, const void *data);
*
* @see eina_semaphore_free()
*/
static inline Eina_Bool eina_semaphore_new(Eina_Semaphore *sem, int count_init);
EAPI Eina_Bool eina_semaphore_new(Eina_Semaphore *sem, int count_init);
/**
* @brief Frees an allocated #Eina_Semaphore.
@ -469,7 +473,7 @@ static inline Eina_Bool eina_semaphore_new(Eina_Semaphore *sem, int count_init);
*
* @see eina_semaphore_new()
*/
static inline Eina_Bool eina_semaphore_free(Eina_Semaphore *sem);
EAPI Eina_Bool eina_semaphore_free(Eina_Semaphore *sem);
/**
* @brief Gets a lock on an #Eina_Semaphore.
@ -482,7 +486,7 @@ static inline Eina_Bool eina_semaphore_free(Eina_Semaphore *sem);
*
* @see eina_semaphore_release()
*/
static inline Eina_Bool eina_semaphore_lock(Eina_Semaphore *sem);
EAPI Eina_Bool eina_semaphore_lock(Eina_Semaphore *sem);
/**
* @brief Releases a lock on an #Eina_Semaphore.
@ -496,7 +500,7 @@ static inline Eina_Bool eina_semaphore_lock(Eina_Semaphore *sem);
*
* @see eina_semaphore_lock()
*/
static inline Eina_Bool eina_semaphore_release(Eina_Semaphore *sem, int count_release);
EAPI Eina_Bool eina_semaphore_release(Eina_Semaphore *sem, int count_release);
/**
* @brief Initializes a new #Eina_Barrier.
@ -511,7 +515,7 @@ static inline Eina_Bool eina_semaphore_release(Eina_Semaphore *sem, int count_re
*
* @see eina_barrier_free()
*/
static inline Eina_Bool eina_barrier_new(Eina_Barrier *barrier, int needed);
EAPI Eina_Bool eina_barrier_new(Eina_Barrier *barrier, int needed);
/**
* @brief Frees an allocated #Eina_Barrier.
@ -521,7 +525,7 @@ static inline Eina_Bool eina_barrier_new(Eina_Barrier *barrier, int needed);
*
* @see eina_barrier_new()
*/
static inline void eina_barrier_free(Eina_Barrier *barrier);
EAPI void eina_barrier_free(Eina_Barrier *barrier);
/**
* @brief Increments the count of threads that are waiting on @p barrier.
@ -532,7 +536,7 @@ static inline void eina_barrier_free(Eina_Barrier *barrier);
* @return #EINA_TRUE on success, else #EINA_FALSE otherwise.
*
*/
static inline Eina_Bool eina_barrier_wait(Eina_Barrier *barrier);
EAPI Eina_Bool eina_barrier_wait(Eina_Barrier *barrier);
/**
@ -549,7 +553,7 @@ static inline Eina_Bool eina_barrier_wait(Eina_Barrier *barrier);
*
* @see eina_spinlock_free()
*/
static inline Eina_Bool eina_spinlock_new(Eina_Spinlock *spinlock);
EAPI Eina_Bool eina_spinlock_new(Eina_Spinlock *spinlock);
/**
* @brief Attempts to take a spinlock.
@ -567,7 +571,7 @@ static inline Eina_Bool eina_spinlock_new(Eina_Spinlock *spinlock);
* @see eina_spinlock_take_try()
* @see eina_spinlock_release()
*/
static inline Eina_Lock_Result eina_spinlock_take(Eina_Spinlock *spinlock);
EAPI Eina_Lock_Result eina_spinlock_take(Eina_Spinlock *spinlock);
/**
* @brief Attempts to take a spinlock if possible.
@ -583,7 +587,7 @@ static inline Eina_Lock_Result eina_spinlock_take(Eina_Spinlock *spinlock);
* @see eina_spinlock_take_try()
* @see eina_spinlock_release()
*/
static inline Eina_Lock_Result eina_spinlock_take_try(Eina_Spinlock *spinlock);
EAPI Eina_Lock_Result eina_spinlock_take_try(Eina_Spinlock *spinlock);
/**
* @brief Releases a spinlock.
@ -599,7 +603,7 @@ static inline Eina_Lock_Result eina_spinlock_take_try(Eina_Spinlock *spinlock);
* @see eina_spinlock_take_try()
*/
static inline Eina_Lock_Result eina_spinlock_release(Eina_Spinlock *spinlock);
EAPI Eina_Lock_Result eina_spinlock_release(Eina_Spinlock *spinlock);
/**
* @brief Deallocates an #Eina_Spinlock.
@ -609,7 +613,7 @@ static inline Eina_Lock_Result eina_spinlock_release(Eina_Spinlock *spinlock);
* @param[in] spinlock The #Eina_Spinlock to be deallocated.
*
*/
static inline void eina_spinlock_free(Eina_Spinlock *spinlock);
EAPI void eina_spinlock_free(Eina_Spinlock *spinlock);
#ifdef EINA_HAVE_DEBUG_THREADS
# define EINA_MAIN_LOOP_CHECK_RETURN_VAL(val) \

View File

@ -41,6 +41,7 @@
#endif
#include "eina_lock.h"
#include "eina_thread.h"
#include "eina_config.h"
#include "eina_private.h"
#include "eina_types.h"
@ -99,7 +100,7 @@ EAPI Eina_Error EINA_ERROR_NOT_IMPLEMENTED = 0;
EAPI unsigned int eina_seed = 0;
#ifdef EFL_HAVE_THREADS
EAPI Eina_Thread _eina_main_loop;
EAPI Eina_Thread _eina_main_loop;
#endif
#ifdef MT
@ -108,7 +109,7 @@ static int _mt_enabled = 0;
#ifdef EFL_HAVE_THREADS
EAPI int _eina_threads_debug = 0;
EAPI pthread_mutex_t _eina_tracking_lock;
EAPI Eina_Lock _eina_tracking_lock;
EAPI Eina_Inlist *_eina_tracking = NULL;
extern Eina_Lock _sysmon_lock;
#endif
@ -230,7 +231,7 @@ _eina_threads_do_shutdown(void)
#ifdef EINA_HAVE_DEBUG_THREADS
const Eina_Lock *lk;
pthread_mutex_lock(&_eina_tracking_lock);
eina_lock_take(&_eina_tracking_lock);
if (_eina_tracking)
{
if (((Eina_Lock*)_eina_tracking != (&_sysmon_lock)) || (_eina_tracking->next))
@ -248,7 +249,7 @@ _eina_threads_do_shutdown(void)
abort();
}
}
pthread_mutex_unlock(&_eina_tracking_lock);
eina_lock_release(&_eina_tracking_lock);
#endif
eina_share_common_threads_shutdown();
@ -317,7 +318,7 @@ eina_init(void)
}
#ifdef EINA_HAVE_DEBUG_THREADS
pthread_mutex_init(&_eina_tracking_lock, NULL);
eina_lock_take(&_eina_tracking_lock, NULL);
if (getenv("EINA_DEBUG_THREADS"))
_eina_threads_debug = atoi(getenv("EINA_DEBUG_THREADS"));
@ -367,7 +368,7 @@ eina_shutdown(void)
if (_eina_threads_activated && (!_eina_main_thread_count))
_eina_threads_do_shutdown();
#ifdef EINA_HAVE_DEBUG_THREADS
pthread_mutex_destroy(&_eina_tracking_lock);
eina_lock_free(&_eina_tracking_lock);
#endif
eina_freeq_free(eina_freeq_main_get());
#ifdef MT
@ -388,7 +389,7 @@ eina_threads_init(void)
{
#ifdef EFL_HAVE_THREADS
int ret;
# ifdef EINA_HAVE_DEBUG_THREADS
# ifdef EINA_HAVE_DEBUG_THREADS
assert(eina_thread_equal(_eina_main_loop, eina_thread_self()));
# endif
@ -438,7 +439,7 @@ eina_main_loop_is(void)
#ifdef EFL_HAVE_THREADS
# ifdef __GNUC__
/* pthread_self() can't be optimized, it's a single asm "movl" */
if (__builtin_types_compatible_p(pthread_t, unsigned long int))
if (__builtin_types_compatible_p(Eina_Thread, unsigned long int))
return (eina_thread_self() == _eina_main_loop);
else
# endif

View File

@ -85,8 +85,6 @@ public_sub_headers = [
'eina_inline_value.x',
'eina_value_util.h',
'eina_inline_value_util.x',
'eina_inline_lock_barrier.x',
'eina_inline_lock_posix.x',
'eina_tmpstr.h',
'eina_alloca.h',
'eina_cow.h',
@ -197,15 +195,17 @@ sources = [
]
if sys_windows == true
public_sub_headers += 'eina_thread_win32.h'
public_sub_headers += 'eina_inline_thread_win32.x'
public_sub_headers += 'eina_thread_win32.h'
public_sub_headers += 'eina_inline_thread_win32.x'
sources += 'eina_file_win32.c'
sources += 'eina_sched_win32.c'
sources += 'eina_sched_win32.c'
public_sub_headers += 'eina_inline_lock_win32.x'
else
public_sub_headers += 'eina_thread_posix.h'
public_sub_headers += 'eina_thread_posix.h'
public_sub_headers += 'eina_inline_thread_posix.x'
sources += 'eina_file.c'
sources += 'eina_sched_posix.c'
sources += 'eina_sched_posix.c'
public_sub_headers += 'eina_inline_lock_posix.x'
endif
eina_config = configuration_data()
@ -347,7 +347,7 @@ if cc.has_header('byteswap.h')
endif
if cc.has_header_symbol('pthread.h', 'pthread_spin_init')
eina_config.set('EINA_HAVE_POSIX_SPINLOCK', '1')
eina_config.set('EINA_HAVE_PTHREAD_SPINLOCK', '1')
endif
if sys_osx == true
@ -359,6 +359,15 @@ if sys_osx == true
endif
endif
if sys_windows == true
if cc.has_header_symbol('synchapi.h', 'SetCriticalSectionSpinCount')
eina_config.set('EINA_HAVE_WIN32_SPINLOCK', '1')
endif
if cc.has_header_symbol('synchapi.h', 'InitializeSynchronizationBarrier')
eina_config.set('EINA_HAVE_WIN32_BARRIER', '1')
endif
endif
if host_machine.endian() == 'big'
eina_config.set('EINA_HAVE_WORDS_BIGENDIAN', '1')
endif
@ -423,4 +432,4 @@ pkgconfig.generate(eina_lib,
version : version_major + '.' + version_minor + '.' + version_micro,
libraries : eina_pub_deps,
)
endif
endif

View File

@ -10,7 +10,6 @@ if sys_windows
'locale.h',
'math.h',
'pthread.h',
'semaphore.h',
'stdlib.h',
'string.h',
'strings.h',

View File

@ -5,24 +5,15 @@
UNIMPLEMENTED typedef unsigned long long pthread_t;
UNIMPLEMENTED_STRUCT_T(pthread_mutexattr)
UNIMPLEMENTED_STRUCT_T(pthread_condattr)
UNIMPLEMENTED_STRUCT_T(pthread_attr)
UNIMPLEMENTED_STRUCT_T(pthread_rwlock)
UNIMPLEMENTED_STRUCT_T(pthread_cond)
UNIMPLEMENTED_STRUCT_T(pthread_mutex)
UNIMPLEMENTED_STRUCT_T(sem)
UNIMPLEMENTED struct sched_param {
int sched_priority;
};
UNIMPLEMENTED typedef int pthread_key_t;
#define SCHED_RR 5
#define SCHED_FIFO 6
#define PTHREAD_BARRIER_SERIAL_THREAD 1
#define PTHREAD_CANCEL_ASYNCHRONOUS 2
#define PTHREAD_CANCEL_ENABLE 3
#define PTHREAD_CANCEL_DEFERRED 4
@ -32,12 +23,6 @@ UNIMPLEMENTED typedef int pthread_key_t;
#define PTHREAD_CREATE_JOINABLE 8
#define PTHREAD_EXPLICIT_SCHED 9
#define PTHREAD_INHERIT_SCHED 10
#define PTHREAD_MUTEX_DEFAULT 11
#define PTHREAD_MUTEX_ERRORCHECK 12
#define PTHREAD_MUTEX_NORMAL 13
#define PTHREAD_MUTEX_RECURSIVE 14
#define PTHREAD_MUTEX_ROBUST 15
#define PTHREAD_MUTEX_STALLED 16
#define PTHREAD_ONCE_INIT 17
#define PTHREAD_PRIO_INHERIT 18
#define PTHREAD_PRIO_NONE 19
@ -47,202 +32,4 @@ UNIMPLEMENTED typedef int pthread_key_t;
#define PTHREAD_SCOPE_PROCESS 23
#define PTHREAD_SCOPE_SYSTEM 24
UNIMPLEMENTED inline int pthread_mutex_trylock(void* m)
{
#warning pthread_mutex_trylock is not implemented.
return 0;
}
UNIMPLEMENTED inline int pthread_mutex_lock(void* m)
{
#warning pthread_mutex_lock is not implemented.
return 0;
}
UNIMPLEMENTED inline int pthread_mutex_unlock(void* m)
{
#warning pthread_mutex_unlock is not implemented.
return 0;
}
UNIMPLEMENTED inline int pthread_cond_wait(void* c, void* m)
{
#warning pthread_cond_wait is not implemented.
return 0;
}
UNIMPLEMENTED inline int pthread_cond_timedwait(void* c, void* m, int t)
{
#warning pthread_cond_timedwait is not implemented.
return 0;
}
UNIMPLEMENTED inline int pthread_cond_broadcast(void* c)
{
#warning pthread_cond_broadcast is not implemented.
return 0;
}
UNIMPLEMENTED inline int pthread_cond_signal(void* c)
{
#warning pthread_cond_signal is not implemented.
return 0;
}
UNIMPLEMENTED inline int pthread_rwlock_init(void* a, ...)
{
#warning pthread_rwlock_init is not implemented.
return 0;
}
UNIMPLEMENTED inline int pthread_mutexattr_settype(void* a, ...)
{
#warning pthread_mutexattr_settype is not implemented.
return 0;
}
UNIMPLEMENTED inline int pthread_mutex_init(void* a, ...)
{
#warning pthread_mutex_init is not implemented.
return 0;
}
UNIMPLEMENTED inline int pthread_mutex_destroy(void* a, ...)
{
#warning pthread_mutex_destroy is not implemented.
return 0;
}
UNIMPLEMENTED inline int pthread_condattr_init(void* a, ...)
{
#warning pthread_condattr_init is not implemented.
return 0;
}
UNIMPLEMENTED inline int pthread_cond_init(void* a, ...)
{
#warning pthread_cond_init is not implemented.
return 0;
}
UNIMPLEMENTED inline int pthread_condattr_destroy(void* a, ...)
{
#warning pthread_condattr_destroy is not implemented.
return 0;
}
UNIMPLEMENTED inline int pthread_cond_destroy(void* a, ...)
{
#warning pthread_cond_destroy is not implemented.
return 0;
}
UNIMPLEMENTED inline int pthread_rwlock_destroy(void* a, ...)
{
#warning pthread_rwlock_destroy is not implemented.
return 0;
}
UNIMPLEMENTED inline int pthread_rwlock_rdlock(void* c)
{
#warning pthread_rwlock_rdlock is not implemented.
return 0;
}
UNIMPLEMENTED inline int pthread_rwlock_wrlock(void* c)
{
#warning pthread_rwlock_wrlock is not implemented.
return 0;
}
UNIMPLEMENTED inline int pthread_rwlock_unlock(void* c)
{
#warning pthread_rwlock_unlock is not implemented.
return 0;
}
UNIMPLEMENTED inline int pthread_key_create(void* c, void * d)
{
#warning pthread_key_create is not implemented.
return 0;
}
UNIMPLEMENTED inline int pthread_key_delete(void* c)
{
#warning pthread_key_delete is not implemented.
return 0;
}
UNIMPLEMENTED inline int pthread_getspecific(void* c)
{
#warning pthread_getspecific is not implemented.
return 0;
}
UNIMPLEMENTED inline int pthread_setspecific(void* c, const void* d)
{
#warning pthread_setspecific is not implemented.
return 0;
}
UNIMPLEMENTED inline int pthread_mutexattr_init(void* c, ...)
{
#warning pthread_mutexattr_init is not implemented.
return 0;
}
UNIMPLEMENTED inline int pthread_getschedparam(void* a, ...)
{
#warning pthread_getschedparam is not implemented.
return 0;
}
UNIMPLEMENTED inline int pthread_setschedparam(void* c, void* d, void* e)
{
#warning pthread_ is not implemented.
return 0;
}
UNIMPLEMENTED inline int pthread_setcancelstate(void* a, ...)
{
#warning pthread_setcancelstate is not implemented.
return 0;
}
UNIMPLEMENTED inline int pthread_testcancel()
{
#warning pthread_testcancel is not implemented.
return 0;
}
UNIMPLEMENTED inline int pthread_cleanup_pop(void* a, ...)
{
#warning pthread_cleanup_pop is not implemented.
return 0;
}
UNIMPLEMENTED inline int pthread_cleanup_push(void* a, ...)
{
#warning pthread_cleanup_push is not implemented.
return 0;
}
UNIMPLEMENTED inline int pthread_attr_init(void* a, ...)
{
#warning pthread_attr_init is not implemented.
return 0;
}
UNIMPLEMENTED inline int pthread_setcanceltype(void* a, ...)
{
#warning pthread_setcanceltype is not implemented.
return 0;
}
UNIMPLEMENTED inline int pthread_mutexattr_destroy(void* a, ...)
{
#warning pthread_mutexattr_destroy is not implemented.
return 0;
}
#endif

View File

@ -1,59 +0,0 @@
#ifndef SEMAPHORE_H
#define SEMAPHORE_H
#include "unimplemented.h"
UNIMPLEMENTED_STRUCT_T(sem)
UNIMPLEMENTED inline int sem_close(sem_t* sem)
{
#warning sem_close is not implemented
return 0;
}
UNIMPLEMENTED inline int sem_destroy(sem_t* sem)
{
#warning sem_destroy is not implemented
return 0;
}
UNIMPLEMENTED inline int sem_getvalue(sem_t* restrict sem, int* restrict x)
{
#warning sem_getvalue is not implemented
return 0;
}
UNIMPLEMENTED inline int sem_init(sem_t* sem, int x, unsigned y)
{
#warning sem_init is not implemented
return 0;
}
UNIMPLEMENTED inline sem_t* sem_open(const char* name, int x, ...)
{
#warning sem_open is not implemented
return 0;
}
UNIMPLEMENTED inline int sem_post(sem_t* sem)
{
#warning sem_post is not implemented
return 0;
}
UNIMPLEMENTED inline int sem_timedwait(sem_t* restrict sem, const struct timespec* restrict timeout)
{
#warning sem_timedwait is not implemented
return 0;
}
UNIMPLEMENTED inline int sem_trywait(sem_t* sem)
{
#warning sem_trywait is not implemented
return 0;
}
UNIMPLEMENTED inline int sem_unlink(const char* name)
{
#warning sem_unlink is not implemented
return 0;
}
UNIMPLEMENTED inline int sem_wait(sem_t* sem)
{
#warning sem_wait is not implemented
return 0;
}
#endif