forked from enlightenment/efl
array threadsafing wip, get rid of dumb undefineds from earlier
SVN revision: 50959
This commit is contained in:
parent
10a14f3994
commit
cbf7f7b58a
|
@ -29,6 +29,11 @@
|
|||
#include "eina_accessor.h"
|
||||
#include "eina_magic.h"
|
||||
|
||||
#ifdef EINA_RWLOCKS_ENABLED
|
||||
# include <pthread.h>
|
||||
# include <errno.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @addtogroup Eina_Data_Types_Group Data Types
|
||||
*
|
||||
|
@ -71,12 +76,15 @@ struct _Eina_Array
|
|||
unsigned int step; /**< How much must we grow the vector when it is full */
|
||||
#ifdef EINA_RWLOCKS_ENABLED
|
||||
pthread_rwlock_t lock;
|
||||
int lockcount;
|
||||
Eina_Bool threadsafe:1;
|
||||
#endif
|
||||
|
||||
EINA_MAGIC
|
||||
};
|
||||
|
||||
EAPI Eina_Array * eina_array_new(unsigned int step) EINA_WARN_UNUSED_RESULT EINA_MALLOC EINA_WARN_UNUSED_RESULT;
|
||||
EAPI Eina_Array * eina_array_threadsafe_new(unsigned int step) EINA_WARN_UNUSED_RESULT EINA_MALLOC EINA_WARN_UNUSED_RESULT;
|
||||
EAPI void eina_array_free(Eina_Array *array) EINA_ARG_NONNULL(1);
|
||||
EAPI void eina_array_step_set(Eina_Array *array, unsigned int step) EINA_ARG_NONNULL(1);
|
||||
EAPI void eina_array_clean(Eina_Array *array) EINA_ARG_NONNULL(1);
|
||||
|
@ -85,12 +93,76 @@ 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(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);
|
||||
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);
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
#ifdef EINA_RWLOCKS_ENABLED
|
||||
static inline Eina_Bool
|
||||
eina_array_rdlock(Eina_Array *array)
|
||||
{
|
||||
if (!array) return EINA_FALSE;
|
||||
if (array->threadsafe)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = pthread_rwlock_rdlock(&array->lock);
|
||||
if ((ret != 0) && (ret != EDEADLK))
|
||||
return EINA_FALSE;
|
||||
array->lockcount++;
|
||||
}
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
static inline Eina_Bool
|
||||
eina_array_wrlock(Eina_Array *array)
|
||||
{
|
||||
if (!array) return EINA_FALSE;
|
||||
if (array->threadsafe)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = pthread_rwlock_wrlock(&array->lock);
|
||||
if ((ret != 0) && (ret != EDEADLK))
|
||||
return EINA_FALSE;
|
||||
array->lockcount++;
|
||||
}
|
||||
return EINA_TRUE;
|
||||
}
|
||||
static inline Eina_Bool
|
||||
eina_array_unlock(Eina_Array *array)
|
||||
{
|
||||
if (!array) return EINA_FALSE;
|
||||
if ((array->threadsafe) && (!(--array->lockcount)))
|
||||
if (pthread_rwlock_unlock(&array->lock))
|
||||
return EINA_FALSE;
|
||||
return EINA_TRUE;
|
||||
}
|
||||
#else
|
||||
static inline Eina_Bool
|
||||
eina_array_rdlock(Eina_Array *array)
|
||||
{
|
||||
if (!array) return EINA_FALSE;
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
static inline Eina_Bool
|
||||
eina_array_wrlock(Eina_Array *array)
|
||||
{
|
||||
if (!array) return EINA_FALSE;
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
static inline Eina_Bool
|
||||
eina_array_unlock(Eina_Array *array)
|
||||
{
|
||||
if (!array) return EINA_FALSE;
|
||||
return EINA_TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def EINA_ARRAY_ITER_NEXT
|
||||
|
@ -129,7 +201,6 @@ EAPI Eina_Accessor * eina_array_accessor_new(Eina_Array *array) EINA_
|
|||
(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.
|
||||
|
@ -170,28 +241,18 @@ EAPI Eina_Accessor * eina_array_accessor_new(Eina_Array *array) EINA_
|
|||
* @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)
|
||||
do \
|
||||
{ \
|
||||
if (eina_array_wrlock((Eina_Array*)array)) \
|
||||
{ \
|
||||
for (index = 0, iterator = (array)->data; \
|
||||
(index < (array)->count) && ((item = *((iterator)++))); \
|
||||
++(index)) \
|
||||
code \
|
||||
eina_array_unlock((Eina_Array*)array); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#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_ESCAPE
|
||||
|
@ -200,7 +261,7 @@ EAPI Eina_Accessor * eina_array_accessor_new(Eina_Array *array) EINA_
|
|||
* @param array The array being iterated over.
|
||||
* @param esc The code to "escape" the loop with
|
||||
*
|
||||
* This macro should be used any time the user wishes to leave break the loop
|
||||
* This macro should be used any time the user wishes to leave the loop
|
||||
* while using EINA_ARRAY_THREADSAFE_ITER_NEXT. It will unlock any mutexes
|
||||
* which may have been locked while iterating. Failure to use this will likely
|
||||
* result in a deadlock.
|
||||
|
@ -230,18 +291,11 @@ EAPI Eina_Accessor * eina_array_accessor_new(Eina_Array *array) EINA_
|
|||
#define EINA_ARRAY_THREADSAFE_ITER_ESCAPE(array, esc...) \
|
||||
do \
|
||||
{ \
|
||||
if (_eina_array_threadsafety) \
|
||||
pthread_rwlock_unlock(&(array)->lock); \
|
||||
eina_array_unlock((Eina_Array*)array); \
|
||||
esc \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#else
|
||||
|
||||
#define EINA_ARRAY_THREADSAFE_ITER_ESCAPE(array, esc...) \
|
||||
esc
|
||||
#endif
|
||||
|
||||
#include "eina_inline_array.x"
|
||||
|
||||
/**
|
||||
|
|
|
@ -169,7 +169,7 @@ struct _Eina_Iterator_Array
|
|||
{
|
||||
Eina_Iterator iterator;
|
||||
|
||||
Eina_Array *array;
|
||||
const Eina_Array *array;
|
||||
unsigned int index;
|
||||
|
||||
EINA_MAGIC
|
||||
|
@ -179,7 +179,7 @@ typedef struct _Eina_Accessor_Array Eina_Accessor_Array;
|
|||
struct _Eina_Accessor_Array
|
||||
{
|
||||
Eina_Accessor accessor;
|
||||
Eina_Array *array;
|
||||
const Eina_Array *array;
|
||||
EINA_MAGIC
|
||||
};
|
||||
|
||||
|
@ -275,9 +275,10 @@ eina_array_grow(Eina_Array *array)
|
|||
void **tmp;
|
||||
unsigned int total;
|
||||
|
||||
EINA_MAGIC_CHECK_ARRAY(array);
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(array, EINA_FALSE);
|
||||
|
||||
EINA_MAGIC_CHECK_ARRAY(array);
|
||||
|
||||
total = array->total + array->step;
|
||||
eina_error_set(0);
|
||||
tmp = realloc(array->data, sizeof (void *) * total);
|
||||
|
@ -351,36 +352,6 @@ 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 *
|
||||
*============================================================================*/
|
||||
|
@ -456,15 +427,63 @@ 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);
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a new array that is threadsafe.
|
||||
*
|
||||
* @param step The count of pointers to add when increasing the array size.
|
||||
* @return @c NULL on failure, non @c NULL otherwise.
|
||||
*
|
||||
* This function creates a new array which is different than a normal array.
|
||||
* Arrays created with this function will automatically mutex themselves in eina_array_*
|
||||
* function calls. In order to ensure that the created array operates successfully
|
||||
* in a threadsafe environment, only EINA_ARRAY_THREADSAFE_* macros can be used with
|
||||
* this type of list.
|
||||
* When adding an element, the array allocates @p step elements. When that buffer is
|
||||
* full, then adding another element will increase the buffer of @p step elements again.
|
||||
*
|
||||
* This function return a valid array on success, or @c NULL if memory
|
||||
* allocation fails. In that case, the error is set to
|
||||
* #EINA_ERROR_OUT_OF_MEMORY.
|
||||
*/
|
||||
EAPI Eina_Array *
|
||||
eina_array_threadsafe_new(__UNUSED__ unsigned int step)
|
||||
{
|
||||
#ifdef EFL_HAVE_POSIX_THREADS_RWLOCK
|
||||
Eina_Array *array;
|
||||
|
||||
eina_error_set(0);
|
||||
array = malloc(sizeof (Eina_Array));
|
||||
if (!array)
|
||||
{
|
||||
eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EINA_MAGIC_SET(array, EINA_MAGIC_ARRAY);
|
||||
|
||||
array->data = NULL;
|
||||
array->total = 0;
|
||||
array->count = 0;
|
||||
array->step = step;
|
||||
|
||||
pthread_rwlock_init(&array->lock, NULL);
|
||||
array->threadsafe = EINA_TRUE;
|
||||
|
||||
|
||||
DBG("array=%p", array);
|
||||
|
||||
return array;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Free an array.
|
||||
*
|
||||
|
@ -479,17 +498,15 @@ 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);
|
||||
if (!eina_array_wrlock(array))
|
||||
return;
|
||||
EINA_MAGIC_CHECK_ARRAY(array);
|
||||
DBG("array=%p", array);
|
||||
#ifdef EFL_HAVE_POSIX_THREADS_RWLOCK
|
||||
if (_eina_array_threadsafety)
|
||||
if (array->threadsafe)
|
||||
pthread_rwlock_destroy(&array->lock);
|
||||
#endif
|
||||
MAGIC_FREE(array);
|
||||
|
@ -509,20 +526,15 @@ 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
|
||||
if (!eina_array_wrlock(array))
|
||||
return;
|
||||
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
|
||||
eina_array_unlock(array);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -538,17 +550,12 @@ EAPI void
|
|||
eina_array_clean(Eina_Array *array)
|
||||
{
|
||||
EINA_SAFETY_ON_NULL_RETURN(array);
|
||||
if (!eina_array_wrlock(array))
|
||||
return;
|
||||
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
|
||||
eina_array_unlock(array);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -565,11 +572,9 @@ EAPI void
|
|||
eina_array_flush(Eina_Array *array)
|
||||
{
|
||||
EINA_SAFETY_ON_NULL_RETURN(array);
|
||||
if (!eina_array_wrlock(array))
|
||||
return;
|
||||
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;
|
||||
|
@ -579,10 +584,7 @@ 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
|
||||
eina_array_unlock(array);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -619,11 +621,10 @@ eina_array_remove(Eina_Array *array, Eina_Bool (*keep)(void *data,
|
|||
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(array, EINA_FALSE);
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(keep, EINA_FALSE);
|
||||
if (!eina_array_wrlock(array))
|
||||
return 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)
|
||||
|
@ -698,10 +699,7 @@ 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
|
||||
eina_array_unlock(array);
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
|
@ -718,7 +716,7 @@ 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(Eina_Array *array)
|
||||
eina_array_iterator_new(const Eina_Array *array)
|
||||
{
|
||||
Eina_Iterator_Array *it;
|
||||
|
||||
|
@ -736,10 +734,6 @@ eina_array_iterator_new(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);
|
||||
|
@ -748,10 +742,7 @@ eina_array_iterator_new(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;
|
||||
}
|
||||
|
||||
|
@ -768,7 +759,7 @@ eina_array_iterator_new(Eina_Array *array)
|
|||
* set. Otherwise, a valid accessor is returned.
|
||||
*/
|
||||
EAPI Eina_Accessor *
|
||||
eina_array_accessor_new(Eina_Array *array)
|
||||
eina_array_accessor_new(const Eina_Array *array)
|
||||
{
|
||||
Eina_Accessor_Array *it;
|
||||
|
||||
|
@ -786,10 +777,6 @@ eina_array_accessor_new(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);
|
||||
|
@ -798,10 +785,7 @@ eina_array_accessor_new(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;
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ START_TEST(eina_array_simple)
|
|||
|
||||
eina_init();
|
||||
|
||||
ea = eina_array_new(11);
|
||||
ea = eina_array_threadsafe_new(11);
|
||||
fail_if(!ea);
|
||||
|
||||
for (i = 0; i < 201; ++i)
|
||||
|
@ -132,7 +132,7 @@ START_TEST(eina_array_remove_stuff)
|
|||
|
||||
eina_init();
|
||||
|
||||
ea = eina_array_new(64);
|
||||
ea = eina_array_threadsafe_new(64);
|
||||
fail_if(!ea);
|
||||
|
||||
for (i = 0; i < 1000; ++i)
|
||||
|
|
Loading…
Reference in New Issue