aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/CMakeLists.txt1
-rw-r--r--src/core/synch_test.c216
-rw-r--r--tests/CMakeLists.txt1
-rw-r--r--tests/synch.c138
4 files changed, 217 insertions, 139 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 90ef4023..b8aa1e63 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -88,5 +88,6 @@ nng_test(message_test)
nng_test(reconnect_test)
nng_test(sock_test)
nng_test(sockaddr_test)
+nng_test(synch_test)
nng_test(stats_test)
nng_test(url_test)
diff --git a/src/core/synch_test.c b/src/core/synch_test.c
new file mode 100644
index 00000000..87745cbe
--- /dev/null
+++ b/src/core/synch_test.c
@@ -0,0 +1,216 @@
+//
+// Copyright 2024 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2018 Capitar IT Group BV <info@capitar.com>
+//
+// This software is supplied under the terms of the MIT License, a
+// copy of which should be located in the distribution where this
+// file was obtained (LICENSE.txt). A copy of the license may also be
+// found online at https://opensource.org/licenses/MIT.
+//
+
+#include <nng/nng.h>
+
+#include <nuts.h>
+
+// Notify tests for verifying condvars.
+struct notifyarg {
+ int did;
+ nng_duration when;
+ nng_mtx *mx;
+ nng_cv *cv;
+ bool wake;
+ bool fini;
+};
+
+void
+notifyafter(void *a)
+{
+ struct notifyarg *na = a;
+
+ nng_msleep(na->when);
+ nng_mtx_lock(na->mx);
+ na->did = 1;
+ nng_cv_wake(na->cv);
+ nng_mtx_unlock(na->mx);
+}
+
+static void
+test_mutex_lock_unlock(void)
+{
+ nng_mtx *mtx;
+ NUTS_PASS(nng_mtx_alloc(&mtx));
+ for (int i = 1; i < 100; i++) {
+ nng_mtx_lock(mtx);
+ nng_mtx_unlock(mtx);
+ }
+ nng_mtx_free(mtx);
+}
+
+static void
+test_mutex_block(void)
+{
+ nng_thread *thr;
+ struct notifyarg arg = { 0 };
+
+ NUTS_PASS(nng_mtx_alloc(&arg.mx));
+ NUTS_PASS(nng_cv_alloc(&arg.cv, arg.mx));
+ arg.did = 0;
+ arg.when = 0;
+ nng_mtx_lock(arg.mx);
+ NUTS_PASS(nng_thread_create(&thr, notifyafter, &arg));
+ nng_thread_set_name(thr, "notify thread");
+ nng_msleep(10);
+ NUTS_TRUE(arg.did == 0);
+ nng_mtx_unlock(arg.mx);
+ nng_msleep(10);
+ nng_mtx_lock(arg.mx);
+ while (!arg.did) {
+ nng_cv_wait(arg.cv);
+ }
+ NUTS_TRUE(arg.did != 0);
+ nng_mtx_unlock(arg.mx);
+ nng_thread_destroy(thr);
+ nng_cv_free(arg.cv);
+ nng_mtx_free(arg.mx);
+}
+
+static void
+test_cv_wake(void)
+{
+ nng_thread *thr;
+ struct notifyarg arg = { 0 };
+
+ NUTS_PASS(nng_mtx_alloc(&arg.mx));
+ NUTS_PASS(nng_cv_alloc(&arg.cv, arg.mx));
+ arg.did = 0;
+ arg.when = 10;
+ NUTS_PASS(nng_thread_create(&thr, notifyafter, &arg));
+ nng_thread_set_name(thr, "notify thread");
+
+ nng_mtx_lock(arg.mx);
+ if (!arg.did) {
+ nng_cv_wait(arg.cv);
+ }
+ nng_mtx_unlock(arg.mx);
+ nng_thread_destroy(thr);
+ NUTS_TRUE(arg.did == 1);
+ nng_cv_free(arg.cv);
+ nng_mtx_free(arg.mx);
+}
+
+static void
+waiter(void *arg)
+{
+ struct notifyarg *na = arg;
+ nng_mtx_lock(na->mx);
+ while (!na->wake && !na->fini) {
+ nng_cv_wait(na->cv);
+ }
+ if ((!na->fini) && na->wake) {
+ na->did++;
+ }
+ nng_mtx_unlock(na->mx);
+}
+
+static void
+test_cv_wake_only_one(void)
+{
+ nng_thread *thr1;
+ nng_thread *thr2;
+ struct notifyarg arg = { 0 };
+
+ NUTS_PASS(nng_mtx_alloc(&arg.mx));
+ NUTS_PASS(nng_cv_alloc(&arg.cv, arg.mx));
+ arg.did = 0;
+ arg.when = 10;
+ NUTS_PASS(nng_thread_create(&thr1, waiter, &arg));
+ nng_thread_set_name(thr1, "one");
+ NUTS_PASS(nng_thread_create(&thr2, waiter, &arg));
+ nng_thread_set_name(thr2, "two");
+ nng_msleep(200);
+
+ nng_mtx_lock(arg.mx);
+ arg.wake = true;
+ nng_cv_wake1(arg.cv);
+ nng_mtx_unlock(arg.mx);
+ nng_msleep(200);
+
+ nng_mtx_lock(arg.mx);
+ NUTS_TRUE(arg.did == 1);
+ NUTS_MSG("arg.did was %d", arg.did);
+ arg.fini = true;
+ nng_cv_wake(arg.cv);
+ nng_mtx_unlock(arg.mx);
+
+ nng_thread_destroy(thr1);
+ nng_thread_destroy(thr2);
+ nng_cv_free(arg.cv);
+ nng_mtx_free(arg.mx);
+}
+
+static void
+test_cv_timeout(void)
+{
+ nng_thread *thr;
+ struct notifyarg arg = { 0 };
+
+ NUTS_PASS(nng_mtx_alloc(&arg.mx));
+ NUTS_PASS(nng_cv_alloc(&arg.cv, arg.mx));
+ arg.did = 0;
+ arg.when = 200;
+ NUTS_PASS(nng_thread_create(&thr, notifyafter, &arg));
+ nng_thread_set_name(thr, "notify thread");
+ nng_mtx_lock(arg.mx);
+ if (!arg.did) {
+ nng_cv_until(arg.cv, nng_clock() + 10);
+ }
+ NUTS_TRUE(arg.did == 0);
+ nng_mtx_unlock(arg.mx);
+ nng_thread_destroy(thr);
+ nng_cv_free(arg.cv);
+ nng_mtx_free(arg.mx);
+}
+
+static void
+test_cv_poll(void)
+{
+ struct notifyarg arg = { 0 };
+
+ NUTS_PASS(nng_mtx_alloc(&arg.mx));
+ NUTS_PASS(nng_cv_alloc(&arg.cv, arg.mx));
+ nng_mtx_lock(arg.mx);
+ NUTS_FAIL(nng_cv_until(arg.cv, 0), NNG_EAGAIN);
+ nng_mtx_unlock(arg.mx);
+ nng_cv_free(arg.cv);
+ nng_mtx_free(arg.mx);
+}
+
+static void
+test_cv_timeout_no_thread(void)
+{
+ struct notifyarg arg = { 0 };
+
+ NUTS_PASS(nng_mtx_alloc(&arg.mx));
+ NUTS_PASS(nng_cv_alloc(&arg.cv, arg.mx));
+ arg.did = 0;
+ arg.when = 1;
+ nng_mtx_lock(arg.mx);
+ if (!arg.did) {
+ nng_cv_until(arg.cv, nng_clock() + 10);
+ }
+ NUTS_TRUE(arg.did == 0);
+ nng_mtx_unlock(arg.mx);
+ nng_cv_free(arg.cv);
+ nng_mtx_free(arg.mx);
+}
+
+NUTS_TESTS = {
+ { "mutex lock unlock", test_mutex_lock_unlock },
+ { "mutex lock block", test_mutex_block },
+ { "cv wake", test_cv_wake },
+ { "cv timeout", test_cv_timeout },
+ { "cv poll", test_cv_poll },
+ { "cv timeout no thread", test_cv_timeout_no_thread },
+ { "cv wake only one", test_cv_wake_only_one },
+ { NULL, NULL },
+};
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 272ba78e..1e8ea918 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -130,7 +130,6 @@ add_nng_test1(httpserver 30 NNG_SUPP_HTTP)
add_nng_test(ipcsupp 10)
add_nng_test(nonblock 60)
add_nng_test(scalability 20 ON)
-add_nng_test(synch 5)
add_nng_test(tcpsupp 10)
add_nng_test(wss 30)
add_nng_test1(zt 60 NNG_TRANSPORT_ZEROTIER)
diff --git a/tests/synch.c b/tests/synch.c
deleted file mode 100644
index c0bf18c9..00000000
--- a/tests/synch.c
+++ /dev/null
@@ -1,138 +0,0 @@
-//
-// Copyright 2022 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2024 Capitar IT Group BV <info@capitar.com>
-//
-// This software is supplied under the terms of the MIT License, a
-// copy of which should be located in the distribution where this
-// file was obtained (LICENSE.txt). A copy of the license may also be
-// found online at https://opensource.org/licenses/MIT.
-//
-
-#include <nng/nng.h>
-
-#include "convey.h"
-
-// Notify tests for verifying condvars.
-struct notifyarg {
- int did;
- nng_duration when;
- nng_mtx *mx;
- nng_cv *cv;
-};
-
-void
-notifyafter(void *a)
-{
- struct notifyarg *na = a;
-
- nng_msleep(na->when);
- nng_mtx_lock(na->mx);
- na->did = 1;
- nng_cv_wake(na->cv);
- nng_mtx_unlock(na->mx);
-}
-
-struct notifyarg arg;
-nng_thread *thr;
-
-static void
-test_sync(void)
-{
- Convey("Mutexes work", {
- nng_mtx *mx;
-
- So(nng_mtx_alloc(&mx) == 0);
- Reset({ nng_mtx_free(mx); });
-
- Convey("We can lock and unlock a mutex", {
- nng_mtx_lock(mx);
- So(1);
- nng_mtx_unlock(mx);
- So(1);
- Convey("And then lock it again", {
- nng_mtx_lock(mx);
- So(1);
- nng_mtx_unlock(mx);
- So(1);
- });
- });
- Convey("Things block properly", {
- So(nng_mtx_alloc(&arg.mx) == 0);
- So(nng_cv_alloc(&arg.cv, arg.mx) == 0);
- arg.did = 0;
- arg.when = 0;
- nng_mtx_lock(arg.mx);
- So(nng_thread_create(&thr, notifyafter, &arg) == 0);
- nng_msleep(10);
- So(arg.did == 0);
- nng_mtx_unlock(arg.mx);
- nng_msleep(10);
- nng_mtx_lock(arg.mx);
- while (!arg.did) {
- nng_cv_wait(arg.cv);
- }
- So(arg.did != 0);
- nng_mtx_unlock(arg.mx);
- nng_thread_destroy(thr);
- nng_cv_free(arg.cv);
- nng_mtx_free(arg.mx);
- })
- });
-
- Convey("Condition variables work", {
- So(nng_mtx_alloc(&arg.mx) == 0);
- So(nng_cv_alloc(&arg.cv, arg.mx) == 0);
-
- Reset({
- nng_cv_free(arg.cv);
- nng_mtx_free(arg.mx);
- });
-
- Convey("Notification works", {
- arg.did = 0;
- arg.when = 10;
- So(nng_thread_create(&thr, notifyafter, &arg) == 0);
-
- nng_mtx_lock(arg.mx);
- if (!arg.did) {
- nng_cv_wait(arg.cv);
- }
- nng_mtx_unlock(arg.mx);
- nng_thread_destroy(thr);
- So(arg.did == 1);
- });
-
- Convey("Timeout works", {
- arg.did = 0;
- arg.when = 200;
- So(nng_thread_create(&thr, notifyafter, &arg) == 0);
- nng_mtx_lock(arg.mx);
- if (!arg.did) {
- nng_cv_until(arg.cv, nng_clock() + 10);
- }
- So(arg.did == 0);
- nng_mtx_unlock(arg.mx);
- nng_thread_destroy(thr);
- });
-
- Convey("Empty timeout is EAGAIN", {
- nng_mtx_lock(arg.mx);
- So(nng_cv_until(arg.cv, 0) == NNG_EAGAIN);
- nng_mtx_unlock(arg.mx);
- });
-
- Convey("Not running works", {
- arg.did = 0;
- arg.when = 1;
- nng_mtx_lock(arg.mx);
- if (!arg.did) {
- nng_cv_until(arg.cv, nng_clock() + 10);
- }
- So(arg.did == 0);
- nng_mtx_unlock(arg.mx);
- });
- });
-}
-
-TestMain(
- "Synchronization", { Convey("Synchronization works", { test_sync(); }); })