diff --git a/ChangeLog b/ChangeLog index f81b1399f1..808f62d291 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2013-10-11 Cedric Bail + + * Eina: add Eina_Spinlock API. + 2013-10-10 Carsten Haitzler (The Rasterman) * Ecore-con: use dlopen/dlsym (eina_module) to load libcurl to diff --git a/NEWS b/NEWS index fa991926b5..91d5bd126a 100644 --- a/NEWS +++ b/NEWS @@ -41,6 +41,7 @@ Additions: EINA_RECTANGLE_INIT, EINA_RECTANGLE_FORMAT, EINA_RECTANGLE_ARGS. - Add eina_f16p16_double_from(), eina_f16p16_double_to(). - Add eina_swap16(), eina_swap32(), eina_swap64(). + - Add Eina_Spinlock API. * Eet: - Add eet_mmap() - Add eet_data_descriptor_name_get() diff --git a/configure.ac b/configure.ac index f9e61b38be..8938381bcc 100644 --- a/configure.ac +++ b/configure.ac @@ -825,7 +825,8 @@ EFL_ADD_CFLAGS([EINA], [${EFL_PTHREAD_CFLAGS}]) 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 "$want_debug_threads" = "yes"]) +EINA_CONFIG([HAVE_DEBUG_THREADS], [test "x${want_debug_threads}" = "xyes"]) +EINA_CONFIG([HAVE_POSIX_SPINLOCK], [test "x${efl_have_posix_threads_spinlock}" = "xyes"]) ### Modules diff --git a/m4/efl_threads.m4 b/m4/efl_threads.m4 index a657500434..e7a84b36c0 100644 --- a/m4/efl_threads.m4 +++ b/m4/efl_threads.m4 @@ -116,11 +116,13 @@ if test "x${_efl_have_posix_threads}" = "xyes" ; then AC_LINK_IFELSE( [AC_LANG_PROGRAM([[ #include +#include ]], [[ pthread_spinlock_t lock; int res; res = pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE); +sched_yield(); ]])], [efl_have_posix_threads_spinlock="yes"], [efl_have_posix_threads_spinlock="no"]) diff --git a/src/lib/eina/eina_config.h.in b/src/lib/eina/eina_config.h.in index 27acdf72b6..72e3ed3eeb 100644 --- a/src/lib/eina/eina_config.h.in +++ b/src/lib/eina/eina_config.h.in @@ -92,4 +92,9 @@ #endif @EINA_CONFIGURE_HAVE_BYTESWAP_H@ +#ifdef EINA_HAVE_POSIX_SPINLOCK +# undef EINA_HAVE_POSIX_SPINLOCK +#endif +@EINA_CONFIGURE_HAVE_POSIX_SPINLOCK@ + #endif /* EINA_CONFIG_H_ */ diff --git a/src/lib/eina/eina_inline_lock_posix.x b/src/lib/eina/eina_inline_lock_posix.x index 88c4b61c11..472717774f 100644 --- a/src/lib/eina/eina_inline_lock_posix.x +++ b/src/lib/eina/eina_inline_lock_posix.x @@ -19,6 +19,10 @@ #ifndef EINA_INLINE_LOCK_POSIX_X_ #define EINA_INLINE_LOCK_POSIX_X_ +#ifdef EINA_HAVE_POSIX_SPINLOCK +# include +#endif + #include #ifndef __USE_UNIX98 # define __USE_UNIX98 @@ -49,6 +53,11 @@ 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 +typedef pthread_spinlock_t Eina_Spinlock; +#else +typedef Eina_Lock Eina_Spinlock; +#endif struct _Eina_Lock { @@ -577,5 +586,79 @@ eina_barrier_wait(Eina_Barrier *barrier) #include "eina_inline_lock_barrier.x" #endif +static inline Eina_Bool +eina_spinlock_new(Eina_Spinlock *spinlock) +{ +#ifdef EINA_HAVE_POSIX_SPINLOCK + return pthread_spin_init(spinlock, PTHREAD_PROCESS_PRIVATE) == 0 ? EINA_TRUE : EINA_FALSE; +#else + return eina_lock_new(spinlock); +#endif +} + +static inline Eina_Lock_Result +eina_spinlock_take(Eina_Spinlock *spinlock) +{ +#ifdef EINA_HAVE_POSIX_SPINLOCK + Eina_Bool yield; + int t; + + do { + yield = EINA_FALSE; + + t = pthread_spin_trylock(spinlock); + if (t != 0) + { + if (errno == EBUSY) + { + sched_yield(); + yield = EINA_TRUE; + } + else if (errno == EDEADLK) + { + return EINA_LOCK_DEADLOCK; + } + } + + } while (t != 0 && yield); + + return t ? EINA_LOCK_FAIL : EINA_LOCK_SUCCEED; +#else + return eina_lock_take(spinlock); +#endif +} + +static inline Eina_Lock_Result +eina_spinlock_take_try(Eina_Spinlock *spinlock) +{ +#ifdef EINA_HAVE_POSIX_SPINLOCK + int t; + + t = pthread_spin_trylock(spinlock); + return t ? EINA_LOCK_FAIL : EINA_LOCK_SUCCEED; +#else + return eina_lock_take_try(spinlock); +#endif +} + +static inline Eina_Lock_Result +eina_spinlock_release(Eina_Spinlock *spinlock) +{ +#ifdef EINA_HAVE_POSIX_SPINLOCK + return pthread_spin_unlock(spinlock) ? EINA_LOCK_FAIL : EINA_LOCK_SUCCEED; +#else + return eina_lock_release(spinlock); +#endif +} + +static inline void +eina_spinlock_free(Eina_Spinlock *spinlock) +{ +#ifdef EINA_HAVE_POSIX_SPINLOCK + pthread_spin_destroy(spinlock); +#else + eina_lock_free(spinlock); +#endif +} #endif diff --git a/src/lib/eina/eina_inline_lock_win32.x b/src/lib/eina/eina_inline_lock_win32.x index 383a543f98..3c637affb1 100644 --- a/src/lib/eina/eina_inline_lock_win32.x +++ b/src/lib/eina/eina_inline_lock_win32.x @@ -30,6 +30,7 @@ typedef struct _Eina_Condition Eina_Condition; typedef struct _Eina_RWLock Eina_RWLock; typedef DWORD Eina_TLS; typedef HANDLE Eina_Semaphore; +typedef Eina_Lock Eina_Spinlock; #if _WIN32_WINNT >= 0x0600 struct _Eina_Condition @@ -551,6 +552,37 @@ eina_semaphore_release(Eina_Semaphore *sem, int count_release) return ReleaseSemaphore(*sem, count_release, NULL) ? EINA_TRUE : EINA_FALSE; } +// FIXME: Implement proper spinlock = http://www.codeproject.com/Articles/184046/Spin-Lock-in-C +static inline Eina_Bool +eina_spinlock_new(Eina_Spinlock *spinlock) +{ + return eina_lock_new(spinlock); +} + +static inline Eina_Lock_Result +eina_spinlock_take(Eina_Spinlock *spinlock) +{ + return eina_lock_take(spinlock); +} + +static inline Eina_Lock_Result +eina_spinlock_take_try(Eina_Spinlock *spinlock) +{ + return eina_lock_take_try(spinlock); +} + +static inline Eina_Lock_Result +eina_spinlock_release(Eina_Spinlock *spinlock) +{ + return eina_lock_release(spinlock); +} + +static inline void +eina_spinlock_free(Eina_Spinlock *spinlock) +{ + eina_lock_free(spinlock); +} + #include "eina_inline_lock_barrier.x" #endif diff --git a/src/lib/eina/eina_inline_lock_wince.x b/src/lib/eina/eina_inline_lock_wince.x index 787795977f..3b732568da 100644 --- a/src/lib/eina/eina_inline_lock_wince.x +++ b/src/lib/eina/eina_inline_lock_wince.x @@ -28,6 +28,7 @@ EAPI extern Eina_Bool _threads_activated; typedef HANDLE Eina_Lock; +typedef Eina_Lock Eina_Spinlock; typedef Eina_Lock Eina_RWLock; typedef DWORD Eina_TLS; typedef void * Eina_Semaphore; @@ -204,6 +205,36 @@ eina_semaphore_release(Eina_Semaphore *sem EINA_UNUSED, return EINA_FALSE; } +static inline Eina_Bool +eina_spinlock_new(Eina_Spinlock *spinlock) +{ + return eina_lock_new(spinlock); +} + +static inline void +eina_spinlock_free(Eina_Spinlock *spinlock) +{ + eina_lock_free(spinlock); +} + +static inline Eina_Lock_Result +eina_spinlock_take(Eina_Spinlock *spinlock) +{ + return eina_lock_take(spinlock); +} + +static inline Eina_Lock_Result +eina_spinlock_take_try(Eina_Spinlock *spinlock) +{ + return eina_lock_take_try(spinlock); +} + +static inline Eina_Lock_Result +eina_spinlock_release(Eina_Spinlock *spinlock) +{ + return eina_lock_release(spinlock); +} + #include "eina_inline_lock_barrier.x" #endif diff --git a/src/lib/eina/eina_lock.h b/src/lib/eina/eina_lock.h index ceb19d7b71..3e4a510252 100644 --- a/src/lib/eina/eina_lock.h +++ b/src/lib/eina/eina_lock.h @@ -113,6 +113,16 @@ static inline void eina_barrier_free(Eina_Barrier *barrier); /** @relates static Eina_Bool eina_barrier_wait(Eina_Barrier *barrier); @since 1.8 */ static inline Eina_Bool eina_barrier_wait(Eina_Barrier *barrier); +/** @relates static Eina_Bool eina_spinlock_new(Eina_Spinlock *spinlock); @since 1.8 */ +static inline Eina_Bool eina_spinlock_new(Eina_Spinlock *spinlock); +/** @relates static Eina_Lock_Result eina_spinlock_take(Eina_Spinlock *spinlock); @since 1.8 */ +static inline Eina_Lock_Result eina_spinlock_take(Eina_Spinlock *spinlock); +/** @relates static Eina_Lock_Result eina_spinlock_take(Eina_Spinlock *spinlock); @since 1.8 */ +static inline Eina_Lock_Result eina_spinlock_take_try(Eina_Spinlock *spinlock); +/** @relates static Eina_Lock_Result eina_spinlock_release(Eina_Spinlock *spinlock); @since 1.8 */ +static inline Eina_Lock_Result eina_spinlock_release(Eina_Spinlock *spinlock); +/** @relates static void eina_spinlock_free(Eina_Spinlock *spinlock); @since 1.8 */ +static inline void eina_spinlock_free(Eina_Spinlock *spinlock); #ifdef EINA_HAVE_DEBUG_THREADS # define EINA_MAIN_LOOP_CHECK_RETURN_VAL(val) \