From 5f80c8b54d011580383810597aa68565ddfb8f3c Mon Sep 17 00:00:00 2001 From: Mitya Selivanov <0x7fffff@guattari.ru> Date: Thu, 18 Aug 2022 06:50:13 +0400 Subject: [test] thread, mutex, condition variable --- source/test/unittests/CMakeLists.txt | 7 ++- source/test/unittests/c11_threads.c | 6 -- source/test/unittests/condition_variable.test.c | 60 +++++++++++++++++++ source/test/unittests/mutex.test.c | 74 +++++++++++++++++++++++ source/test/unittests/thread.test.c | 78 +++++++++++++++++++++++++ 5 files changed, 216 insertions(+), 9 deletions(-) delete mode 100644 source/test/unittests/c11_threads.c create mode 100644 source/test/unittests/condition_variable.test.c create mode 100644 source/test/unittests/mutex.test.c create mode 100644 source/test/unittests/thread.test.c (limited to 'source/test') diff --git a/source/test/unittests/CMakeLists.txt b/source/test/unittests/CMakeLists.txt index 5ec950d..e64628d 100644 --- a/source/test/unittests/CMakeLists.txt +++ b/source/test/unittests/CMakeLists.txt @@ -1,7 +1,8 @@ target_sources( ${KIT_TEST_SUITE} PRIVATE - async_function.test.c test_duration.test.c main.test.c - string_ref.test.c atomic.test.c array_ref.test.c input_stream.test.c - lower_bound.test.c mersenne_twister_64.test.c input_buffer.test.c + async_function.test.c mutex.test.c test_duration.test.c + main.test.c string_ref.test.c atomic.test.c thread.test.c + array_ref.test.c input_stream.test.c lower_bound.test.c + condition_variable.test.c mersenne_twister_64.test.c input_buffer.test.c dynamic_array.test.c) diff --git a/source/test/unittests/c11_threads.c b/source/test/unittests/c11_threads.c deleted file mode 100644 index cd50846..0000000 --- a/source/test/unittests/c11_threads.c +++ /dev/null @@ -1,6 +0,0 @@ -#include "../../kit/c11/threads.h" - -#define KIT_TEST_FILE atomic -#include "../../kit_test/test.h" - -TEST("c11 threads") { } diff --git a/source/test/unittests/condition_variable.test.c b/source/test/unittests/condition_variable.test.c new file mode 100644 index 0000000..c9d818a --- /dev/null +++ b/source/test/unittests/condition_variable.test.c @@ -0,0 +1,60 @@ +#include "../../kit/threads.h" + +#define KIT_TEST_FILE condition_variable +#include "../../kit_test/test.h" + +typedef struct { + mtx_t m; + cnd_t send; + cnd_t receive; + int value; +} test_data_t; + +static int test_run(void *p) { + test_data_t *data = (test_data_t *) p; + + mtx_lock(&data->m); + + data->value = 20; + mtx_unlock(&data->m); + cnd_broadcast(&data->send); + + cnd_wait(&data->receive, &data->m); + + data->value = 22; + cnd_broadcast(&data->send); + + mtx_unlock(&data->m); + + return 0; +} + +TEST("condition variable") { + test_data_t data; + REQUIRE(mtx_init(&data.m, mtx_plain) == thrd_success); + REQUIRE(cnd_init(&data.send) == thrd_success); + REQUIRE(cnd_init(&data.receive) == thrd_success); + data.value = 0; + + thrd_t t; + REQUIRE(thrd_create(&t, test_run, &data) == thrd_success); + + REQUIRE(mtx_lock(&data.m) == thrd_success); + + REQUIRE(cnd_wait(&data.send, &data.m) == thrd_success); + int x = data.value; + + REQUIRE(cnd_broadcast(&data.receive) == thrd_success); + + REQUIRE(cnd_wait(&data.send, &data.m) == thrd_success); + x += data.value; + + REQUIRE(mtx_unlock(&data.m) == thrd_success); + REQUIRE(thrd_join(t, NULL) == thrd_success); + + mtx_destroy(&data.m); + cnd_destroy(&data.send); + cnd_destroy(&data.receive); + + REQUIRE(x == 42); +} diff --git a/source/test/unittests/mutex.test.c b/source/test/unittests/mutex.test.c new file mode 100644 index 0000000..c0153e7 --- /dev/null +++ b/source/test/unittests/mutex.test.c @@ -0,0 +1,74 @@ +#include "../../kit/threads.h" + +#define KIT_TEST_FILE mutex +#include "../../kit_test/test.h" + +enum { THREAD_COUNT = 200 }; + +typedef struct { + mtx_t lock; + int value; +} test_data_t; + +static int test_run(void *data) { + test_data_t *x = (test_data_t *) data; + for (int i = 0; i < 1000; i++) { + mtx_lock(&x->lock); + + x->value += i; + thrd_yield(); + x->value -= i + 42; + thrd_yield(); + x->value += i + 20; + thrd_yield(); + x->value += 22 - i; + + mtx_unlock(&x->lock); + } + return 0; +} + +int test_lock_for_2_sec(void *data) { + mtx_t *m = (mtx_t *) data; + mtx_lock(m); + + struct timespec sec = { .tv_sec = 2, .tv_nsec = 0 }; + thrd_sleep(&sec, NULL); + + mtx_unlock(m); +} + +TEST("mutex lock") { + test_data_t data; + thrd_t pool[THREAD_COUNT]; + data.value = 42; + REQUIRE(mtx_init(&data.lock, mtx_plain) == thrd_success); + + for (ptrdiff_t i = 0; i < THREAD_COUNT; i++) + thrd_create(pool + i, test_run, &data); + for (ptrdiff_t i = 0; i < THREAD_COUNT; i++) + thrd_join(pool[i], NULL); + + mtx_destroy(&data.lock); + REQUIRE(data.value == 42); +} + +TEST("mutex try lock") { + mtx_t m; + REQUIRE(mtx_init(&m, mtx_plain) == thrd_success); + + thrd_t t; + REQUIRE(thrd_create(&t, test_lock_for_2_sec, &m) == thrd_success); + + struct timespec sec = { .tv_sec = 1, .tv_nsec = 0 }; + REQUIRE(thrd_sleep(&sec, NULL) == thrd_success); + + REQUIRE(mtx_trylock(&m) == thrd_busy); + + REQUIRE(thrd_join(t, NULL) == thrd_success); + + REQUIRE(mtx_trylock(&m) == thrd_success); + REQUIRE(mtx_unlock(&m) == thrd_success); + + mtx_destroy(&m); +} diff --git a/source/test/unittests/thread.test.c b/source/test/unittests/thread.test.c new file mode 100644 index 0000000..44e51b5 --- /dev/null +++ b/source/test/unittests/thread.test.c @@ -0,0 +1,78 @@ +#include "../../kit/threads.h" + +#define KIT_TEST_FILE thread +#include "../../kit_test/test.h" + +static int test_nothing(void *) { } + +static int test_run(void *data) { + int *n = (int *) data; + return *n + 20; +} + +static int test_exit(void *data) { + int *n = (int *) data; + + *n = 1; + thrd_exit(3); + *n = 2; + return 4; +} + +static int test_yield(void *data) { + thrd_yield(); +} + +static int test_sleep(void *data) { + struct timespec t = { .tv_sec = 0, .tv_nsec = 10000000 }; + thrd_sleep(&t, NULL); +} + +TEST("thread run") { + thrd_t t; + int data = 22; + int result; + REQUIRE(thrd_create(&t, test_run, &data) == thrd_success); + REQUIRE(thrd_join(t, &result) == thrd_success); + REQUIRE(result == 42); +} + +TEST("thread equal") { + thrd_t foo, bar; + REQUIRE(thrd_create(&foo, test_nothing, NULL) == thrd_success); + REQUIRE(thrd_create(&bar, test_nothing, NULL) == thrd_success); + REQUIRE(thrd_equal(foo, foo)); + REQUIRE(!thrd_equal(foo, bar)); + REQUIRE(!thrd_equal(foo, thrd_current())); +} + +TEST("thread exit") { + thrd_t foo; + int data; + int result; + REQUIRE(thrd_create(&foo, test_exit, &data) == thrd_success); + REQUIRE(thrd_join(foo, &result) == thrd_success); + REQUIRE(data == 1); + REQUIRE(result == 3); +} + +TEST("thread yield") { + thrd_t foo; + REQUIRE(thrd_create(&foo, test_yield, NULL) == thrd_success); + REQUIRE(thrd_join(foo, NULL) == thrd_success); +} + +TEST("thread sleep") { + thrd_t foo; + REQUIRE(thrd_create(&foo, test_sleep, NULL) == thrd_success); + REQUIRE(thrd_join(foo, NULL) == thrd_success); +} + +TEST("thread detach") { + thrd_t foo; + REQUIRE(thrd_create(&foo, test_nothing, NULL) == thrd_success); + REQUIRE(thrd_detach(foo) == thrd_success); + + struct timespec t = { .tv_sec = 0, .tv_nsec = 10000000 }; + thrd_sleep(&t, NULL); +} -- cgit v1.2.3