446 lines
13 KiB
C
446 lines
13 KiB
C
#include "easy_atomic.h"
|
|
#include <pthread.h>
|
|
#include <easy_test.h>
|
|
|
|
/**
|
|
* 测试 easy_atomic.h
|
|
*/
|
|
#define TEST_ATOMIC_ADD32(v1, init_value, add_value) \
|
|
{v1 = (init_value); \
|
|
easy_atomic32_add(&v1, (add_value)); \
|
|
EXPECT_EQ(v1, (int32_t)((int64_t)(init_value) + (add_value))); \
|
|
v1 = (init_value); \
|
|
typeof(v1) vv = easy_atomic32_add_return(&v1, add_value);\
|
|
EXPECT_EQ(vv, (int32_t)((int64_t)(init_value) + (add_value))); \
|
|
EXPECT_EQ(v1, (int32_t)((int64_t)(init_value) + (add_value)));}
|
|
|
|
#define TEST_ATOMIC_ADD(v2, init_value, add_value) \
|
|
{v2 = (easy_atomic_t)(init_value); \
|
|
int64_t cv = v2 + (easy_atomic_t)add_value; \
|
|
easy_atomic_add(&v2, (easy_atomic_t)(add_value)); \
|
|
EXPECT_EQ(v2, cv); \
|
|
v2 = (easy_atomic_t)(init_value); \
|
|
EXPECT_EQ(easy_atomic_add_return(&v2, (easy_atomic_t)add_value), cv); \
|
|
EXPECT_EQ(v2, cv);}
|
|
|
|
#define TEST_ATOMIC_CMP_SET(v3, init_value, set_value) \
|
|
v3 = (easy_atomic_t)(init_value); \
|
|
if (init_value != set_value) EXPECT_EQ(easy_atomic_cmp_set(&v3, set_value, init_value), 0); \
|
|
EXPECT_EQ(easy_atomic_cmp_set(&v3, init_value, set_value), 1); \
|
|
EXPECT_EQ(v3, (easy_atomic_t)(set_value));
|
|
|
|
#define TEST_ATOMIC_INC(i, v3, start, end) \
|
|
for (v3 = i = (start); i < (end);) { \
|
|
easy_atomic_inc(&v3); \
|
|
i ++; \
|
|
EXPECT_EQ(v3, i); }
|
|
|
|
#define TEST_ATOMIC_DEC(i, v3, start, end) \
|
|
for (v3 = i = (start); i > (end);) { \
|
|
easy_atomic_dec(&v3); \
|
|
i --; \
|
|
EXPECT_EQ(v3, i); }
|
|
|
|
#define TEST_ATOMIC_INC32(i, v4, start, end) \
|
|
for (v4 = i = (start); i < (end);) { \
|
|
easy_atomic32_inc(&v4); \
|
|
i ++; \
|
|
EXPECT_EQ(v4, i); }
|
|
|
|
#define TEST_ATOMIC_DEC32(i, v3, start, end) \
|
|
for (v3 = i = (start); i > (end);) { \
|
|
easy_atomic32_dec(&v3); \
|
|
i --; \
|
|
EXPECT_EQ(v3, i); }
|
|
|
|
#define INT32_MAX_VALUE 0x7fffffff
|
|
#define INT32_MIN_VALUE 0x80000000
|
|
#if __WORDSIZE == 64
|
|
#define INT64_MAX_VALUE 0x7fffffffffffffff
|
|
#define INT64_MIN_VALUE 0x8000000000000000
|
|
#else
|
|
#define INT64_MAX_VALUE INT32_MAX_VALUE
|
|
#define INT64_MIN_VALUE INT32_MIN_VALUE
|
|
#endif
|
|
|
|
TEST(easy_atomic, func)
|
|
{
|
|
easy_atomic32_t v1 = 0;
|
|
easy_atomic_t v2 = 0;
|
|
|
|
easy_atomic32_add(&v1, 1);
|
|
EXPECT_EQ(v1, 1);
|
|
easy_atomic32_add(&v1, 10);
|
|
EXPECT_EQ(v1, 11);
|
|
EXPECT_EQ(easy_atomic32_add_return(&v1, 100), 111);
|
|
EXPECT_EQ(v1, 111);
|
|
|
|
TEST_ATOMIC_ADD32(v1, INT32_MAX_VALUE, INT32_MIN_VALUE); // 2147483647 + -2147483648 = -1
|
|
TEST_ATOMIC_ADD32(v1, INT32_MAX_VALUE, INT32_MAX_VALUE); // 2147483647 + 2147483647 = -2
|
|
TEST_ATOMIC_ADD32(v1, 0x0, INT32_MIN_VALUE); // 0 + -2147483648 = -2147483648
|
|
TEST_ATOMIC_ADD32(v1, 0x0, INT32_MAX_VALUE); // 0 + 2147483647 = 2147483647
|
|
TEST_ATOMIC_ADD32(v1, INT32_MIN_VALUE, INT32_MIN_VALUE); // -2147483648 + -2147483648 = 0
|
|
TEST_ATOMIC_ADD32(v1, INT32_MIN_VALUE, INT32_MAX_VALUE); // -2147483648 + 2147483647 = -1
|
|
|
|
easy_atomic_add(&v2, 1);
|
|
EXPECT_EQ(v2, 1);
|
|
easy_atomic_add(&v2, 10);
|
|
EXPECT_EQ(v2, 11);
|
|
EXPECT_EQ(easy_atomic_add_return(&v2, 100), 111);
|
|
EXPECT_EQ(v2, 111);
|
|
|
|
EXPECT_EQ(easy_atomic_cmp_set(&v2, 110, 1), 0);
|
|
EXPECT_EQ(v2, 111);
|
|
EXPECT_EQ(easy_atomic_cmp_set(&v2, 111, 1), 1);
|
|
EXPECT_EQ(v2, 1);
|
|
|
|
TEST_ATOMIC_ADD(v2, INT64_MAX_VALUE, INT64_MIN_VALUE);
|
|
//TEST_ATOMIC_ADD(v2, INT64_MAX_VALUE, INT64_MAX_VALUE);
|
|
TEST_ATOMIC_ADD(v2, 0x0, INT64_MIN_VALUE);
|
|
TEST_ATOMIC_ADD(v2, 0x0, INT64_MAX_VALUE);
|
|
TEST_ATOMIC_ADD(v2, INT64_MIN_VALUE, INT64_MIN_VALUE);
|
|
TEST_ATOMIC_ADD(v2, INT64_MIN_VALUE, INT64_MAX_VALUE);
|
|
|
|
TEST_ATOMIC_CMP_SET(v2, INT64_MAX_VALUE, INT64_MIN_VALUE);
|
|
TEST_ATOMIC_CMP_SET(v2, INT64_MAX_VALUE, INT64_MAX_VALUE);
|
|
TEST_ATOMIC_CMP_SET(v2, 0x0, INT64_MIN_VALUE);
|
|
TEST_ATOMIC_CMP_SET(v2, 0x0, INT64_MAX_VALUE);
|
|
TEST_ATOMIC_CMP_SET(v2, INT64_MIN_VALUE, INT64_MIN_VALUE);
|
|
TEST_ATOMIC_CMP_SET(v2, INT64_MIN_VALUE, INT64_MAX_VALUE);
|
|
|
|
EXPECT_EQ(easy_trylock(&v2), 0);
|
|
easy_unlock(&v2);
|
|
EXPECT_EQ(v2, 0);
|
|
|
|
EXPECT_EQ(easy_trylock(&v2), 1);
|
|
EXPECT_EQ(v2, 1);
|
|
easy_unlock(&v2);
|
|
EXPECT_EQ(v2, 0);
|
|
|
|
easy_spin_lock(&v2);
|
|
EXPECT_EQ(v2, 1);
|
|
EXPECT_EQ(easy_trylock(&v2), 0);
|
|
easy_unlock(&v2);
|
|
EXPECT_EQ(v2, 0);
|
|
|
|
// 64 bit, atomic inc and dec
|
|
int64_t i = 0;
|
|
easy_atomic_t v3 = 0;
|
|
TEST_ATOMIC_INC(i, v3, -1000, 1000);
|
|
TEST_ATOMIC_DEC(i, v3, 1000, -1000);
|
|
easy_atomic_t v3_t = INT64_MAX_VALUE;
|
|
easy_atomic_add_return(&v3_t, 1000);
|
|
TEST_ATOMIC_INC(i, v3, INT64_MAX_VALUE - 1000, v3_t);
|
|
TEST_ATOMIC_DEC(i, v3, v3_t, INT64_MAX_VALUE - 1000);
|
|
|
|
// 32 bit, atomic inc and dec
|
|
easy_atomic32_t v4 = 0;
|
|
TEST_ATOMIC_INC32(i, v4, -1000, 1000);
|
|
TEST_ATOMIC_DEC32(i, v4, 1000, -1000);
|
|
easy_atomic32_t v4_t = INT32_MAX_VALUE;
|
|
easy_atomic32_add_return(&v4_t, 1000);
|
|
TEST_ATOMIC_INC32(i, v4, INT32_MAX_VALUE - 1000, v4_t);
|
|
TEST_ATOMIC_DEC32(i, v4, v4_t, INT32_MAX_VALUE - 1000);
|
|
}
|
|
|
|
typedef struct easy_atomic_mt_args_t {
|
|
easy_atomic_t lock;
|
|
int64_t loop_count;
|
|
easy_atomic_t v1;
|
|
int64_t v2;
|
|
int64_t sleep_value;
|
|
} easy_atomic_mt_args_t;
|
|
|
|
void *easy_atomic_mthread_start(void *args)
|
|
{
|
|
int i;
|
|
easy_atomic_mt_args_t *p = (easy_atomic_mt_args_t *)args;
|
|
|
|
for(i = 0; i < p->loop_count; i++) {
|
|
easy_atomic_add(&p->v1, 1);
|
|
}
|
|
|
|
volatile int t;
|
|
|
|
for(i = 0; i < p->loop_count; i++) {
|
|
easy_spin_lock(&p->lock);
|
|
t = p->v2;
|
|
p->v2 = t + 1;
|
|
easy_spin_unlock(&p->lock);
|
|
}
|
|
|
|
struct timespec req;
|
|
|
|
struct timespec rem;
|
|
|
|
req.tv_sec = 0;
|
|
|
|
req.tv_nsec = 1000000;
|
|
|
|
{
|
|
easy_spin_lock(&p->lock);
|
|
t = p->sleep_value;
|
|
EXPECT_EQ(nanosleep(&req, &rem), 0);
|
|
p->sleep_value = t + 1;
|
|
easy_spin_unlock(&p->lock);
|
|
}
|
|
|
|
return (void *)NULL;
|
|
}
|
|
|
|
TEST(easy_atomic, mthread)
|
|
{
|
|
const int thread_count = 10;
|
|
pthread_t tids[thread_count];
|
|
int i;
|
|
easy_atomic_mt_args_t param;
|
|
param.lock = 0;
|
|
param.loop_count = 50000;
|
|
param.v1 = 0;
|
|
param.v2 = 0;
|
|
param.sleep_value = 0;
|
|
|
|
for(i = 0; i < thread_count; i++) {
|
|
pthread_create(&tids[i], NULL, easy_atomic_mthread_start, ¶m);
|
|
}
|
|
|
|
for(i = 0; i < thread_count; i++) {
|
|
pthread_join(tids[i], NULL);
|
|
}
|
|
|
|
EXPECT_EQ(param.v1, param.loop_count * thread_count);
|
|
EXPECT_EQ(param.v2, param.loop_count * thread_count);
|
|
EXPECT_EQ(param.sleep_value, thread_count);
|
|
}
|
|
|
|
void *easy_atomic_mthread_trylock_start(void *args)
|
|
{
|
|
int i;
|
|
easy_atomic_mt_args_t *p = (easy_atomic_mt_args_t *)args;
|
|
|
|
volatile int t;
|
|
|
|
for(i = 0; i < p->loop_count;) {
|
|
if (easy_trylock(&p->lock)) {
|
|
t = p->v2;
|
|
p->v2 = t + 1;
|
|
easy_unlock(&p->lock);
|
|
i ++;
|
|
}
|
|
}
|
|
|
|
/*
|
|
struct timespec req;
|
|
|
|
struct timespec rem;
|
|
|
|
req.tv_sec = 0;
|
|
|
|
req.tv_nsec = 1000000;
|
|
*/
|
|
|
|
while(1) {
|
|
if (easy_trylock(&p->lock) == 0)
|
|
continue;
|
|
|
|
int t = p->v1;
|
|
//EXPECT_EQ(nanosleep(&req, &rem), 0);
|
|
p->v1 = t + 1;
|
|
break;
|
|
}
|
|
|
|
easy_unlock(&p->lock);
|
|
|
|
return (void *)NULL;
|
|
}
|
|
|
|
TEST(easy_atomic, mthread_trylock)
|
|
{
|
|
const int thread_count = 10;
|
|
pthread_t tids[thread_count];
|
|
int i;
|
|
easy_atomic_mt_args_t param;
|
|
param.lock = 0;
|
|
param.loop_count = 10000;
|
|
param.v1 = 0;
|
|
param.v2 = 0;
|
|
|
|
for(i = 0; i < thread_count; i++) {
|
|
pthread_create(&tids[i], NULL, easy_atomic_mthread_trylock_start, ¶m);
|
|
}
|
|
|
|
for(i = 0; i < thread_count; i++) {
|
|
pthread_join(tids[i], NULL);
|
|
}
|
|
|
|
EXPECT_EQ(param.v1, thread_count);
|
|
EXPECT_EQ(param.v2, param.loop_count * thread_count);
|
|
}
|
|
|
|
typedef struct easy_atomic_mt_op_args_t {
|
|
easy_atomic_t int64_add;
|
|
easy_atomic_t int64_add_return;
|
|
easy_atomic_t int64_inc;
|
|
easy_atomic_t int64_dec;
|
|
easy_atomic_t int64_set;
|
|
easy_atomic_t int64_set_sum;
|
|
easy_atomic_t int64_sum;
|
|
easy_atomic32_t int32_add;
|
|
easy_atomic32_t int32_add_return;
|
|
easy_atomic32_t int32_inc;
|
|
easy_atomic32_t int32_dec;
|
|
easy_atomic32_t int32_sum;
|
|
int64_t loop_count;
|
|
} easy_atomic_mt_op_args_t;
|
|
|
|
void *easy_atomic_mthread_op_start(void *args)
|
|
{
|
|
easy_atomic_mt_op_args_t *p = (easy_atomic_mt_op_args_t *)args;
|
|
int i;
|
|
|
|
for(i = 0; i < p->loop_count; i++) {
|
|
easy_atomic_add(&p->int64_add, 1);
|
|
easy_atomic_add(&p->int64_sum, 1);
|
|
}
|
|
|
|
for(i = 0; i < p->loop_count; i++) {
|
|
easy_atomic_add_return(&p->int64_add_return, 1);
|
|
easy_atomic_add_return(&p->int64_sum, 1);
|
|
}
|
|
|
|
for(i = 0; i < p->loop_count; i++) {
|
|
easy_atomic_inc(&p->int64_inc);
|
|
easy_atomic_inc(&p->int64_sum);
|
|
}
|
|
|
|
for(i = 0; i < p->loop_count; i++) {
|
|
easy_atomic_dec(&p->int64_dec);
|
|
easy_atomic_dec(&p->int64_sum);
|
|
}
|
|
|
|
for(i = 0; i < p->loop_count; i++) {
|
|
easy_atomic32_add(&p->int32_add, 1);
|
|
easy_atomic32_add(&p->int32_sum, 1);
|
|
}
|
|
|
|
for(i = 0; i < p->loop_count; i++) {
|
|
easy_atomic32_add_return(&p->int32_add_return, 1);
|
|
easy_atomic32_add_return(&p->int32_sum, 1);
|
|
}
|
|
|
|
for(i = 0; i < p->loop_count; i++) {
|
|
easy_atomic32_inc(&p->int32_inc);
|
|
easy_atomic32_inc(&p->int32_sum);
|
|
}
|
|
|
|
for(i = 0; i < p->loop_count; i++) {
|
|
easy_atomic32_dec(&p->int32_dec);
|
|
easy_atomic32_dec(&p->int32_sum);
|
|
}
|
|
|
|
int j = 0;
|
|
int t = 0;
|
|
easy_atomic_t v;
|
|
|
|
for(j = 0; j < p->loop_count; j++) {
|
|
do {
|
|
v = p->int64_set;
|
|
t = easy_atomic_cmp_set(&p->int64_set, v, v + 1);
|
|
} while(t == 0);
|
|
|
|
easy_atomic_add(&p->int64_set_sum, t);
|
|
}
|
|
|
|
return (void *)NULL;
|
|
}
|
|
|
|
TEST(easy_atomic, mthread_atomic_op)
|
|
{
|
|
const int thread_count = 10;
|
|
pthread_t tids[thread_count];
|
|
int i;
|
|
easy_atomic_mt_op_args_t param;
|
|
memset(¶m, 0, sizeof(param));
|
|
param.loop_count = 10000;
|
|
|
|
for(i = 0; i < thread_count; i++) {
|
|
pthread_create(&tids[i], NULL, easy_atomic_mthread_op_start, ¶m);
|
|
}
|
|
|
|
for(i = 0; i < thread_count; i++) {
|
|
pthread_join(tids[i], NULL);
|
|
}
|
|
|
|
EXPECT_EQ(param.int64_add, param.loop_count * thread_count);
|
|
EXPECT_EQ(param.int64_add_return, param.loop_count * thread_count);
|
|
EXPECT_EQ(param.int64_inc, param.loop_count * thread_count);
|
|
EXPECT_EQ(param.int64_dec, - param.loop_count * thread_count);
|
|
EXPECT_EQ(param.int64_sum, param.loop_count * 2 * thread_count);
|
|
|
|
EXPECT_EQ(param.int32_add, param.loop_count * thread_count);
|
|
EXPECT_EQ(param.int32_add_return, param.loop_count * thread_count);
|
|
EXPECT_EQ(param.int32_inc, param.loop_count * thread_count);
|
|
EXPECT_EQ(param.int32_dec, - param.loop_count * thread_count);
|
|
EXPECT_EQ(param.int32_sum, param.loop_count * 2 * thread_count);
|
|
|
|
EXPECT_EQ(param.int64_set_sum, param.loop_count * thread_count);
|
|
}
|
|
|
|
TEST(easy_atomic, easy_bit)
|
|
{
|
|
uint64_t x = 0;
|
|
int i;
|
|
|
|
for(i = 0; i < 8; i++) easy_set_bit(i * 8, &x);
|
|
|
|
EXPECT_EQ(x, __INT64_C(0x0101010101010101));
|
|
|
|
for(i = 0; i < 8; i++) easy_set_bit(i * 8 + 7, &x);
|
|
|
|
EXPECT_EQ(x, __INT64_C(0x8181818181818181));
|
|
|
|
for(i = 0; i < 8; i++) easy_clear_bit(i * 8 + 7, &x);
|
|
|
|
EXPECT_EQ(x, __INT64_C(0x0101010101010101));
|
|
|
|
for(i = 0; i < 8; i++) easy_clear_bit(i * 8, &x);
|
|
|
|
EXPECT_EQ(x, 0);
|
|
}
|
|
|
|
TEST(easy_atomic, easy_spinrwlock)
|
|
{
|
|
easy_spinrwlock_t lock = EASY_SPINRWLOCK_INITIALIZER;
|
|
|
|
int ret = easy_spinrwlock_rdlock(&lock);
|
|
EXPECT_EQ(EASY_OK, ret);
|
|
ret = easy_spinrwlock_unlock(&lock);
|
|
EXPECT_EQ(EASY_OK, ret);
|
|
|
|
ret = easy_spinrwlock_wrlock(&lock);
|
|
EXPECT_EQ(EASY_OK, ret);
|
|
ret = easy_spinrwlock_unlock(&lock);
|
|
EXPECT_EQ(EASY_OK, ret);
|
|
|
|
ret = easy_spinrwlock_rdlock(&lock);
|
|
EXPECT_EQ(EASY_OK, ret);
|
|
ret = easy_spinrwlock_try_rdlock(&lock);
|
|
EXPECT_EQ(EASY_OK, ret);
|
|
ret = easy_spinrwlock_unlock(&lock);
|
|
EXPECT_EQ(EASY_OK, ret);
|
|
ret = easy_spinrwlock_try_wrlock(&lock);
|
|
EXPECT_EQ(EASY_AGAIN, ret);
|
|
ret = easy_spinrwlock_unlock(&lock);
|
|
EXPECT_EQ(EASY_OK, ret);
|
|
|
|
ret = easy_spinrwlock_wrlock(&lock);
|
|
EXPECT_EQ(EASY_OK, ret);
|
|
ret = easy_spinrwlock_try_rdlock(&lock);
|
|
EXPECT_EQ(EASY_AGAIN, ret);
|
|
ret = easy_spinrwlock_try_wrlock(&lock);
|
|
EXPECT_EQ(EASY_AGAIN, ret);
|
|
ret = easy_spinrwlock_unlock(&lock);
|
|
EXPECT_EQ(EASY_OK, ret);
|
|
}
|
|
|