eina: port Eina_Spinlock for OSX
authorJean Guyomarc'h <jean.guyomarch@gmail.com>
Thu, 21 Aug 2014 09:23:24 +0000 (11:23 +0200)
committerCedric BAIL <cedric@osg.samsung.com>
Thu, 21 Aug 2014 10:04:53 +0000 (12:04 +0200)
Summary: Support of Spinlocks in Eina (Eina_Spinlock) for OSX, which does not implement them in pthread.
@feature

Reviewers: raster, raoulh, naguirre, cedric, stefan_schmidt

Subscribers: cedric

Differential Revision: https://phab.enlightenment.org/D1151

Signed-off-by: Cedric BAIL <cedric@osg.samsung.com>
configure.ac
m4/efl_threads.m4
src/lib/eina/eina_config.h.in
src/lib/eina/eina_inline_lock_posix.x

index dbd24cc..c39c550 100644 (file)
@@ -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}])
 
index 04b3e64..9596908 100644 (file)
@@ -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 <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.])])])
 
+
 ])
+
index 1f6fe67..cdaf867 100644 (file)
 #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.
index 0de48e5..172e571 100644 (file)
 # include <pthread.h>
 #endif
 
+#ifdef EINA_HAVE_OSX_SPINLOCK
+# include <libkern/OSAtomic.h>
+#endif
+
 #include <semaphore.h>
 
 #include <sys/time.h>
@@ -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 {
@@ -626,6 +637,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);
 #endif
@@ -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