From b53edfe94790a875ab873b880516326b88a3a751 Mon Sep 17 00:00:00 2001
From: Mitya Selivanov <0x7fffff@guattari.ru>
Date: Wed, 31 Aug 2022 02:18:29 +0400
Subject: [atomic] win32 test

---
 source/test/unittests/atomic.test.c             | 159 ++++++++++++++++++++++++
 source/test/unittests/condition_variable.test.c |   2 +-
 source/test/unittests/mutex.test.c              |  34 ++---
 3 files changed, 177 insertions(+), 18 deletions(-)

(limited to 'source/test')

diff --git a/source/test/unittests/atomic.test.c b/source/test/unittests/atomic.test.c
index 9f1a10b..8f6d22b 100644
--- a/source/test/unittests/atomic.test.c
+++ b/source/test/unittests/atomic.test.c
@@ -1,4 +1,5 @@
 #include "../../kit/atomic.h"
+#include "../../kit/threads.h"
 
 #define KIT_TEST_FILE atomic
 #include "../../kit_test/test.h"
@@ -24,3 +25,161 @@ TEST("atomic fetch add") {
                                     memory_order_relaxed) == 20);
   REQUIRE(atomic_load_explicit(&value, memory_order_relaxed) == 42);
 }
+
+enum { THREAD_COUNT = 20, TICK_COUNT = 10000 };
+
+static int test_8_(void *p) {
+  ATOMIC(int8_t) *x = (ATOMIC(int8_t) *) p;
+
+  for (ptrdiff_t i = 0; i < TICK_COUNT; i++) {
+    atomic_fetch_add_explicit(x, 20, memory_order_relaxed);
+    thrd_yield();
+    atomic_fetch_add_explicit(x, 22, memory_order_relaxed);
+    thrd_yield();
+    atomic_fetch_add_explicit(x, -42, memory_order_relaxed);
+    thrd_yield();
+  }
+}
+
+TEST("atomic types") {
+  ATOMIC(int8_t) byte;
+  ATOMIC(int16_t) i16;
+  ATOMIC(int32_t) i32;
+  ATOMIC(int64_t) i64;
+
+  atomic_store_explicit(&byte, 42, memory_order_relaxed);
+  atomic_store_explicit(&i16, 4242, memory_order_relaxed);
+  atomic_store_explicit(&i32, 42424242, memory_order_relaxed);
+  atomic_store_explicit(&i64, 4242424242424242ll,
+                        memory_order_relaxed);
+
+  atomic_fetch_add_explicit(&byte, -20, memory_order_relaxed);
+  atomic_fetch_add_explicit(&i16, -2020, memory_order_relaxed);
+  atomic_fetch_add_explicit(&i32, -20202020, memory_order_relaxed);
+  atomic_fetch_add_explicit(&i64, -2020202020202020ll,
+                            memory_order_relaxed);
+
+  REQUIRE(atomic_exchange_explicit(&byte, 0, memory_order_relaxed) ==
+          22);
+  REQUIRE(atomic_exchange_explicit(&i16, 0, memory_order_relaxed) ==
+          2222);
+  REQUIRE(atomic_exchange_explicit(&i32, 0, memory_order_relaxed) ==
+          22222222);
+  REQUIRE(atomic_exchange_explicit(&i64, 0, memory_order_relaxed) ==
+          2222222222222222ll);
+
+  REQUIRE(atomic_load_explicit(&byte, memory_order_relaxed) == 0);
+  REQUIRE(atomic_load_explicit(&i16, memory_order_relaxed) == 0);
+  REQUIRE(atomic_load_explicit(&i32, memory_order_relaxed) == 0);
+  REQUIRE(atomic_load_explicit(&i64, memory_order_relaxed) == 0ll);
+}
+
+TEST("atomic byte concurrency") {
+  ATOMIC(int8_t) foo;
+  ATOMIC(int8_t) bar;
+
+  atomic_store_explicit(&foo, 42, memory_order_relaxed);
+  atomic_store_explicit(&bar, 43, memory_order_relaxed);
+
+  thrd_t threads[THREAD_COUNT];
+  for (ptrdiff_t i = 0; i < THREAD_COUNT; i++)
+    thrd_create(threads + i, test_8_, (i % 2) ? &foo : &bar);
+  for (ptrdiff_t i = 0; i < THREAD_COUNT; i++)
+    thrd_join(threads[i], NULL);
+
+  REQUIRE(atomic_load_explicit(&foo, memory_order_relaxed) == 42);
+  REQUIRE(atomic_load_explicit(&bar, memory_order_relaxed) == 43);
+}
+
+static int test_16_(void *p) {
+  ATOMIC(int16_t) *x = (ATOMIC(int16_t) *) p;
+
+  for (ptrdiff_t i = 0; i < TICK_COUNT; i++) {
+    atomic_fetch_add_explicit(x, 2020, memory_order_relaxed);
+    thrd_yield();
+    atomic_fetch_add_explicit(x, 2222, memory_order_relaxed);
+    thrd_yield();
+    atomic_fetch_add_explicit(x, -4242, memory_order_relaxed);
+    thrd_yield();
+  }
+}
+
+TEST("atomic int16 concurrency") {
+  ATOMIC(int16_t) foo;
+  ATOMIC(int16_t) bar;
+
+  atomic_store_explicit(&foo, 42, memory_order_relaxed);
+  atomic_store_explicit(&bar, 43, memory_order_relaxed);
+
+  thrd_t threads[THREAD_COUNT];
+  for (ptrdiff_t i = 0; i < THREAD_COUNT; i++)
+    thrd_create(threads + i, test_16_, (i % 2) ? &foo : &bar);
+  for (ptrdiff_t i = 0; i < THREAD_COUNT; i++)
+    thrd_join(threads[i], NULL);
+
+  REQUIRE(atomic_load_explicit(&foo, memory_order_relaxed) == 42);
+  REQUIRE(atomic_load_explicit(&bar, memory_order_relaxed) == 43);
+}
+
+static int test_32_(void *p) {
+  ATOMIC(int32_t) *x = (ATOMIC(int32_t) *) p;
+
+  for (ptrdiff_t i = 0; i < TICK_COUNT; i++) {
+    atomic_fetch_add_explicit(x, 202020, memory_order_relaxed);
+    thrd_yield();
+    atomic_fetch_add_explicit(x, 222222, memory_order_relaxed);
+    thrd_yield();
+    atomic_fetch_add_explicit(x, -424242, memory_order_relaxed);
+    thrd_yield();
+  }
+}
+
+TEST("atomic int32 concurrency") {
+  ATOMIC(int32_t) foo;
+  ATOMIC(int32_t) bar;
+
+  atomic_store_explicit(&foo, 42, memory_order_relaxed);
+  atomic_store_explicit(&bar, 43, memory_order_relaxed);
+
+  thrd_t threads[THREAD_COUNT];
+  for (ptrdiff_t i = 0; i < THREAD_COUNT; i++)
+    thrd_create(threads + i, test_32_, (i % 2) ? &foo : &bar);
+  for (ptrdiff_t i = 0; i < THREAD_COUNT; i++)
+    thrd_join(threads[i], NULL);
+
+  REQUIRE(atomic_load_explicit(&foo, memory_order_relaxed) == 42);
+  REQUIRE(atomic_load_explicit(&bar, memory_order_relaxed) == 43);
+}
+
+static int test_64_(void *p) {
+  ATOMIC(int64_t) *x = (ATOMIC(int64_t) *) p;
+
+  for (ptrdiff_t i = 0; i < TICK_COUNT; i++) {
+    atomic_fetch_add_explicit(x, 20202020202020ll,
+                              memory_order_relaxed);
+    thrd_yield();
+    atomic_fetch_add_explicit(x, 22222222222222ll,
+                              memory_order_relaxed);
+    thrd_yield();
+    atomic_fetch_add_explicit(x, -42424242424242ll,
+                              memory_order_relaxed);
+    thrd_yield();
+  }
+}
+
+TEST("atomic int64 concurrency") {
+  ATOMIC(int64_t) foo;
+  ATOMIC(int64_t) bar;
+
+  atomic_store_explicit(&foo, 42, memory_order_relaxed);
+  atomic_store_explicit(&bar, 43, memory_order_relaxed);
+
+  thrd_t threads[THREAD_COUNT];
+  for (ptrdiff_t i = 0; i < THREAD_COUNT; i++)
+    thrd_create(threads + i, test_64_, (i % 2) ? &foo : &bar);
+  for (ptrdiff_t i = 0; i < THREAD_COUNT; i++)
+    thrd_join(threads[i], NULL);
+
+  REQUIRE(atomic_load_explicit(&foo, memory_order_relaxed) == 42);
+  REQUIRE(atomic_load_explicit(&bar, memory_order_relaxed) == 43);
+}
diff --git a/source/test/unittests/condition_variable.test.c b/source/test/unittests/condition_variable.test.c
index 93389e9..c855b0c 100644
--- a/source/test/unittests/condition_variable.test.c
+++ b/source/test/unittests/condition_variable.test.c
@@ -1,4 +1,4 @@
-#include "../../kit/threads.h"
+#include "../../kit/condition_variable.h"
 
 #define KIT_TEST_FILE condition_variable
 #include "../../kit_test/test.h"
diff --git a/source/test/unittests/mutex.test.c b/source/test/unittests/mutex.test.c
index d7b209b..7cce6db 100644
--- a/source/test/unittests/mutex.test.c
+++ b/source/test/unittests/mutex.test.c
@@ -1,9 +1,9 @@
-#include "../../kit/threads.h"
+#include "../../kit/mutex.h"
 
 #define KIT_TEST_FILE mutex
 #include "../../kit_test/test.h"
 
-enum { THREAD_COUNT = 200 };
+enum { SLEEP = 200000000, TICK_COUNT = 200, THREAD_COUNT = 100 };
 
 typedef struct {
   mtx_t lock;
@@ -12,7 +12,7 @@ typedef struct {
 
 static int test_run(void *data) {
   test_data_t *x = (test_data_t *) data;
-  for (int i = 0; i < 1000; i++) {
+  for (int i = 0; i < TICK_COUNT; i++) {
     mtx_lock(&x->lock);
 
     x->value += i;
@@ -28,18 +28,6 @@ static int test_run(void *data) {
   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);
-
-  return 0;
-}
-
 TEST("mutex lock") {
   test_data_t data;
   thrd_t      pool[THREAD_COUNT];
@@ -55,14 +43,26 @@ TEST("mutex lock") {
   REQUIRE(data.value == 42);
 }
 
+static int test_lock(void *data) {
+  mtx_t *m = (mtx_t *) data;
+  mtx_lock(m);
+
+  struct timespec sec = { .tv_sec = 0, .tv_nsec = SLEEP };
+  thrd_sleep(&sec, NULL);
+
+  mtx_unlock(m);
+
+  return 0;
+}
+
 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);
+  REQUIRE(thrd_create(&t, test_lock, &m) == thrd_success);
 
-  struct timespec sec = { .tv_sec = 1, .tv_nsec = 0 };
+  struct timespec sec = { .tv_sec = 0, .tv_nsec = SLEEP / 2 };
   REQUIRE(thrd_sleep(&sec, NULL) == thrd_success);
 
   REQUIRE(mtx_trylock(&m) == thrd_busy);
-- 
cgit v1.2.3