Add atomic compare-and-swap
The atomic compare-and-swap can be used to implement lock-free structures. The planned use for this is to remove some of the locking done in the services when listeners are being manipulated.
This commit is contained in:
parent
18ca4189f0
commit
c7cffa0722
@ -102,4 +102,19 @@ static inline void atomic_synchronize()
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Atomic compare-and-swap of pointers
|
||||
*
|
||||
* @param variable Pointer to the variable
|
||||
* @param old_value Pointer to the expected value of @variable
|
||||
* @param new_value Stored value if @c variable is equal to @c old_value
|
||||
*
|
||||
* @return True if @c variable and @c old_value were equal
|
||||
*
|
||||
* @note If GCC __atomic builtins are available, the contents of @c variable are
|
||||
* written to @c old_value if the two are not equal. Do not rely on this behavior
|
||||
* and always do a separate read before attempting a compare-and-swap.
|
||||
*/
|
||||
bool atomic_cas_ptr(void **variable, void** old_value, void *new_value);
|
||||
|
||||
MXS_END_DECLS
|
||||
|
@ -124,3 +124,13 @@ void atomic_store_ptr(void **variable, void *value)
|
||||
(void)__sync_lock_test_and_set(variable, value);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool atomic_cas_ptr(void **variable, void** old_value, void *new_value)
|
||||
{
|
||||
#ifdef MXS_USE_ATOMIC_BUILTINS
|
||||
return __atomic_compare_exchange_n(variable, old_value, new_value,
|
||||
false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
|
||||
#else
|
||||
return __sync_val_compare_and_swap(variable, *old_value, new_value);
|
||||
#endif
|
||||
}
|
||||
|
@ -37,7 +37,6 @@ void test_add(void* data)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void test_load_store(void* data)
|
||||
{
|
||||
int id = (size_t)data;
|
||||
@ -51,6 +50,29 @@ void test_load_store(void* data)
|
||||
}
|
||||
}
|
||||
|
||||
static void* cas_dest = (void*)1;
|
||||
|
||||
void test_cas(void* data)
|
||||
{
|
||||
int id = (size_t)data;
|
||||
static int loops = 0;
|
||||
|
||||
while (atomic_load_int32(&running))
|
||||
{
|
||||
intptr_t my_value = (id + 1) % NTHR;
|
||||
intptr_t my_expected = id;
|
||||
|
||||
while (!atomic_cas_ptr(&cas_dest, (void**)&my_expected, (void*)&my_value))
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
loops++;
|
||||
}
|
||||
|
||||
ss_dassert(loops > 0);
|
||||
}
|
||||
|
||||
int run_test(void(*func)(void*))
|
||||
{
|
||||
THREAD threads[NTHR];
|
||||
@ -58,9 +80,9 @@ int run_test(void(*func)(void*))
|
||||
atomic_store_int32(&expected, 0);
|
||||
atomic_store_int32(&running, 1);
|
||||
|
||||
for (int i = 0; i < NTHR; i++)
|
||||
for (size_t i = 0; i < NTHR; i++)
|
||||
{
|
||||
if (thread_start(&threads[i], func, NULL) == NULL)
|
||||
if (thread_start(&threads[i], func, (void*)(i + 1)) == NULL)
|
||||
{
|
||||
ss_dassert(false);
|
||||
}
|
||||
@ -83,6 +105,7 @@ int main(int argc, char** argv)
|
||||
|
||||
run_test(test_load_store);
|
||||
run_test(test_add);
|
||||
run_test(test_cas);
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user