diff --git a/configure.ac b/configure.ac index dbd24ccbc2..c39c5505dd 100644 --- a/configure.ac +++ b/configure.ac @@ -936,6 +936,7 @@ EINA_CONFIG([HAVE_PTHREAD_BARRIER], [test "x${efl_have_pthread_barrier}" = "xyes EINA_CONFIG([HAVE_PTHREAD_AFFINITY], [test "x${efl_have_setaffinity}" = "xyes"]) EINA_CONFIG([HAVE_DEBUG_THREADS], [test "x${want_debug_threads}" = "xyes"]) EINA_CONFIG([HAVE_POSIX_SPINLOCK], [test "x${efl_have_posix_threads_spinlock}" = "xyes"]) +EINA_CONFIG([HAVE_OSX_SPINLOCK], [test "x${efl_have_osx_spinlock}" = "xyes"]) ### Modules @@ -4498,7 +4499,12 @@ elif test "${have_windows}" = "yes"; then fi EFL_ADD_FEATURE([system], [ipv6]) -EFL_ADD_FEATURE([thread], [spinlocks], [${efl_have_posix_threads_spinlock}]) +if test "x${efl_have_posix_threads_spinlock}" = "xyes" || test "x${efl_have_osx_spinlock}" = "xyes"; then + efl_have_spinlock="yes" +else + efl_have_spinlock="no" +fi +EFL_ADD_FEATURE([thread], [spinlocks], [${efl_have_spinlock}]) EFL_ADD_FEATURE([thread], [barrier], [${efl_have_pthread_barrier}]) EFL_ADD_FEATURE([thread], [affinity], [${efl_have_setaffinity}]) diff --git a/m4/efl_threads.m4 b/m4/efl_threads.m4 index 04b3e64c3a..9596908c96 100644 --- a/m4/efl_threads.m4 +++ b/m4/efl_threads.m4 @@ -125,8 +125,37 @@ if test "x${efl_have_posix_threads_spinlock}" = "xyes" ; then AC_DEFINE([EFL_HAVE_POSIX_THREADS_SPINLOCK], [1], [Define to mention that POSIX threads spinlocks are supported]) fi + +dnl checks if the compiler supports OSX spinlock + +efl_have_osx_spinlock="no" + +if test "x${_efl_have_posix_threads}" = "xyes" ; then + AC_LINK_IFELSE( + [AC_LANG_PROGRAM([[ +#include + ]], + [[ +OSSpinLock spin_lock = 0; +OSSpinLockTry(&spin_lock); + ]])], + [efl_have_osx_spinlock="yes"], + [efl_have_osx_spinlock="no"]) +fi + +AC_MSG_CHECKING([whether to build OSX spinlock code]) +AC_MSG_RESULT([${efl_have_osx_spinlock}]) + +if test "x${efl_have_osx_spinlock}" = "xyes" ; then + AC_DEFINE([EFL_HAVE_OSX_SPINLOCK], [1], [Define to mention that OSX spinlocks are supported]) +fi + + + AS_IF([test "x$_efl_have_posix_threads" = "xyes" || test "x$_efl_have_win32_threads" = "xyes"], [$1], [m4_if([$2], [$2], [AC_MSG_ERROR([Threads are required.])])]) + ]) + diff --git a/src/lib/eina/eina_config.h.in b/src/lib/eina/eina_config.h.in index 1f6fe676b7..cdaf867a8a 100644 --- a/src/lib/eina/eina_config.h.in +++ b/src/lib/eina/eina_config.h.in @@ -97,6 +97,11 @@ #endif @EINA_CONFIGURE_HAVE_POSIX_SPINLOCK@ +#ifndef EINA_HAVE_OSX_SPINLOCK +# undef EINA_HAVE_OSX_SPINLOCK +#endif +@EINA_CONFIGURE_HAVE_OSX_SPINLOCK@ + /* Do not turn the following #define as meaning EFL64. We are only interested to know if sizeof (void*) == 64bits or not. Those means something else. diff --git a/src/lib/eina/eina_inline_lock_posix.x b/src/lib/eina/eina_inline_lock_posix.x index 0de48e5cc4..172e5714ec 100644 --- a/src/lib/eina/eina_inline_lock_posix.x +++ b/src/lib/eina/eina_inline_lock_posix.x @@ -38,6 +38,10 @@ # include #endif +#ifdef EINA_HAVE_OSX_SPINLOCK +# include +#endif + #include #include @@ -59,8 +63,10 @@ typedef struct _Eina_RWLock Eina_RWLock; typedef struct _Eina_Condition Eina_Condition; typedef pthread_key_t Eina_TLS; typedef sem_t Eina_Semaphore; -#ifdef EINA_HAVE_POSIX_SPINLOCK +#if defined(EINA_HAVE_POSIX_SPINLOCK) typedef pthread_spinlock_t Eina_Spinlock; +#elif defined(EINA_HAVE_OSX_SPINLOCK) +typedef OSSpinLock Eina_Spinlock; #else typedef Eina_Lock Eina_Spinlock; #endif @@ -603,8 +609,13 @@ eina_barrier_wait(Eina_Barrier *barrier) static inline Eina_Bool eina_spinlock_new(Eina_Spinlock *spinlock) { -#ifdef EINA_HAVE_POSIX_SPINLOCK +#if defined(EINA_HAVE_POSIX_SPINLOCK) return pthread_spin_init(spinlock, PTHREAD_PROCESS_PRIVATE) == 0 ? EINA_TRUE : EINA_FALSE; +#elif defined(EINA_HAVE_OSX_SPINLOCK) + /* OSSpinLock is an integer type. The convention is that unlocked is + * zero, and locked is nonzero. */ + *spinlock = 0; + return EINA_LOCK_SUCCEED; #else return eina_lock_new(spinlock); #endif @@ -613,7 +624,7 @@ eina_spinlock_new(Eina_Spinlock *spinlock) static inline Eina_Lock_Result eina_spinlock_take(Eina_Spinlock *spinlock) { -#ifdef EINA_HAVE_POSIX_SPINLOCK +#if defined(EINA_HAVE_POSIX_SPINLOCK) int t; do { @@ -625,6 +636,12 @@ eina_spinlock_take(Eina_Spinlock *spinlock) } } while (t != 0); + return EINA_LOCK_SUCCEED; +#elif defined(EINA_HAVE_OSX_SPINLOCK) + /* void OSSpinLockLock(OSSpinLock *lock); + * Will spin if the lock is already held, but employs various strategies to + * back off, making it immune to most priority-inversion livelocks. */ + OSSpinLockLock(spinlock); return EINA_LOCK_SUCCEED; #else return eina_lock_take(spinlock); @@ -634,11 +651,16 @@ eina_spinlock_take(Eina_Spinlock *spinlock) static inline Eina_Lock_Result eina_spinlock_take_try(Eina_Spinlock *spinlock) { -#ifdef EINA_HAVE_POSIX_SPINLOCK +#if defined(EINA_HAVE_POSIX_SPINLOCK) int t; t = pthread_spin_trylock(spinlock); return t ? EINA_LOCK_FAIL : EINA_LOCK_SUCCEED; +#elif defined(EINA_HAVE_OSX_SPINLOCK) + /* bool OSSpinLockTry(OSSpinLock *lock); + * Immediately returns false if the lock was held, true if it took the + * lock. It does not spin. */ + return (OSSpinLockTry(spinlock)) ? EINA_LOCK_SUCCEED : EINA_LOCK_FAIL; #else return eina_lock_take_try(spinlock); #endif @@ -647,8 +669,13 @@ eina_spinlock_take_try(Eina_Spinlock *spinlock) static inline Eina_Lock_Result eina_spinlock_release(Eina_Spinlock *spinlock) { -#ifdef EINA_HAVE_POSIX_SPINLOCK +#if defined(EINA_HAVE_POSIX_SPINLOCK) return pthread_spin_unlock(spinlock) ? EINA_LOCK_FAIL : EINA_LOCK_SUCCEED; +#elif defined(EINA_HAVE_OSX_SPINLOCK) + /* void OSSpinLockUnlock(OSSpinLock *lock); + * Unconditionally unlocks the lock by zeroing it. */ + OSSpinLockUnlock(spinlock); + return EINA_LOCK_SUCCEED; #else return eina_lock_release(spinlock); #endif @@ -657,8 +684,11 @@ eina_spinlock_release(Eina_Spinlock *spinlock) static inline void eina_spinlock_free(Eina_Spinlock *spinlock) { -#ifdef EINA_HAVE_POSIX_SPINLOCK +#if defined(EINA_HAVE_POSIX_SPINLOCK) pthread_spin_destroy(spinlock); +#elif defined(EINA_HAVE_OSX_SPINLOCK) + /* Not applicable */ + (void) spinlock; #else eina_lock_free(spinlock); #endif @@ -670,4 +700,19 @@ eina_spinlock_free(Eina_Spinlock *spinlock) # define _XOPEN_SOURCE EINA_XOPEN_SOURCE #endif +#ifdef EINA_HAVE_OSX_SPINLOCK +/* The inclusion of libkern/OSAtomic.h is a mess because it includes stdbool + * which #defines bool. #undef bool is not sufficient because then other + * headers (dlfcn.h) require it and #include stdbool.h to get it. It is + * therefore important to "undo" the whole stdbool.h inclusion. */ +# undef true +# undef false +# undef bool +# undef __bool_true_false_are_defined +# undef _STDBOOL_H_ // OSX SDK +# undef __STDBOOL_H // Clang 5.1 +# undef _STDBOOL_H // GCC +#endif + + #endif