diff options
Diffstat (limited to 'libcr_ipc/tests')
-rw-r--r-- | libcr_ipc/tests/config.h | 20 | ||||
-rw-r--r-- | libcr_ipc/tests/test.h | 21 | ||||
-rw-r--r-- | libcr_ipc/tests/test_chan.c | 49 | ||||
-rw-r--r-- | libcr_ipc/tests/test_mutex.c | 37 | ||||
-rw-r--r-- | libcr_ipc/tests/test_rpc.c | 59 | ||||
-rw-r--r-- | libcr_ipc/tests/test_rwmutex.c | 88 | ||||
-rw-r--r-- | libcr_ipc/tests/test_select.c | 89 | ||||
-rw-r--r-- | libcr_ipc/tests/test_sema.c | 76 |
8 files changed, 439 insertions, 0 deletions
diff --git a/libcr_ipc/tests/config.h b/libcr_ipc/tests/config.h new file mode 100644 index 0000000..a648589 --- /dev/null +++ b/libcr_ipc/tests/config.h @@ -0,0 +1,20 @@ +/* config.h - Compile-time configuration for the libcr_ipc tests + * + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#ifndef _CONFIG_H_ +#define _CONFIG_H_ + +#define CONFIG_COROUTINE_STACK_SIZE_DEFAULT (8*1024) +#define CONFIG_COROUTINE_NAME_LEN 16 +#define CONFIG_COROUTINE_NUM 16 + +#define CONFIG_COROUTINE_MEASURE_STACK 1 +#define CONFIG_COROUTINE_PROTECT_STACK 1 +#define CONFIG_COROUTINE_DEBUG 1 +#define CONFIG_COROUTINE_VALGRIND 1 +#define CONFIG_COROUTINE_GDB 1 + +#endif /* _CONFIG_H_ */ diff --git a/libcr_ipc/tests/test.h b/libcr_ipc/tests/test.h new file mode 100644 index 0000000..4928d8d --- /dev/null +++ b/libcr_ipc/tests/test.h @@ -0,0 +1,21 @@ +/* libcr_ipc/tests/test.h - Common test utilities + * + * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#ifndef _LIBCR_IPC_TESTS_TEST_H_ +#define _LIBCR_IPC_TESTS_TEST_H_ + +#include <stdio.h> +#include <stdlib.h> /* for exit() */ + +#define test_assert(expr) do { \ + if (!(expr)) { \ + printf("test failure: %s:%d:%s: %s\n", \ + __FILE__, __LINE__, __func__, #expr); \ + exit(1); \ + } \ + } while (0) + +#endif /* _LIBCR_IPC_TESTS_TEST_H_ */ diff --git a/libcr_ipc/tests/test_chan.c b/libcr_ipc/tests/test_chan.c new file mode 100644 index 0000000..4788dd4 --- /dev/null +++ b/libcr_ipc/tests/test_chan.c @@ -0,0 +1,49 @@ +/* libcr_ipc/tests/test_chan.c - Tests for <libcr_ipc/chan.h> + * + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#include <libcr/coroutine.h> +#include <libcr_ipc/chan.h> + +#include "test.h" + +CR_CHAN_DECLARE(intchan, int); + +COROUTINE producer_cr(void *_ch) { + intchan_t *ch = _ch; + cr_begin(); + + cr_chan_send(ch, 1); + + while (!cr_chan_can_send(ch)) + cr_yield(); + + cr_chan_send(ch, 2); + + + cr_end(); +} + +COROUTINE consumer_cr(void *_ch) { + int x; + intchan_t *ch = _ch; + cr_begin(); + + x = cr_chan_recv(ch); + test_assert(x == 1); + + x = cr_chan_recv(ch); + test_assert(x == 2); + + cr_end(); +} + +int main() { + intchan_t ch = {0}; + coroutine_add("producer", producer_cr, &ch); + coroutine_add("consumer", consumer_cr, &ch); + coroutine_main(); + return 0; +} diff --git a/libcr_ipc/tests/test_mutex.c b/libcr_ipc/tests/test_mutex.c new file mode 100644 index 0000000..d08315d --- /dev/null +++ b/libcr_ipc/tests/test_mutex.c @@ -0,0 +1,37 @@ +/* libcr_ipc/tests/test_mutex.c - Tests for <libcr_ipc/mutex.h> + * + * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#include <libcr/coroutine.h> +#include <libcr_ipc/mutex.h> + +#include "test.h" + +int counter = 0; + +COROUTINE worker_cr(void *_mu) { + cr_mutex_t *mu = _mu; + cr_begin(); + + for (int i = 0; i < 100; i++) { + cr_mutex_lock(mu); + int a = counter; + cr_yield(); + counter = a + 1; + cr_mutex_unlock(mu); + cr_yield(); + } + + cr_end(); +} + +int main() { + cr_mutex_t mu = {}; + coroutine_add("a", worker_cr, &mu); + coroutine_add("b", worker_cr, &mu); + coroutine_main(); + test_assert(counter == 200); + return 0; +} diff --git a/libcr_ipc/tests/test_rpc.c b/libcr_ipc/tests/test_rpc.c new file mode 100644 index 0000000..1461450 --- /dev/null +++ b/libcr_ipc/tests/test_rpc.c @@ -0,0 +1,59 @@ +/* libcr_ipc/tests/test_rpc.c - Tests for <libcr_ipc/rpc.h> + * + * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#include <libcr/coroutine.h> +#include <libcr_ipc/rpc.h> + +#include "test.h" + +CR_RPC_DECLARE(intrpc, int, int); + +/* Test that the RPC is fair, have worker1 start waiting first, and + * ensure that it gets the first request. */ + +COROUTINE caller_cr(void *_ch) { + intrpc_t *ch = _ch; + cr_begin(); + + int resp = cr_rpc_send_req(ch, 1); + test_assert(resp == 2); + + resp = cr_rpc_send_req(ch, 3); + test_assert(resp == 4); + + cr_exit(); +} + +COROUTINE worker1_cr(void *_ch) { + intrpc_t *ch = _ch; + cr_begin(); + + intrpc_req_t req = cr_rpc_recv_req(ch); + test_assert(req.req == 1); + cr_rpc_send_resp(req, 2); + + cr_exit(); +} + +COROUTINE worker2_cr(void *_ch) { + intrpc_t *ch = _ch; + cr_begin(); + + intrpc_req_t req = cr_rpc_recv_req(ch); + test_assert(req.req == 3); + cr_rpc_send_resp(req, 4); + + cr_exit(); +} + +int main() { + intrpc_t ch = {0}; + coroutine_add("worker1", worker1_cr, &ch); + coroutine_add("caller", caller_cr, &ch); + coroutine_add("worker2", worker2_cr, &ch); + coroutine_main(); + return 0; +} diff --git a/libcr_ipc/tests/test_rwmutex.c b/libcr_ipc/tests/test_rwmutex.c new file mode 100644 index 0000000..77e8c7c --- /dev/null +++ b/libcr_ipc/tests/test_rwmutex.c @@ -0,0 +1,88 @@ +/* libcr_ipc/tests/test_rwmutex.c - Tests for <libcr_ipc/rwmutex.h> + * + * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#include <string.h> + +#include <libcr/coroutine.h> +#include <libcr_ipc/rwmutex.h> + +#include "test.h" + +cr_rwmutex_t mu = {}; +char out[10] = {0}; +size_t len = 0; + +COROUTINE cr1_reader(void *_mu) { + cr_rwmutex_t *mu = _mu; + cr_begin(); + + cr_rwmutex_rlock(mu); + out[len++] = 'r'; + cr_yield(); + cr_rwmutex_runlock(mu); + + cr_end(); +} + +COROUTINE cr1_writer(void *_mu) { + cr_rwmutex_t *mu = _mu; + cr_begin(); + + cr_rwmutex_lock(mu); + out[len++] = 'w'; + cr_yield(); + cr_rwmutex_unlock(mu); + + cr_end(); +} + +COROUTINE cr2_waiter(void *_ch) { + char ch = *(char *)_ch; + cr_begin(); + + cr_rwmutex_rlock(&mu); + out[len++] = ch; + cr_rwmutex_runlock(&mu); + + cr_end(); +} + +COROUTINE cr2_init(void *) { + cr_begin(); + + char ch; + cr_rwmutex_lock(&mu); + ch = 'a'; coroutine_add("wait-a", cr2_waiter, &ch); + ch = 'b'; coroutine_add("wait-b", cr2_waiter, &ch); + cr_yield(); + ch = 'c'; coroutine_add("wait-c", cr2_waiter, &ch); + cr_rwmutex_unlock(&mu); + + cr_end(); +} + +int main() { + printf("== test 1 =========================================\n"); + coroutine_add("r1", cr1_reader, &mu); + coroutine_add("r2", cr1_reader, &mu); + coroutine_add("w", cr1_writer, &mu); + coroutine_add("r3", cr1_reader, &mu); + coroutine_add("r4", cr1_reader, &mu); + coroutine_main(); + test_assert(len == 5); + test_assert(strcmp(out, "rrwrr") == 0); + + printf("== test 2 =========================================\n"); + mu = (cr_rwmutex_t){}; + len = 0; + memset(out, 0, sizeof(out)); + coroutine_add("init", cr2_init, NULL); + coroutine_main(); + test_assert(len == 3); + test_assert(strcmp(out, "abc") == 0); + + return 0; +} diff --git a/libcr_ipc/tests/test_select.c b/libcr_ipc/tests/test_select.c new file mode 100644 index 0000000..9b5d117 --- /dev/null +++ b/libcr_ipc/tests/test_select.c @@ -0,0 +1,89 @@ +/* libcr_ipc/tests/test_select.c - Tests for <libcr_ipc/select.h> + * + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#include <libcr/coroutine.h> +#include <libcr_ipc/chan.h> + +#include "test.h" + +CR_CHAN_DECLARE(intchan, int); + +intchan_t ch[10] = {0}; +intchan_t fch = {0}; + +COROUTINE consumer_cr(void *) { + cr_begin(); + + struct cr_select_arg args[11]; + + bool chdone[10] = {0}; + int arg2ch[10]; + for (;;) { + int ret_ch; + int i_arg = 0; + for (int i_ch = 0; i_ch < 10; i_ch++) { + if (!chdone[i_ch]) { + args[i_arg] = CR_SELECT_RECV(&ch[i_ch], &ret_ch); + arg2ch[i_arg] = i_ch; + i_arg++; + } + } + if (!i_arg) + break; + args[i_arg] = CR_SELECT_DEFAULT; /* check that default doesn't trigger */ + test_assert(i_arg <= 10); + int ret_arg = cr_select_v(i_arg+1, args); + test_assert(ret_arg < i_arg); + test_assert(arg2ch[ret_arg] == ret_ch); + chdone[ret_ch] = true; + } + int ret_ch, ret_arg; + args[0] = CR_SELECT_RECV(&ch[0], &ret_ch); + args[1] = CR_SELECT_DEFAULT; + ret_arg = cr_select_v(2, args); + test_assert(ret_arg == 1); + + int send = 567; + args[0] = CR_SELECT_SEND(&fch, &send); + args[1] = CR_SELECT_DEFAULT; + ret_arg = cr_select_v(2, args); + test_assert(ret_arg == 0); + + send = 890; + ret_arg = cr_select_l(CR_SELECT_SEND(&fch, &send), + CR_SELECT_DEFAULT); + test_assert(ret_arg == 1); + + cr_end(); +} + +COROUTINE producer_cr(void *_n) { + int n = *(int *)_n; + cr_begin(); + + cr_chan_send(&ch[n], n); + + cr_end(); +} + +COROUTINE final_cr(void *) { + cr_begin(); + + int ret = cr_chan_recv(&fch); + printf("ret=%d\n", ret); + test_assert(ret == 567); + + cr_end(); +} + +int main() { + for (int i = 0; i < 10; i++) + coroutine_add("producer", producer_cr, &i); + coroutine_add("consumer", consumer_cr, NULL); + coroutine_add("final", final_cr, NULL); + coroutine_main(); + return 0; +} diff --git a/libcr_ipc/tests/test_sema.c b/libcr_ipc/tests/test_sema.c new file mode 100644 index 0000000..435c01a --- /dev/null +++ b/libcr_ipc/tests/test_sema.c @@ -0,0 +1,76 @@ +/* libcr_ipc/tests/test_sema.c - Tests for <libcr_ipc/sema.h> + * + * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#include <libcr/coroutine.h> + +#define IMPLEMENTATION_FOR_LIBCR_IPC_SEMA_H YES /* so we can access .cnt */ +#include <libcr_ipc/sema.h> + +#include "test.h" + +int counter = 0; + +COROUTINE first_cr(void *_sema) { + cr_sema_t *sema = _sema; + cr_begin(); + + cr_sema_wait(sema); + counter++; + cr_sema_signal(sema); + + cr_exit(); +} + +COROUTINE second_cr(void *_sema) { + cr_sema_t *sema = _sema; + cr_begin(); + + cr_sema_signal(sema); /* should be claimed by cr_first, which has been waiting */ + cr_sema_wait(sema); /* should block, because cr_first claimed it */ + test_assert(counter == 1); + + cr_exit(); +} + +COROUTINE producer_cr(void *_sema) { + cr_sema_t *sema = _sema; + cr_begin(); + + for (int i = 0; i < 10; i++) + cr_sema_signal(sema); + + cr_end(); +} + +COROUTINE consumer_cr(void *_sema) { + cr_sema_t *sema = _sema; + cr_begin(); + + for (int i = 0; i < 5; i++) + cr_sema_wait(sema); + + cr_end(); +} + +int main() { + cr_sema_t sema = {}; + + printf("== test 1 =========================================\n"); + coroutine_add("first", first_cr, &sema); + coroutine_add("second", second_cr, &sema); + coroutine_main(); + test_assert(sema.cnt == 0); + + printf("== test 2 =========================================\n"); + coroutine_add("consumer", consumer_cr, &sema); + coroutine_add("producer", producer_cr, &sema); + coroutine_main(); + coroutine_add("consumer", consumer_cr, &sema); + coroutine_main(); + test_assert(sema.cnt == 0); + + return 0; +} |