#include "easy_atomic.h" #include #include /** * 测试 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); }