summaryrefslogtreecommitdiff
path: root/source/test
diff options
context:
space:
mode:
authorMitya Selivanov <0x7fffff@guattari.ru>2022-08-18 06:50:13 +0400
committerMitya Selivanov <0x7fffff@guattari.ru>2022-08-18 06:50:13 +0400
commit5f80c8b54d011580383810597aa68565ddfb8f3c (patch)
tree3bf431e61e580a68de55840fa016dbfa0767d4e9 /source/test
parentac4face2d7d6d2b033874d3e6e24d2133c96132f (diff)
downloadkit-5f80c8b54d011580383810597aa68565ddfb8f3c.zip
[test] thread, mutex, condition variable
Diffstat (limited to 'source/test')
-rw-r--r--source/test/unittests/CMakeLists.txt7
-rw-r--r--source/test/unittests/c11_threads.c6
-rw-r--r--source/test/unittests/condition_variable.test.c60
-rw-r--r--source/test/unittests/mutex.test.c74
-rw-r--r--source/test/unittests/thread.test.c78
5 files changed, 216 insertions, 9 deletions
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);
+}