implement threadsafety for arrays, alter all eina internal array usage to (hopefully...
authordiscomfitor <discomfitor@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Tue, 10 Aug 2010 03:26:15 +0000 (03:26 +0000)
committerdiscomfitor <discomfitor@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Tue, 10 Aug 2010 03:26:15 +0000 (03:26 +0000)
call eina_threads_init() to enable this if you have pthread rwlock support (posix 2001)
note some function prototypes have lost const on array params to allow locking
WARNING: you should NOT call eina_threads_shutdown unless you are positive that you will not use any arrays which were created while threadsafe mode were enabled, and vice versa.  Failing to adhere to this warning WILL result in either deadlocks or memory leaks.

git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/eina@50951 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

14 files changed:
src/include/eina_array.h
src/include/eina_inline_array.x
src/include/eina_module.h
src/include/eina_private.h
src/lib/eina_array.c
src/lib/eina_benchmark.c
src/lib/eina_main.c
src/lib/eina_module.c
src/lib/eina_rbtree.c
src/tests/eina_bench_array.c
src/tests/eina_bench_hash.c
src/tests/eina_test_array.c
src/tests/eina_test_benchmark.c
src/tests/eina_test_rbtree.c

index 8d66d9e..d640779 100644 (file)
@@ -66,9 +66,12 @@ typedef void **Eina_Array_Iterator;
 struct _Eina_Array
 {
    void **data; /**< Pointer to a vector of pointer to payload */
-   unsigned int total; /**< Total number of slot in the vector */
-   unsigned int count; /**< Number of activ slot in the vector */
+   unsigned int total; /**< Total number of slots in the vector */
+   unsigned int count; /**< Number of active slots in the vector */
    unsigned int step; /**< How much must we grow the vector when it is full */
+#ifdef EINA_RWLOCKS_ENABLED
+   pthread_rwlock_t lock;
+#endif
 
    EINA_MAGIC
 };
@@ -82,12 +85,12 @@ EAPI Eina_Bool                  eina_array_remove(Eina_Array *array, Eina_Bool(*
 
 static inline Eina_Bool         eina_array_push(Eina_Array *array, const void *data) EINA_ARG_NONNULL(1, 2);
 static inline void *            eina_array_pop(Eina_Array *array) EINA_ARG_NONNULL(1);
-static inline void *            eina_array_data_get(const Eina_Array *array, unsigned int idx) EINA_ARG_NONNULL(1);
-static inline void              eina_array_data_set(const Eina_Array *array, unsigned int idx, const void *data) EINA_ARG_NONNULL(1, 3);
-static inline unsigned int      eina_array_count_get(const Eina_Array *array) EINA_ARG_NONNULL(1);
+static inline void *            eina_array_data_get(Eina_Array *array, unsigned int idx) EINA_ARG_NONNULL(1);
+static inline void              eina_array_data_set(Eina_Array *array, unsigned int idx, const void *data) EINA_ARG_NONNULL(1, 3);
+static inline unsigned int      eina_array_count_get(Eina_Array *array) EINA_ARG_NONNULL(1);
 
-EAPI Eina_Iterator *            eina_array_iterator_new(const Eina_Array *array) EINA_MALLOC EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
-EAPI Eina_Accessor *            eina_array_accessor_new(const Eina_Array *array) EINA_MALLOC EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Iterator *            eina_array_iterator_new(Eina_Array *array) EINA_MALLOC EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Accessor *            eina_array_accessor_new(Eina_Array *array) EINA_MALLOC EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
 
 /**
  * @def EINA_ARRAY_ITER_NEXT
@@ -98,9 +101,9 @@ EAPI Eina_Accessor *            eina_array_accessor_new(const Eina_Array *array)
  * @param item The data
  * @param iterator The iterator
  *
- * This macro allow the iteration over @p array in an easy way. It
+ * This macro allows the iteration over @p array in an easy way. It
  * iterates from the first element to the last one. @p index is an
- * integer that increase from 0 to the number of elements. @p item is
+ * integer that increases from 0 to the number of elements. @p item is
  * the data of each element of @p array, so it is a pointer to a type
  * chosen by the user. @p iterator is of type #Eina_Array_Iterator.
  *
@@ -126,6 +129,120 @@ EAPI Eina_Accessor *            eina_array_accessor_new(const Eina_Array *array)
         (index < eina_array_count_get(array)) && ((item = *((iterator)++))); \
                                                    ++(index))
 
+#ifdef EINA_RWLOCKS_ENABLED
+/**
+ * @def EINA_ARRAY_THREADSAFE_ITER_NEXT
+ * @brief Macro to iterate over an array easily while mutexing.
+ *
+ * @param array The array to iterate over.
+ * @param index The integer number that is increased while itareting.
+ * @param item The data
+ * @param iterator The iterator
+ * @param code The code in the iterator loop
+ *
+ * This macro allows the iteration over @p array in an easy way. It
+ * iterates from the first element to the last one. @p index is an
+ * integer that increases from 0 to the number of elements. @p item is
+ * the data of each element of @p array, so it is a pointer to a type
+ * chosen by the user. @p iterator is of type #Eina_Array_Iterator.
+ * @p code is the entire chunk of code which will be in the iterator loop,
+ * terminated by a semicolon.
+ *
+ * This macro can be used for safely freeing the data of an array in a thread,
+ * like in the following example:
+ *
+ * @code
+ * Eina_Array         *array;
+ * char               *item;
+ * Eina_Array_Iterator iterator;
+ * unsigned int        i;
+ *
+ * // array is already filled,
+ * // its elements are just duplicated strings,
+ * // EINA_ARRAY_ITER_NEXT will be used to free those strings
+ *
+ * EINA_ARRAY_THREADSAFE_ITER_NEXT(array, i, item, iterator,
+ *   {
+ *      if (item)
+ *        free(item);
+ *   }
+ * );
+ * @endcode
+ */
+#define EINA_ARRAY_THREADSAFE_ITER_NEXT(array, index, item, iterator, code...)   \
+   if (_eina_array_threadsafety)    \
+     pthread_rwlock_wrlock(&(array)->lock); \
+   for (index = 0, iterator = (array)->data; \
+        (index < (array)->count) && ((item = *((iterator)++))); \
+                                                   ++(index)) \
+        code \
+   if (_eina_array_threadsafety)    \
+     pthread_rwlock_unlock(&(array)->lock)
+
+#else
+#define EINA_ARRAY_THREADSAFE_ITER_NEXT(array, index, item, iterator, code...)   \
+  do \
+    { \
+       for (index = 0, iterator = (array)->data; \
+            (index < (array)->count) && ((item = *((iterator)++))); \
+                                                       ++(index)) \
+            code \
+    } \
+  while (0)
+#endif
+
+#ifdef EINA_RWLOCKS_ENABLED
+
+/**
+ * @def EINA_ARRAY_THREADSAFE_ITER_RETURN
+ * @brief Macro to perform a return while using EINA_ARRAY_THREADSAFE_ITER_NEXT
+ *
+ * @param array The array being iterated over.
+ * @param retval The value to be returned
+ *
+ * This macro should be used any time the user wishes to perform a return
+ * statement while using EINA_ARRAY_THREADSAFE_ITER_RETURN to unlock any mutexes
+ * which may have been locked while iterating.  Failure to use this will likely
+ * result in a deadlock.
+ *
+ * example:
+ *
+ * @code
+ * Eina_Array         *array;
+ * char               *item;
+ * Eina_Array_Iterator iterator;
+ * unsigned int        i;
+ *
+ * // array is already filled,
+ * // its elements are just duplicated strings,
+ * // EINA_ARRAY_ITER_NEXT will be used to free those strings
+ *
+ * EINA_ARRAY_THREADSAFE_ITER_NEXT(array, i, item, iterator,
+ *   {
+ *      if (item)
+ *        free(item);
+ *      else
+ *        EINA_ARRAY_THREADSAFE_ITER_RETURN(array, NULL);
+  *   }
+ * );
+ * @endcode
+ */
+#define EINA_ARRAY_THREADSAFE_ITER_RETURN(array, retval) \
+do \
+  { \
+     if (_eina_array_threadsafety)    \
+       pthread_rwlock_unlock(&(array)->lock); \
+     return (retval); \
+  } \
+while (0)
+
+#else
+
+#define EINA_ARRAY_THREADSAFE_ITER_RETURN(array, retval) \
+     return (retval)
+
+#endif
+
 #include "eina_inline_array.x"
 
 /**
index 400da23..75e499f 100644 (file)
 #ifndef EINA_INLINE_ARRAY_X_
 #define EINA_INLINE_ARRAY_X_
 
+#ifdef EINA_RWLOCKS_ENABLED
+# include <pthread.h>
+#endif
 
+extern Eina_Bool _eina_array_threadsafety;
 /**
  * @cond LOCAL
  */
@@ -57,10 +61,30 @@ eina_array_push(Eina_Array *array, const void *data)
 {
    if (!data) return EINA_FALSE;
 
+#ifdef EINA_RWLOCKS_ENABLED
+   if (_eina_array_threadsafety)
+     pthread_rwlock_wrlock(&array->lock);
+#endif
+
    if (EINA_UNLIKELY((array->count + 1) > array->total))
-     if (!eina_array_grow(array)) return EINA_FALSE;
+     if (!eina_array_grow(array))
+       {
+
+#ifdef EINA_RWLOCKS_ENABLED
+          if (_eina_array_threadsafety)
+            pthread_rwlock_unlock(&array->lock);
+#endif
+
+          return EINA_FALSE;
+       }
 
    array->data[array->count++] = (void*) data;
+
+#ifdef EINA_RWLOCKS_ENABLED
+   if (_eina_array_threadsafety)
+     pthread_rwlock_unlock(&array->lock);
+#endif
+
    return EINA_TRUE;
 }
 
@@ -79,8 +103,31 @@ eina_array_push(Eina_Array *array, const void *data)
 static inline void *
 eina_array_pop(Eina_Array *array)
 {
-   if (array->count <= 0) return NULL;
-   return array->data[--array->count];
+   void *ret = NULL;
+   
+#ifdef EINA_RWLOCKS_ENABLED
+   if (_eina_array_threadsafety)
+     pthread_rwlock_wrlock(&array->lock);
+#endif
+
+   if (array->count <= 0)
+     {
+      
+#ifdef EINA_RWLOCKS_ENABLED
+   if (_eina_array_threadsafety)
+     pthread_rwlock_unlock(&array->lock);
+#endif
+
+        return NULL;
+     }
+   ret = array->data[--array->count];
+   
+#ifdef EINA_RWLOCKS_ENABLED
+   if (_eina_array_threadsafety)
+     pthread_rwlock_unlock(&array->lock);
+#endif
+
+   return ret;
 }
 
 /**
@@ -95,26 +142,50 @@ eina_array_pop(Eina_Array *array)
  * idx. If it is @c NULL or invalid, the program may crash.
  */
 static inline void *
-eina_array_data_get(const Eina_Array *array, unsigned int idx)
+eina_array_data_get(Eina_Array *array, unsigned int idx)
 {
-   return array->data[idx];
+   void *ret = NULL;
+
+#ifdef EINA_RWLOCKS_ENABLED
+   if (_eina_array_threadsafety)
+     pthread_rwlock_rdlock(&array->lock);
+#endif
+
+   ret = array->data[idx];
+
+#ifdef EINA_RWLOCKS_ENABLED
+   if (_eina_array_threadsafety)
+     pthread_rwlock_unlock(&array->lock);
+#endif
+
+   return ret;
 }
 
 /**
- * @brief Return the data at a given position in an array.
+ * @brief Set the data at a given position in an array.
  *
  * @param array The array.
  * @param idx The potition of the data to set.
  * @param data The data to set.
  *
- * This function returns the data at the position @p idx in @p
+ * This function sets the data at the position @p idx in @p
  * array. For performance reasons, there is no check of @p array or @p
  * idx. If it is @c NULL or invalid, the program may crash.
  */
 static inline void
-eina_array_data_set(const Eina_Array *array, unsigned int idx, const void *data)
+eina_array_data_set(Eina_Array *array, unsigned int idx, const void *data)
 {
+#ifdef EINA_RWLOCKS_ENABLED
+   if (_eina_array_threadsafety)
+     pthread_rwlock_wrlock(&array->lock);
+#endif
+
    array->data[idx] = (void*) data;
+
+#ifdef EINA_RWLOCKS_ENABLED
+   if (_eina_array_threadsafety)
+     pthread_rwlock_unlock(&array->lock);
+#endif
 }
 
 /**
@@ -128,9 +199,19 @@ eina_array_data_set(const Eina_Array *array, unsigned int idx, const void *data)
  * @c NULL or invalid, the program may crash.
  */
 static inline unsigned int
-eina_array_count_get(const Eina_Array *array)
+eina_array_count_get(Eina_Array *array)
 {
+#ifdef EINA_RWLOCKS_ENABLED
+   if (_eina_array_threadsafety)
+     pthread_rwlock_rdlock(&array->lock);
+#endif
+
    return array->count;
+
+#ifdef EINA_RWLOCKS_ENABLED
+   if (_eina_array_threadsafety)
+     pthread_rwlock_unlock(&array->lock);
+#endif
 }
 
 /**
index c5e25bd..113fb69 100644 (file)
@@ -164,7 +164,7 @@ eina_module_list_unload(Eina_Array *list) EINA_ARG_NONNULL(1);
 EAPI void
 eina_module_list_free(Eina_Array *list) EINA_ARG_NONNULL(1);
 EAPI Eina_Module *
-eina_module_find(const Eina_Array *array, const char *module) EINA_ARG_NONNULL(
+eina_module_find(Eina_Array *array, const char *module) EINA_ARG_NONNULL(
    1,
    2);
 
index 7e8074b..f952be9 100644 (file)
@@ -129,6 +129,10 @@ void eina_share_common_threads_init(void);
 void eina_share_common_threads_shutdown(void);
 void eina_log_threads_init(void);
 void eina_log_threads_shutdown(void);
+#ifdef EINA_RWLOCKS_ENABLE
+void eina_array_threadsafety_init(void);
+void eina_array_threadsafety_shutdown(void);
+#endif
 #endif
 
 #endif /* EINA_PRIVATE_H_ */
index 9d66a6f..ef26a71 100644 (file)
 #include <string.h>
 #include <stdio.h>
 
+#ifdef EFL_HAVE_POSIX_THREADS_RWLOCK
+# include <pthread.h>
+#endif
+
 #include "eina_config.h"
 #include "eina_private.h"
 #include "eina_error.h"
@@ -165,7 +169,7 @@ struct _Eina_Iterator_Array
 {
    Eina_Iterator iterator;
 
-   const Eina_Array *array;
+   Eina_Array *array;
    unsigned int index;
 
    EINA_MAGIC
@@ -175,12 +179,16 @@ typedef struct _Eina_Accessor_Array Eina_Accessor_Array;
 struct _Eina_Accessor_Array
 {
    Eina_Accessor accessor;
-   const Eina_Array *array;
+   Eina_Array *array;
    EINA_MAGIC
 };
 
 static int _eina_array_log_dom = -1;
 
+#ifdef EFL_HAVE_POSIX_THREADS_RWLOCK
+Eina_Bool _eina_array_threadsafety = EINA_FALSE;
+#endif
+
 #ifdef ERR
 #undef ERR
 #endif
@@ -191,20 +199,16 @@ static int _eina_array_log_dom = -1;
 #endif
 #define DBG(...) EINA_LOG_DOM_DBG(_eina_array_log_dom, __VA_ARGS__)
 
-static void        eina_array_iterator_free(Eina_Iterator_Array *it)
-EINA_ARG_NONNULL(1);
-static Eina_Array *eina_array_iterator_get_container(Eina_Iterator_Array *it)
-EINA_ARG_NONNULL(1);
+static void        eina_array_iterator_free(Eina_Iterator_Array *it) EINA_ARG_NONNULL(1);
+static Eina_Array *eina_array_iterator_get_container(Eina_Iterator_Array *it) EINA_ARG_NONNULL(1);
 static Eina_Bool   eina_array_iterator_next(Eina_Iterator_Array *it,
                                             void **data) EINA_ARG_NONNULL(1);
 
 static Eina_Bool   eina_array_accessor_get_at(Eina_Accessor_Array *it,
                                               unsigned int idx,
                                               void **data) EINA_ARG_NONNULL(1);
-static Eina_Array *eina_array_accessor_get_container(Eina_Accessor_Array *it)
-EINA_ARG_NONNULL(1);
-static void        eina_array_accessor_free(Eina_Accessor_Array *it)
-EINA_ARG_NONNULL(1);
+static Eina_Array *eina_array_accessor_get_container(Eina_Accessor_Array *it) EINA_ARG_NONNULL(1);
+static void        eina_array_accessor_free(Eina_Accessor_Array *it) EINA_ARG_NONNULL(1);
 
 static Eina_Bool
 eina_array_iterator_next(Eina_Iterator_Array *it, void **data)
@@ -347,6 +351,36 @@ eina_array_shutdown(void)
    return EINA_TRUE;
 }
 
+#ifdef EFL_HAVE_POSIX_THREADS_RWLOCK
+/**
+ * @brief Enable threadsafe mode in arrays
+ *
+ * This function enables threadsafe mode in all arrays.
+ *
+ * @warning Once enabled, this CANNOT be disabled.
+ */
+
+void
+eina_array_threadsafety_init(void)
+{
+   _eina_array_threadsafety = EINA_TRUE;
+}
+
+/**
+ * @brief Disable threadsafe mode in arrays
+ *
+ * This function disables threadsafe mode in all arrays.
+ */
+
+void
+eina_array_threadsafety_shutdown(void)
+{
+   _eina_array_threadsafety = EINA_TRUE;
+}
+
+#endif
+
+
 /*============================================================================*
 *                                   API                                      *
 *============================================================================*/
@@ -422,6 +456,9 @@ eina_array_new(unsigned int step)
    array->total = 0;
    array->count = 0;
    array->step = step;
+#ifdef EFL_HAVE_POSIX_THREADS_RWLOCK
+   pthread_rwlock_init(&array->lock, NULL);
+#endif
 
    DBG("array=%p", array);
 
@@ -434,7 +471,7 @@ eina_array_new(unsigned int step)
  * @param array The array to free.
  *
  * This function frees @p array. It calls first eina_array_flush() then
- * free the memory of the pointeur. It does not free the memory
+ * free the memory of the pointer. It does not free the memory
  * allocated for the elements of @p array. To free them, use
  * #EINA_ARRAY_ITER_NEXT. For performance reasons, there is no check
  * of @p array.
@@ -442,11 +479,19 @@ eina_array_new(unsigned int step)
 EAPI void
 eina_array_free(Eina_Array *array)
 {
+#ifdef EFL_HAVE_POSIX_THREADS_RWLOCK
+   if (_eina_array_threadsafety)
+     pthread_rwlock_wrlock(&array->lock);
+#endif
    eina_array_flush(array);
 
    EINA_MAGIC_CHECK_ARRAY(array);
    EINA_SAFETY_ON_NULL_RETURN(array);
    DBG("array=%p", array);
+#ifdef EFL_HAVE_POSIX_THREADS_RWLOCK
+   if (_eina_array_threadsafety)
+     pthread_rwlock_destroy(&array->lock);
+#endif
    MAGIC_FREE(array);
 }
 
@@ -464,12 +509,20 @@ EAPI void
 eina_array_step_set(Eina_Array *array, unsigned int step)
 {
    EINA_SAFETY_ON_NULL_RETURN(array);
+#ifdef EFL_HAVE_POSIX_THREADS_RWLOCK
+   if (_eina_array_threadsafety)
+     pthread_rwlock_wrlock(&array->lock);
+#endif
    array->data = NULL;
    array->total = 0;
    array->count = 0;
    array->step = step;
    EINA_MAGIC_SET(array, EINA_MAGIC_ARRAY);
    DBG("array=%p, step=%u", array, step);
+#ifdef EFL_HAVE_POSIX_THREADS_RWLOCK
+   if (_eina_array_threadsafety)
+     pthread_rwlock_unlock(&array->lock);
+#endif
 }
 
 /**
@@ -484,10 +537,18 @@ eina_array_step_set(Eina_Array *array, unsigned int step)
 EAPI void
 eina_array_clean(Eina_Array *array)
 {
-   EINA_MAGIC_CHECK_ARRAY(array);
    EINA_SAFETY_ON_NULL_RETURN(array);
+   EINA_MAGIC_CHECK_ARRAY(array);
+#ifdef EFL_HAVE_POSIX_THREADS_RWLOCK
+   if (_eina_array_threadsafety)
+     pthread_rwlock_wrlock(&array->lock);
+#endif
    array->count = 0;
    DBG("array=%p", array);
+#ifdef EFL_HAVE_POSIX_THREADS_RWLOCK
+   if (_eina_array_threadsafety)
+     pthread_rwlock_unlock(&array->lock);
+#endif
 }
 
 /**
@@ -503,8 +564,12 @@ eina_array_clean(Eina_Array *array)
 EAPI void
 eina_array_flush(Eina_Array *array)
 {
-   EINA_MAGIC_CHECK_ARRAY(array);
    EINA_SAFETY_ON_NULL_RETURN(array);
+   EINA_MAGIC_CHECK_ARRAY(array);
+#ifdef EFL_HAVE_POSIX_THREADS_RWLOCK
+   if (_eina_array_threadsafety)
+     pthread_rwlock_wrlock(&array->lock);
+#endif
    DBG("array=%p", array);
    array->count = 0;
    array->total = 0;
@@ -514,6 +579,10 @@ eina_array_flush(Eina_Array *array)
 
    free(array->data);
    array->data = NULL;
+#ifdef EFL_HAVE_POSIX_THREADS_RWLOCK
+   if (_eina_array_threadsafety)
+     pthread_rwlock_unlock(&array->lock);
+#endif
 }
 
 /**
@@ -548,10 +617,13 @@ eina_array_remove(Eina_Array *array, Eina_Bool (*keep)(void *data,
    unsigned int limit;
    unsigned int i;
 
-   EINA_MAGIC_CHECK_ARRAY(array);
    EINA_SAFETY_ON_NULL_RETURN_VAL(array, EINA_FALSE);
    EINA_SAFETY_ON_NULL_RETURN_VAL(keep,  EINA_FALSE);
-
+   EINA_MAGIC_CHECK_ARRAY(array);
+#ifdef EFL_HAVE_POSIX_THREADS_RWLOCK
+   if (_eina_array_threadsafety)
+     pthread_rwlock_wrlock(&array->lock);
+#endif
    DBG("array=%p, keep=%p, gdata=%p", array, keep, gdata);
 
    if (array->total == 0)
@@ -626,7 +698,10 @@ eina_array_remove(Eina_Array *array, Eina_Bool (*keep)(void *data,
 
    array->data = tmp;
    array->count = total;
-
+#ifdef EFL_HAVE_POSIX_THREADS_RWLOCK
+   if (_eina_array_threadsafety)
+     pthread_rwlock_unlock(&array->lock);
+#endif
    return EINA_TRUE;
 }
 
@@ -643,12 +718,12 @@ eina_array_remove(Eina_Array *array, Eina_Bool (*keep)(void *data,
  * set. Otherwise, a valid iterator is returned.
  */
 EAPI Eina_Iterator *
-eina_array_iterator_new(const Eina_Array *array)
+eina_array_iterator_new(Eina_Array *array)
 {
    Eina_Iterator_Array *it;
 
-   EINA_MAGIC_CHECK_ARRAY(array);
    EINA_SAFETY_ON_NULL_RETURN_VAL(array, NULL);
+   EINA_MAGIC_CHECK_ARRAY(array);
 
         eina_error_set(0);
    it = calloc(1, sizeof (Eina_Iterator_Array));
@@ -661,6 +736,10 @@ eina_array_iterator_new(const Eina_Array *array)
    EINA_MAGIC_SET(it,            EINA_MAGIC_ARRAY_ITERATOR);
    EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
 
+#ifdef EFL_HAVE_POSIX_THREADS_RWLOCK
+   if (_eina_array_threadsafety)
+     pthread_rwlock_rdlock(&array->lock);
+#endif
    it->array = array;
 
    it->iterator.next = FUNC_ITERATOR_NEXT(eina_array_iterator_next);
@@ -669,7 +748,10 @@ eina_array_iterator_new(const Eina_Array *array)
    it->iterator.free = FUNC_ITERATOR_FREE(eina_array_iterator_free);
 
    DBG("array=%p, iterator=%p", array, it);
-
+#ifdef EFL_HAVE_POSIX_THREADS_RWLOCK
+   if (_eina_array_threadsafety)
+     pthread_rwlock_unlock(&array->lock);
+#endif
    return &it->iterator;
 }
 
@@ -686,12 +768,12 @@ eina_array_iterator_new(const Eina_Array *array)
  * set. Otherwise, a valid accessor is returned.
  */
 EAPI Eina_Accessor *
-eina_array_accessor_new(const Eina_Array *array)
+eina_array_accessor_new(Eina_Array *array)
 {
    Eina_Accessor_Array *it;
 
-   EINA_MAGIC_CHECK_ARRAY(array);
    EINA_SAFETY_ON_NULL_RETURN_VAL(array, NULL);
+   EINA_MAGIC_CHECK_ARRAY(array);
 
         eina_error_set(0);
    it = calloc(1, sizeof (Eina_Accessor_Array));
@@ -704,6 +786,10 @@ eina_array_accessor_new(const Eina_Array *array)
    EINA_MAGIC_SET(it,            EINA_MAGIC_ARRAY_ACCESSOR);
    EINA_MAGIC_SET(&it->accessor, EINA_MAGIC_ACCESSOR);
 
+#ifdef EFL_HAVE_POSIX_THREADS_RWLOCK
+   if (_eina_array_threadsafety)
+     pthread_rwlock_rdlock(&array->lock);
+#endif
    it->array = array;
 
    it->accessor.get_at = FUNC_ACCESSOR_GET_AT(eina_array_accessor_get_at);
@@ -712,7 +798,10 @@ eina_array_accessor_new(const Eina_Array *array)
    it->accessor.free = FUNC_ACCESSOR_FREE(eina_array_accessor_free);
 
    DBG("array=%p, accessor=%p", array, it);
-
+#ifdef EFL_HAVE_POSIX_THREADS_RWLOCK
+   if (_eina_array_threadsafety)
+     pthread_rwlock_unlock(&array->lock);
+#endif
    return &it->accessor;
 }
 
index 522719b..47ecd44 100644 (file)
@@ -518,8 +518,9 @@ eina_benchmark_free(Eina_Benchmark *bench)
       char *tmp;
       unsigned int i;
 
-      EINA_ARRAY_ITER_NEXT(names, i, tmp, it)
-      free(tmp);
+      EINA_ARRAY_THREADSAFE_ITER_NEXT(names, i, tmp, it,
+        free(tmp);
+      );
 
       eina_array_free(names);
    }
index 9cb13f7..8c53fc6 100644 (file)
@@ -311,6 +311,9 @@ eina_threads_init(void)
 
    eina_share_common_threads_init();
    eina_log_threads_init();
+#ifdef EFL_RWLOCKS_ENABLE
+   eina_array_threadsafety_init();
+#endif
    _threads_activated = EINA_TRUE;
 
    return ret;
@@ -349,6 +352,9 @@ eina_threads_shutdown(void)
 
    eina_share_common_threads_shutdown();
    eina_log_threads_shutdown();
+#ifdef EFL_RWLOCKS_ENABLE
+   eina_array_threadsafety_shutdown();
+#endif
 
    _threads_activated = EINA_FALSE;
 
index c570d17..75c86e7 100644 (file)
@@ -623,32 +623,33 @@ EAPI Eina_Array *eina_module_list_get(Eina_Array *array,
  * If the element is found return the module else NULL.
  */
 EAPI Eina_Module *
-eina_module_find(const Eina_Array *array, const char *module)
+eina_module_find(Eina_Array *array, const char *module)
 {
    unsigned int i;
    Eina_Array_Iterator iterator;
    Eina_Module *m;
 
-   EINA_ARRAY_ITER_NEXT(array, i, m, iterator)
-   {
-      char *file_m;
-      char *tmp;
-      ssize_t len;
-
-      /* basename() can modify its argument, so we first get a copie */
-      /* do not use strdupa, as opensolaris does not have it */
-      len = strlen(eina_module_file_get(m));
-      tmp = alloca(len + 1);
-      memcpy(tmp, eina_module_file_get(m), len + 1);
-      file_m = basename(tmp);
-      len = strlen(file_m);
-      len -= sizeof(SHARED_LIB_SUFFIX) - 1;
-      if (len <= 0)
-         continue;
-
-      if (!strncmp(module, file_m, len))
-         return m;
-   }
+   EINA_ARRAY_THREADSAFE_ITER_NEXT(array, i, m, iterator,
+     {
+        char *file_m;
+        char *tmp;
+        ssize_t len;
+
+        /* basename() can modify its argument, so we first get a copie */
+        /* do not use strdupa, as opensolaris does not have it */
+        len = strlen(eina_module_file_get(m));
+        tmp = alloca(len + 1);
+        memcpy(tmp, eina_module_file_get(m), len + 1);
+        file_m = basename(tmp);
+        len = strlen(file_m);
+        len -= sizeof(SHARED_LIB_SUFFIX) - 1;
+        if (len <= 0)
+           continue;
+
+        if (!strncmp(module, file_m, len))
+           EINA_ARRAY_THREADSAFE_ITER_RETURN(array, m);
+     }
+   );
 
    return NULL;
 }
@@ -665,8 +666,9 @@ EAPI void eina_module_list_load(Eina_Array *array)
 
    EINA_SAFETY_ON_NULL_RETURN(array);
    DBG("array %p, count %u", array, array->count);
-   EINA_ARRAY_ITER_NEXT(array, i, m, iterator)
-   eina_module_load(m);
+   EINA_ARRAY_THREADSAFE_ITER_NEXT(array, i, m, iterator,
+     eina_module_load(m);
+   );
 }
 
 /**
@@ -681,8 +683,9 @@ EAPI void eina_module_list_unload(Eina_Array *array)
 
    EINA_SAFETY_ON_NULL_RETURN(array);
    DBG("array %p, count %u", array, array->count);
-   EINA_ARRAY_ITER_NEXT(array, i, m, iterator)
-   eina_module_unload(m);
+   EINA_ARRAY_THREADSAFE_ITER_NEXT(array, i, m, iterator,
+     eina_module_unload(m);
+   );
 }
 
 /**
@@ -697,8 +700,9 @@ EAPI void eina_module_list_free(Eina_Array *array)
 
    EINA_SAFETY_ON_NULL_RETURN(array);
    DBG("array %p, count %u", array, array->count);
-   EINA_ARRAY_ITER_NEXT(array, i, m, iterator)
-   eina_module_free(m);
+   EINA_ARRAY_THREADSAFE_ITER_NEXT(array, i, m, iterator,
+     eina_module_free(m);
+   );
 
    eina_array_flush(array);
 }
index 88a471c..be0d977 100644 (file)
@@ -96,8 +96,9 @@ _eina_rbtree_iterator_free(Eina_Iterator_Rbtree *it)
    Eina_Array_Iterator et;
    unsigned int i;
 
-   EINA_ARRAY_ITER_NEXT(it->stack, i, item, et)
-   free(item);
+   EINA_ARRAY_THREADSAFE_ITER_NEXT(it->stack, i, item, et,
+     free(item);
+   );
 
    eina_array_free(it->stack);
                      free(it);
index cf6b805..50d1b04 100644 (file)
@@ -88,20 +88,23 @@ eina_bench_array_4evas_render_inline(int request)
 
         if (i == 500)
           {
-             EINA_ARRAY_ITER_NEXT(array, j, ebo, it)
-             free(ebo);
+             EINA_ARRAY_THREADSAFE_ITER_NEXT(array, j, ebo, it,
+               free(ebo);
+             );
 
              eina_array_clean(array);
           }
         else if (i % 30 == 0)
            eina_array_remove(array, keep, NULL);
 
-        EINA_ARRAY_ITER_NEXT(array, j, ebo, it)
-        ebo->keep = rand() < (RAND_MAX / 2) ? ebo->keep : EINA_FALSE;
+        EINA_ARRAY_THREADSAFE_ITER_NEXT(array, j, ebo, it,
+          ebo->keep = rand() < (RAND_MAX / 2) ? ebo->keep : EINA_FALSE;
+        );
      }
 
-        EINA_ARRAY_ITER_NEXT(array, j, ebo, it)
-        free(ebo);
+        EINA_ARRAY_THREADSAFE_ITER_NEXT(array, j, ebo, it,
+          free(ebo);
+        );
 
    eina_array_free(array);
 
index 93bb69e..a615a15 100644 (file)
@@ -344,8 +344,9 @@ eina_bench_lookup_evas(int request)
 
    evas_hash_free(hash);
 
-   EINA_ARRAY_ITER_NEXT(array, i, tmp_val, it)
-   free(tmp_val);
+   EINA_ARRAY_THREADSAFE_ITER_NEXT(array, i, tmp_val, it,
+     free(tmp_val);
+   );
 
    eina_array_free(array);
 }
index 2b90261..c5d118d 100644 (file)
@@ -53,11 +53,12 @@ START_TEST(eina_array_simple)
    fail_if(atoi(tmp) != 200);
    free(tmp);
 
-   EINA_ARRAY_ITER_NEXT(ea, i, tmp, it)
-   {
-      fail_if((unsigned int)atoi(tmp) != i);
-      free(tmp);
-   }
+   EINA_ARRAY_THREADSAFE_ITER_NEXT(ea, i, tmp, it,
+     {
+        fail_if((unsigned int)atoi(tmp) != i);
+        free(tmp);
+     }
+   );
 
    fail_if(i != 200);
 
@@ -92,11 +93,12 @@ START_TEST(eina_array_static)
    fail_if(eina_array_data_get(&sea, 10) == NULL);
    fail_if(atoi(eina_array_data_get(&sea, 10)) != 10);
 
-   EINA_ARRAY_ITER_NEXT(&sea, i, tmp, it)
-   {
-      fail_if((unsigned int)atoi(tmp) != i);
-      free(tmp);
-   }
+   EINA_ARRAY_THREADSAFE_ITER_NEXT(&sea, i, tmp, it,
+     {
+        fail_if((unsigned int)atoi(tmp) != i);
+        free(tmp);
+     }
+   );
 
    fail_if(i != 200);
 
@@ -152,8 +154,9 @@ START_TEST(eina_array_remove_stuff)
         fail_if(eina_array_remove(ea, keep_int, NULL) != EINA_TRUE);
 
         fail_if(eina_array_count_get(ea) != 990);
-        EINA_ARRAY_ITER_NEXT(ea, i, tmp, it)
-        fail_if(*tmp == 0);
+        EINA_ARRAY_THREADSAFE_ITER_NEXT(ea, i, tmp, it,
+          fail_if(*tmp == 0);
+        );
 
    // Remove the last items
    for (i = 980; i < 990; ++i)
@@ -166,11 +169,12 @@ START_TEST(eina_array_remove_stuff)
 
    // Remove all items
    fail_if(eina_array_count_get(ea) != 980);
-   EINA_ARRAY_ITER_NEXT(ea, i, tmp, it)
-   {
-      fail_if(*tmp == 0);
-      *tmp = 0;
-   }
+   EINA_ARRAY_THREADSAFE_ITER_NEXT(ea, i, tmp, it,
+     {
+        fail_if(*tmp == 0);
+        *tmp = 0;
+     }
+   );
 
    eina_array_remove(ea, keep_int, NULL);
 
index 04362c2..213bc7c 100644 (file)
@@ -57,11 +57,12 @@ START_TEST(eina_benchmark_simple)
    ea = eina_benchmark_run(eb);
    fail_if(!ea);
 
-   EINA_ARRAY_ITER_NEXT(ea, i, tmp, it)
-   {
-      fail_if(!tmp);
-      fail_if(unlink(tmp));
-   }
+   EINA_ARRAY_THREADSAFE_ITER_NEXT(ea, i, tmp, it,
+     {
+        fail_if(!tmp);
+        fail_if(unlink(tmp));
+     }
+   );
 
       fail_if(global_test != 499500);
 
index ad3f63e..dcf00fb 100644 (file)
@@ -214,17 +214,18 @@ START_TEST(eina_rbtree_remove)
    _eina_rbtree_black_height(&root->node,
                              EINA_RBTREE_CMP_NODE_CB(eina_rbtree_int_cmp));
 
-   EINA_ARRAY_ITER_NEXT(ea, i, item, it)
-   {
-      root = (Eina_Rbtree_Int *)eina_rbtree_inline_remove(
-            &root->node,
-            &item->node,
-            EINA_RBTREE_CMP_NODE_CB(
-               eina_rbtree_int_cmp),
-            NULL);
-      _eina_rbtree_black_height(&root->node,
-                                EINA_RBTREE_CMP_NODE_CB(eina_rbtree_int_cmp));
-   }
+   EINA_ARRAY_THREADSAFE_ITER_NEXT(ea, i, item, it,
+     {
+        root = (Eina_Rbtree_Int *)eina_rbtree_inline_remove(
+              &root->node,
+              &item->node,
+              EINA_RBTREE_CMP_NODE_CB(
+                 eina_rbtree_int_cmp),
+              NULL);
+        _eina_rbtree_black_height(&root->node,
+                                  EINA_RBTREE_CMP_NODE_CB(eina_rbtree_int_cmp));
+     }
+   );
 
    fail_if(root != NULL);