diff options
| author | Garrett D'Amore <garrett@damore.org> | 2024-11-30 21:50:12 -0500 |
|---|---|---|
| committer | Garrett D'Amore <garrett@damore.org> | 2024-11-30 22:33:42 -0500 |
| commit | 0a2a8d4c14543b9b8b1228e6012b05190915bda4 (patch) | |
| tree | 97be4892f700eff2bde58820976c6f6f9afddabc | |
| parent | 6a417484cd7327b0092df47457fa8cc7f548955c (diff) | |
| download | nng-0a2a8d4c14543b9b8b1228e6012b05190915bda4.tar.gz nng-0a2a8d4c14543b9b8b1228e6012b05190915bda4.tar.bz2 nng-0a2a8d4c14543b9b8b1228e6012b05190915bda4.zip | |
tests: convert synch test to NUTS.
While here we added a test for nng_cv_wake1 to demonstrate it does
not fall afoul of the thundering herd.
| -rw-r--r-- | src/core/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/core/synch_test.c | 216 | ||||
| -rw-r--r-- | tests/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | tests/synch.c | 138 |
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(); }); }) |
