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:
Markus Mäkelä 2017-05-07 11:00:48 +03:00
parent 18ca4189f0
commit c7cffa0722
3 changed files with 51 additions and 3 deletions

View File

@ -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

View File

@ -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
}

View File

@ -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;
}