diff --git a/legacy/eina/ChangeLog b/legacy/eina/ChangeLog index a1a8e21dfe..d36ad6eb9e 100644 --- a/legacy/eina/ChangeLog +++ b/legacy/eina/ChangeLog @@ -110,3 +110,7 @@ * Add eina_hash_free_cb_set to change the free callback during the life of an Eina_Hash. + +2011-06-23 Cedric Bail + + * Add Eina_LockRW. diff --git a/legacy/eina/src/include/eina_inline_lock_posix.x b/legacy/eina/src/include/eina_inline_lock_posix.x index c1026d436c..1c54fca6b3 100644 --- a/legacy/eina/src/include/eina_inline_lock_posix.x +++ b/legacy/eina/src/include/eina_inline_lock_posix.x @@ -40,6 +40,7 @@ typedef void (*Eina_Lock_Bt_Func) (); #endif typedef struct _Eina_Lock Eina_Lock; +typedef struct _Eina_RWLock Eina_RWLock; typedef struct _Eina_Condition Eina_Condition; struct _Eina_Lock @@ -62,6 +63,14 @@ struct _Eina_Condition pthread_cond_t condition; }; +struct _Eina_RWLock +{ + pthread_rwlock_t mutex; +#ifdef EINA_HAVE_DEBUG_THREADS + pthread_t lock_thread_wid; +#endif +}; + EAPI extern Eina_Bool _eina_threads_activated; #ifdef EINA_HAVE_DEBUG_THREADS @@ -353,5 +362,80 @@ eina_condition_signal(Eina_Condition *cond) return pthread_cond_signal(&(cond->condition)) == 0 ? EINA_TRUE : EINA_FALSE; } +static inline Eina_Bool +eina_rwlock_new(Eina_RWLock *mutex) +{ +#ifdef EINA_HAVE_DEBUG_THREADS + assert(pthread_equal(_eina_main_loop, pthread_self())); +#endif + + if (pthread_rwlock_init(&(mutex->mutex), NULL) != 0) + return EINA_FALSE; + return EINA_TRUE; +} + +static inline void +eina_rwlock_free(Eina_RWLock *mutex) +{ +#ifdef EINA_HAVE_DEBUG_THREADS + assert(pthread_equal(_eina_main_loop, pthread_self())); +#endif + + pthread_rwlock_destroy(&(mutex->mutex)); +} + +static inline Eina_Lock_Result +eina_rwlock_take_read(Eina_RWLock *mutex) +{ +#ifdef EINA_HAVE_ON_OFF_THREADS + if (!_eina_threads_activated) + { +#ifdef EINA_HAVE_DEBUG_THREADS + assert(pthread_equal(_eina_main_loop, pthread_self())); +#endif + return EINA_LOCK_SUCCEED; + } +#endif + + if (pthread_rwlock_rdlock(&(mutex->mutex)) != 0) + return EINA_LOCK_FAIL; + return EINA_LOCK_SUCCEED; +} + +static inline Eina_Lock_Result +eina_rwlock_take_write(Eina_RWLock *mutex) +{ +#ifdef EINA_HAVE_ON_OFF_THREADS + if (!_eina_threads_activated) + { +#ifdef EINA_HAVE_DEBUG_THREADS + assert(pthread_equal(_eina_main_loop, pthread_self())); +#endif + return EINA_LOCK_SUCCEED; + } +#endif + + if (pthread_rwlock_wrlock(&(mutex->mutex)) != 0) + return EINA_LOCK_FAIL; + return EINA_LOCK_SUCCEED; +} + +static inline Eina_Lock_Result +eina_rwlock_release(Eina_RWLock *mutex) +{ +#ifdef EINA_HAVE_ON_OFF_THREADS + if (!_eina_threads_activated) + { +#ifdef EINA_HAVE_DEBUG_THREADS + assert(pthread_equal(_eina_main_loop, pthread_self())); +#endif + return EINA_LOCK_SUCCEED; + } +#endif + + if (pthread_rwlock_unlock(&(mutex->mutex)) != 0) + return EINA_LOCK_FAIL; + return EINA_LOCK_SUCCEED; +} #endif diff --git a/legacy/eina/src/include/eina_inline_lock_void.x b/legacy/eina/src/include/eina_inline_lock_void.x index 6bcf15141d..2c849ac990 100644 --- a/legacy/eina/src/include/eina_inline_lock_void.x +++ b/legacy/eina/src/include/eina_inline_lock_void.x @@ -44,6 +44,7 @@ * Abtract type for a mutual exclusive object. */ typedef void *Eina_Lock; +typedef void *Eina_RWLock; typedef void *Eina_Condition; /** @@ -173,6 +174,35 @@ eina_condition_signal(Eina_Condition *cond EINA_UNUSED) return EINA_FALSE; } +static inline Eina_Bool +eina_rwlock_new(Eina_RWLock *mutex EINA_UNUSED) +{ + return EINA_FALSE; +} + +static inline void + eina_rwlock_free(Eina_RWLock *mutex EINA_UNUSED) +{ +} + +static inline Eina_Lock_Result +eina_rwlock_read_take(Eina_RWLock *mutex EINA_UNUSED) +{ + return EINA_LOCK_FAIL; +} + +static inline Eina_Lock_Result +eina_rwlock_write_take(Eina_RWLock *mutex EINA_UNUSED) +{ + return EINA_LOCK_FAIL; +} + +static inline Eina_Lock_Result +eina_rwlock_release(Eina_RWLock *mutex) +{ + return EINA_LOCK_FAIL; +} + /** * @} */ diff --git a/legacy/eina/src/include/eina_inline_lock_win32.x b/legacy/eina/src/include/eina_inline_lock_win32.x index d495b6f4a0..07dfbd4137 100644 --- a/legacy/eina/src/include/eina_inline_lock_win32.x +++ b/legacy/eina/src/include/eina_inline_lock_win32.x @@ -42,6 +42,19 @@ struct _Eina_Condition }; #endif +typedef struct _Eina_Win32_RWLock Eina_RWLock; + +struct _Eina_Win32_RWLock +{ + LONG readers_count; + LONG writers_count; + int readers; + int writers; + + Eina_Lock mutex; + Eina_Condition cond_read; + Eina_Condition cond_write; +}; EAPI extern Eina_Bool _eina_threads_activated; @@ -297,4 +310,116 @@ eina_condition_signal(Eina_Condition *cond) #endif } +static inline Eina_Bool +eina_rwlock_new(Eina_RWLock *mutex) +{ + if (!eina_lock_new(&(mutex->mutex))) return EINA_FALSE; + if (!eina_condition_new(&(mutex->cond_read), &(mutex->mutex))) + goto on_error1; + if (!eina_condition_new(&(mutex->cond_write), &(mutex->mutex))) + goto on_error2; + + return EINA_TRUE; + + on_error2: + eina_condition_free(&(mutex->cond_read)); + on_error1: + eina_lock_free(&(mutex->mutex)); + return EINA_FALSE; +} + +static inline void +eina_rwlock_free(Eina_RWLock *mutex) +{ + eina_condition_free(&(mutex->cond_read)); + eina_condition_free(&(mutex->cond_write)); + eina_lock_free(&(mutex->mutex)); +} + +static inline Eina_Lock_Result +eina_rwlock_take_read(Eina_RWLock *mutex) +{ + DWORD res; + + eina_lock_take(&(x->mutex)); + if (mutex->writers) + { + mutex->readers_count++; + while (mutex->writers) + { + EnterCriticalSection(&mutex->cond_write->waiters_count_lock); + mutex->cond_read->waiters_count++; + LeaveCriticalSection(&mutex->cond_write->waiters_count_lock); + res = WaitForSingleObject(mutex->cond_write->semaphore, INFINITE); + if (res != WAIT_OBJECT_0) break; + } + mutex->readers_count--; + } + if (res == 0) + mutex->readers++; + eina_lock_release(&(mutex->mutex)); +} + +static inline Eina_Lock_Result +eina_rwlock_take_write(Eina_RWLock *mutex) +{ + DWORD res; + + eina_lock_take(&(mutex->mutex)); + if (mutex->writers || mutex->readers > 0) + { + mutex->writers_count++; + while (mutex->writers || mutex->readers > 0) + { + EnterCriticalSection(&mutex->cond_write->waiters_count_lock); + mutex->cond_read->waiters_count++; + LeaveCriticalSection(&mutex->cond_write->waiters_count_lock); + res = WaitForSingleObject(mutex->cond_write->semaphore, INFINITE); + if (res != WAIT_OBJECT_0) break; + } + mutex->writers_count--; + } + if (res == 0) x->writers_count = 1; + eina_lock_release(&(mutex->mutex)); +} + +static inline Eina_Lock_Result +eina_rwlock_release(Eina_RWLock *mutex) +{ + eina_lock_take(&(mutex->mutex)); + + if (mutex->writers) + { + mutex->writers = 0; + if (mutex->readers_count == 1) + { + EnterCriticalSection(&mutex->cond_read->waiters_count_lock); + if (mutex->cond_read->waiters_count > 0) + ReleaseSemaphore(x->cond_read->semaphore, 1, 0); + LeaveCriticalSection(&mutex->cond_read->threads_count_lock); + } + else if (mutex->readers_count > 0) + eina_condition_broadast(&(mutex->cond_read)); + else if (mutex->writers_count > 0) + { + EnterCriticalSection (&mutex->cond_write->waiters_count_lock); + if (mutex->cond_write->waiters_count > 0) + ReleaseSemaphore(mutex->cond_write->semaphore, 1, 0); + LeaveCriticalSection (&mutex->cond_write->waiters_count_lock); + } + } + else if (mutex->readers > 0) + { + mutex->readers--; + if (mutex->readers == 0 && mutex->writers_count > 0) + { + EnterCriticalSection (&mutex->cond_write->waiters_count_lock); + if (mutex->cond_write->waiters_count > 0) + ReleaseSemaphore(mutex->cond_write->semaphore, 1, 0); + LeaveCriticalSection (&mutex->cond_write->waiters_count_lock); + } + } + eina_lock_release(&(mutex->mutex)); +} + #endif diff --git a/legacy/eina/src/include/eina_inline_lock_wince.x b/legacy/eina/src/include/eina_inline_lock_wince.x index 65145beab9..1be0890841 100644 --- a/legacy/eina/src/include/eina_inline_lock_wince.x +++ b/legacy/eina/src/include/eina_inline_lock_wince.x @@ -24,6 +24,7 @@ EAPI extern Eina_Bool _threads_activated; typedef HANDLE Eina_Lock; +typedef Eina_Lock Eina_RWLock; static inline Eina_Bool eina_lock_new(Eina_Lock *mutex) @@ -113,5 +114,34 @@ eina_condition_signal(Eina_Condition *cond) return EINA_FALSE; } +static inline Eina_Bool +eina_rwlock_new(Eina_RWLock *mutex) +{ + return eina_lock_new(mutex); +} + +static inline void +eina_rwlock_free(Eina_RWLock *mutex) +{ + return eina_lock_free(mutex); +} + +static inline Eina_Lock_Result +eina_rwlock_take_read(Eina_RWLock *mutex) +{ + return eina_lock_take(mutex); +} + +static inline Eina_Lock_Result +eina_rwlock_take_write(Eina_RWLock *mutex) +{ + return eina_lock_take(mutex); +} + +static inline Eina_Lock_Result +eina_rwlock_release(Eina_RWLock *mutex) +{ + return eina_lock_release(mutex); +} #endif diff --git a/legacy/eina/src/include/eina_lock.h b/legacy/eina/src/include/eina_lock.h index 2dbeaba6fe..21aa4314f4 100644 --- a/legacy/eina/src/include/eina_lock.h +++ b/legacy/eina/src/include/eina_lock.h @@ -67,6 +67,12 @@ static inline Eina_Bool eina_condition_timedwait(Eina_Condition *cond, double t) static inline Eina_Bool eina_condition_broadcast(Eina_Condition *cond); static inline Eina_Bool eina_condition_signal(Eina_Condition *cond); +static inline Eina_Bool eina_rwlock_new(Eina_RWLock *mutex); +static inline void eina_rwlock_free(Eina_RWLock *mutex); +static inline Eina_Lock_Result eina_rwlock_take_read(Eina_RWLock *mutex); +static inline Eina_Lock_Result eina_rwlock_take_write(Eina_RWLock *mutex); +static inline Eina_Lock_Result eina_rwlock_release(Eina_RWLock *mutex); + /** * @} */