diff --git a/src/lib/eina/eina_debug_bt.c b/src/lib/eina/eina_debug_bt.c index df96833c7d..3b23c622c1 100644 --- a/src/lib/eina/eina_debug_bt.c +++ b/src/lib/eina/eina_debug_bt.c @@ -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) diff --git a/src/lib/eina/eina_inline_lock_barrier.x b/src/lib/eina/eina_inline_lock_barrier.x deleted file mode 100644 index 02f4bdc20d..0000000000 --- a/src/lib/eina/eina_inline_lock_barrier.x +++ /dev/null @@ -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; -} diff --git a/src/lib/eina/eina_inline_lock_posix.x b/src/lib/eina/eina_inline_lock_posix.x index 911b5c1f3b..8dbcf7693e 100644 --- a/src/lib/eina/eina_inline_lock_posix.x +++ b/src/lib/eina/eina_inline_lock_posix.x @@ -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 +# define SPINLOCK_GET(LCK) ((os_unfair_lock_t)(LCK)) +# else +# include +# 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 #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) diff --git a/src/lib/eina/eina_inline_lock_win32.x b/src/lib/eina/eina_inline_lock_win32.x new file mode 100644 index 0000000000..dc5c8659de --- /dev/null +++ b/src/lib/eina/eina_inline_lock_win32.x @@ -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 . + */ + +#ifndef EINA_INLINE_LOCK_WIN32_X_ +#define EINA_INLINE_LOCK_WIN32_X_ + +#ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif + +#include +#include +#undef WIN32_LEAN_AND_MEAN + +#include "unimplemented.h" + +#include + +#include +#include +#include +#include + +#include +#include + +#ifdef EINA_HAVE_DEBUG_THREADS +#include +#include +#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 +#include + +#include + +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 diff --git a/src/lib/eina/eina_lock.c b/src/lib/eina/eina_lock.c index aa085cd15a..1566ab25c3 100644 --- a/src/lib/eina/eina_lock.c +++ b/src/lib/eina/eina_lock.c @@ -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 -# define SPINLOCK_GET(LCK) ((os_unfair_lock_t)(LCK)) -# else -# include -# 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); +} + diff --git a/src/lib/eina/eina_lock.h b/src/lib/eina/eina_lock.h index d173f6be34..a6e438843e 100644 --- a/src/lib/eina/eina_lock.h +++ b/src/lib/eina/eina_lock.h @@ -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) \ diff --git a/src/lib/eina/eina_main.c b/src/lib/eina/eina_main.c index 61c21b01c3..54af2cfa00 100644 --- a/src/lib/eina/eina_main.c +++ b/src/lib/eina/eina_main.c @@ -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 diff --git a/src/lib/eina/meson.build b/src/lib/eina/meson.build index 5d52682d58..e2220f96df 100644 --- a/src/lib/eina/meson.build +++ b/src/lib/eina/meson.build @@ -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 \ No newline at end of file +endif diff --git a/src/lib/evil/unposix/meson.build b/src/lib/evil/unposix/meson.build index 6fba6e87c2..53d82022fa 100644 --- a/src/lib/evil/unposix/meson.build +++ b/src/lib/evil/unposix/meson.build @@ -10,7 +10,6 @@ if sys_windows 'locale.h', 'math.h', 'pthread.h', - 'semaphore.h', 'stdlib.h', 'string.h', 'strings.h', diff --git a/src/lib/evil/unposix/pthread.h b/src/lib/evil/unposix/pthread.h index 7790821c8d..98491dcb49 100644 --- a/src/lib/evil/unposix/pthread.h +++ b/src/lib/evil/unposix/pthread.h @@ -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 diff --git a/src/lib/evil/unposix/semaphore.h b/src/lib/evil/unposix/semaphore.h deleted file mode 100644 index 0e1f46f5bb..0000000000 --- a/src/lib/evil/unposix/semaphore.h +++ /dev/null @@ -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