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
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}])
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 <libkern/OSAtomic.h>
+ ]],
+ [[
+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.])])])
+
])
+
# include <pthread.h>
#endif
+#ifdef EINA_HAVE_OSX_SPINLOCK
+# include <libkern/OSAtomic.h>
+#endif
+
#include <semaphore.h>
#include <sys/time.h>
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
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
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 {
}
} 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);
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
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
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
# 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