diff --git a/configure.ac b/configure.ac index 7df264afc1..1dd62ed51f 100644 --- a/configure.ac +++ b/configure.ac @@ -960,6 +960,7 @@ 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"]) +EINA_CONFIG([HAVE_OSX_SEMAPHORE], [test "x${have_darwin}" = "xyes"]) ### Modules diff --git a/src/lib/eina/eina_config.h.in b/src/lib/eina/eina_config.h.in index cdaf867a8a..af65f3b6b6 100644 --- a/src/lib/eina/eina_config.h.in +++ b/src/lib/eina/eina_config.h.in @@ -102,6 +102,11 @@ #endif @EINA_CONFIGURE_HAVE_OSX_SPINLOCK@ +#ifndef EINA_HAVE_OSX_SEMAPHORE +# undef EINA_HAVE_OSX_SEMAPHORE +#endif +@EINA_CONFIGURE_HAVE_OSX_SEMAPHORE@ + /* 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 172e5714ec..b73b849326 100644 --- a/src/lib/eina/eina_inline_lock_posix.x +++ b/src/lib/eina/eina_inline_lock_posix.x @@ -62,7 +62,7 @@ typedef struct _Eina_Lock Eina_Lock; typedef struct _Eina_RWLock Eina_RWLock; typedef struct _Eina_Condition Eina_Condition; typedef pthread_key_t Eina_TLS; -typedef sem_t Eina_Semaphore; + #if defined(EINA_HAVE_POSIX_SPINLOCK) typedef pthread_spinlock_t Eina_Spinlock; #elif defined(EINA_HAVE_OSX_SPINLOCK) @@ -71,6 +71,29 @@ typedef OSSpinLock Eina_Spinlock; typedef Eina_Lock Eina_Spinlock; #endif +#if defined(EINA_HAVE_OSX_SEMAPHORE) +/* OSX supports only named semaphores. + * So, we need to be able to generate a unique string identifier for each + * semaphore we want to create. + * It seems reasonable to use a counter, which is incremented each time a + * semaphore is created. However, it needs to be atomic... + * It would be easier if we were using C11 with stdatomic, but I guess it + * will just be fine without. + * That's why there are two static variables below the struct */ +struct _Eina_Semaphore +{ + sem_t *sema; + char name[16]; +}; +typedef struct _Eina_Semaphore Eina_Semaphore; + +static unsigned int _sem_ctr = 0; +static Eina_Spinlock _sem_ctr_lock = 0; // 0: not locked + +#else +typedef sem_t Eina_Semaphore; +#endif + /** @privatesection @{ */ struct _Eina_Lock { @@ -537,41 +560,6 @@ eina_tls_set(Eina_TLS key, const void *data) return EINA_TRUE; } -static inline Eina_Bool -eina_semaphore_new(Eina_Semaphore *sem, int count_init) -{ - if (!sem || (count_init <= 0)) - return EINA_FALSE; - - return (sem_init(sem, count_init, 1) == 0) ? EINA_TRUE : EINA_FALSE; -} - -static inline Eina_Bool -eina_semaphore_free(Eina_Semaphore *sem) -{ - if (!sem) - return EINA_FALSE; - - return (sem_destroy(sem) == 0) ? EINA_TRUE : EINA_FALSE; -} - -static inline Eina_Bool -eina_semaphore_lock(Eina_Semaphore *sem) -{ - if (!sem) - return EINA_FALSE; - - return (sem_wait(sem) == 0) ? EINA_TRUE : EINA_FALSE; -} - -static inline Eina_Bool -eina_semaphore_release(Eina_Semaphore *sem, int count_release EINA_UNUSED) -{ - if (!sem) - return EINA_FALSE; - - return (sem_post(sem) == 0) ? EINA_TRUE : EINA_FALSE; -} #ifdef EINA_HAVE_PTHREAD_BARRIER typedef struct _Eina_Barrier Eina_Barrier; @@ -694,6 +682,66 @@ eina_spinlock_free(Eina_Spinlock *spinlock) #endif } +static inline Eina_Bool +eina_semaphore_new(Eina_Semaphore *sem, int count_init) +{ + if (!sem || (count_init <= 0)) + return EINA_FALSE; + +#if defined(EINA_HAVE_OSX_SEMAPHORE) + /* Atomic increment to generate the unique identifier */ + eina_spinlock_take(&_sem_ctr_lock); + ++_sem_ctr; + eina_spinlock_release(&_sem_ctr_lock); + + snprintf(sem->name, sizeof(sem->name), "/eina_sem_%u", _sem_ctr); + sem->sema = sem_open(sem->name, O_CREAT, 0644, 1); + return (sem->sema == SEM_FAILED) ? EINA_FALSE : EINA_TRUE; +#else + return (sem_init(sem, count_init, 1) == 0) ? EINA_TRUE : EINA_FALSE; +#endif +} + +static inline Eina_Bool +eina_semaphore_free(Eina_Semaphore *sem) +{ + if (!sem) + return EINA_FALSE; + +#if defined(EINA_HAVE_OSX_SEMAPHORE) + return ((sem_close(sem->sema) == 0) && + (sem_unlink(sem->name)) == 0) ? EINA_TRUE : EINA_FALSE; +#else + return (sem_destroy(sem) == 0) ? EINA_TRUE : EINA_FALSE; +#endif +} + +static inline Eina_Bool +eina_semaphore_lock(Eina_Semaphore *sem) +{ + if (!sem) + return EINA_FALSE; + +#if defined(EINA_HAVE_OSX_SEMAPHORE) + return (sem_wait(sem->sema) == 0) ? EINA_TRUE : EINA_FALSE; +#else + return (sem_wait(sem) == 0) ? EINA_TRUE : EINA_FALSE; +#endif +} + +static inline Eina_Bool +eina_semaphore_release(Eina_Semaphore *sem, int count_release EINA_UNUSED) +{ + if (!sem) + return EINA_FALSE; + +#if defined(EINA_HAVE_OSX_SEMAPHORE) + return (sem_post(sem->sema) == 0) ? EINA_TRUE : EINA_FALSE; +#else + return (sem_post(sem) == 0) ? EINA_TRUE : EINA_FALSE; +#endif +} + #undef _XOPEN_SOURCE // This is necessary to let third party still define this macro #ifdef EINA_XOPEN_SOURCE