diff options
Diffstat (limited to 'libcr_ipc')
-rw-r--r-- | libcr_ipc/CMakeLists.txt | 1 | ||||
-rw-r--r-- | libcr_ipc/_linkedlist.c | 62 | ||||
-rw-r--r-- | libcr_ipc/_linkedlist.h | 51 | ||||
-rw-r--r-- | libcr_ipc/chan.c | 153 | ||||
-rw-r--r-- | libcr_ipc/include/libcr_ipc/_linkedlist_pub.h | 26 | ||||
-rw-r--r-- | libcr_ipc/include/libcr_ipc/chan.h | 240 | ||||
-rw-r--r-- | libcr_ipc/include/libcr_ipc/mutex.h | 7 | ||||
-rw-r--r-- | libcr_ipc/include/libcr_ipc/rpc.h | 186 | ||||
-rw-r--r-- | libcr_ipc/include/libcr_ipc/rwmutex.h | 11 | ||||
-rw-r--r-- | libcr_ipc/include/libcr_ipc/sema.h | 9 | ||||
-rw-r--r-- | libcr_ipc/mutex.c | 15 | ||||
-rw-r--r-- | libcr_ipc/rpc.c | 37 | ||||
-rw-r--r-- | libcr_ipc/rwmutex.c | 49 | ||||
-rw-r--r-- | libcr_ipc/sema.c | 28 | ||||
-rw-r--r-- | libcr_ipc/tests/test_chan.c | 18 | ||||
-rw-r--r-- | libcr_ipc/tests/test_mutex.c | 6 | ||||
-rw-r--r-- | libcr_ipc/tests/test_rpc.c | 24 | ||||
-rw-r--r-- | libcr_ipc/tests/test_select.c | 21 | ||||
-rw-r--r-- | libcr_ipc/tests/test_sema.c | 18 |
19 files changed, 392 insertions, 570 deletions
diff --git a/libcr_ipc/CMakeLists.txt b/libcr_ipc/CMakeLists.txt index bd72f54..60d3f2d 100644 --- a/libcr_ipc/CMakeLists.txt +++ b/libcr_ipc/CMakeLists.txt @@ -6,7 +6,6 @@ add_library(libcr_ipc INTERFACE) target_include_directories(libcr_ipc PUBLIC INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include) target_sources(libcr_ipc INTERFACE - _linkedlist.c chan.c mutex.c rpc.c diff --git a/libcr_ipc/_linkedlist.c b/libcr_ipc/_linkedlist.c deleted file mode 100644 index b27dba8..0000000 --- a/libcr_ipc/_linkedlist.c +++ /dev/null @@ -1,62 +0,0 @@ -/* libcr_ipc/_linkedlist.c - Common low-level linked lists for use in libcr_ipc - * - * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -#include <stddef.h> /* for NULL */ - -#include "_linkedlist.h" - -/* singly linked list *********************************************************/ - -void cr_ipc_sll_push_to_rear(_cr_ipc_sll_root *root, cr_ipc_sll_node *node) { - assert(root); - node->rear = NULL; - if (root->rear) - root->rear->rear = node; - else - root->front = node; - root->rear = node; -} - -void cr_ipc_sll_pop_from_front(_cr_ipc_sll_root *root) { - assert(root); - assert(root->front); - root->front = root->front->rear; - if (!root->front) - root->rear = NULL; -} - -/* doubly linked list *********************************************************/ - -void cr_ipc_dll_push_to_rear(_cr_ipc_dll_root *root, cr_ipc_dll_node *node) { - assert(root); - assert(node); - node->front = root->rear; - node->rear = NULL; - if (root->rear) - root->rear->rear = node; - else - root->front = node; - root->rear = node; -} - -void cr_ipc_dll_remove(_cr_ipc_dll_root *root, cr_ipc_dll_node *node) { - assert(root); - assert(node); - if (node->front) - node->front->rear = node->rear; - else - root->front = node->rear; - if (node->rear) - node->rear->front = node->front; - else - root->rear = node->front; -} - -void cr_ipc_dll_pop_from_front(_cr_ipc_dll_root *root) { - assert(root); - assert(root->front); - cr_ipc_dll_remove(root, root->front); -} diff --git a/libcr_ipc/_linkedlist.h b/libcr_ipc/_linkedlist.h deleted file mode 100644 index ab6d89e..0000000 --- a/libcr_ipc/_linkedlist.h +++ /dev/null @@ -1,51 +0,0 @@ -/* libcr_ipc/_linkedlist.h - Common low-level linked lists for use in libcr_ipc - * - * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -#ifndef _LIBCR_IPC__LINKEDLIST_H_ -#define _LIBCR_IPC__LINKEDLIST_H_ - -#include <libmisc/assert.h> - -#include <libcr_ipc/_linkedlist_pub.h> - -/* singly linked list *********************************************************/ - -typedef struct _cr_ipc_sll_node { - struct _cr_ipc_sll_node *rear; -} cr_ipc_sll_node; - -#define cr_ipc_sll_node_cast(node_typ, node_ptr) \ - ({ \ - static_assert(_Generic(node_ptr, cr_ipc_sll_node *: 1, default: 0), \ - "typeof("#node_ptr") != cr_ipc_sll_node *"); \ - assert(node_ptr); \ - static_assert(offsetof(node_typ, cr_ipc_sll_node) == 0); \ - ((node_typ*)(node_ptr)); \ - }) - -void cr_ipc_sll_push_to_rear(_cr_ipc_sll_root *root, cr_ipc_sll_node *node); -void cr_ipc_sll_pop_from_front(_cr_ipc_sll_root *root); - -/* doubly linked list *********************************************************/ - -typedef struct _cr_ipc_dll_node { - struct _cr_ipc_dll_node *front, *rear; -} cr_ipc_dll_node; - -#define cr_ipc_dll_node_cast(node_typ, node_ptr) \ - ({ \ - static_assert(_Generic(node_ptr, cr_ipc_dll_node *: 1, default: 0), \ - "typeof("#node_ptr") != cr_ipc_dll_node *"); \ - assert(node_ptr); \ - static_assert(offsetof(node_typ, cr_ipc_dll_node) == 0); \ - ((node_typ*)(node_ptr)); \ - }) - -void cr_ipc_dll_push_to_rear(_cr_ipc_dll_root *root, cr_ipc_dll_node *node); -void cr_ipc_dll_remove(_cr_ipc_dll_root *root, cr_ipc_dll_node *node); -void cr_ipc_dll_pop_from_front(_cr_ipc_dll_root *root); - -#endif /* _LIBCR_IPC__LINKEDLIST_H_ */ diff --git a/libcr_ipc/chan.c b/libcr_ipc/chan.c index 12d2ec2..b7ecfc8 100644 --- a/libcr_ipc/chan.c +++ b/libcr_ipc/chan.c @@ -4,62 +4,22 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ -#include <alloca.h> /* for alloca() */ #include <string.h> /* for memcpy() */ #include <libcr/coroutine.h> /* for cid_t, cr_* */ #include <libmisc/assert.h> #include <libmisc/rand.h> +#define IMPLEMENTATION_FOR_LIBCR_IPC_CHAN_H YES #include <libcr_ipc/chan.h> -#include "_linkedlist.h" - -/* base channels **************************************************************/ - -struct cr_chan_waiter { - cr_ipc_dll_node; +struct _cr_select_waiter { cid_t cid; - void *val_ptr; - void (*dequeue)(void *, size_t); - void *dequeue_arg1; - size_t dequeue_arg2; -}; - -void cr_chan_dequeue(void *_ch, size_t) { - struct _cr_chan *ch = _ch; - cr_ipc_dll_pop_from_front(&ch->waiters); -} - -void _cr_chan_xfer(enum _cr_chan_waiter_typ self_typ, struct _cr_chan *ch, void *val_ptr, size_t val_size) { - assert(ch); - assert(val_ptr); + struct _cr_select_arg_list_node *arg_vec; + size_t arg_cnt; - if (ch->waiters.front && ch->waiter_typ != self_typ) { /* non-blocking fast-path */ - /* Copy. */ - struct cr_chan_waiter *front = cr_ipc_dll_node_cast(struct cr_chan_waiter, ch->waiters.front); - if (self_typ == _CR_CHAN_SENDER) - memcpy(front->val_ptr, val_ptr, val_size); - else - memcpy(val_ptr, front->val_ptr, val_size); - cr_unpause(front->cid); - front->dequeue(front->dequeue_arg1, - front->dequeue_arg2); - cr_yield(); - } else { /* blocking slow-path */ - struct cr_chan_waiter self = { - .cid = cr_getcid(), - .val_ptr = val_ptr, - .dequeue = cr_chan_dequeue, - .dequeue_arg1 = ch, - }; - cr_ipc_dll_push_to_rear(&ch->waiters, &self); - ch->waiter_typ = self_typ; - cr_pause_and_yield(); - } -} - -/* select *********************************************************************/ + size_t ret; +}; enum cr_select_class { CR_SELECT_CLASS_DEFAULT, @@ -67,40 +27,26 @@ enum cr_select_class { CR_SELECT_CLASS_NONBLOCK, }; -struct cr_select_waiters { - size_t cnt; - struct cr_select_arg *args; - struct cr_chan_waiter *nodes; -}; - -static inline enum cr_select_class cr_select_getclass(struct cr_select_arg arg) { - switch (arg.op) { +static inline enum cr_select_class cr_select_getclass(struct _cr_select_arg *arg) { + switch (arg->op) { case _CR_SELECT_OP_RECV: - if (arg.ch->waiters.front && arg.ch->waiter_typ == _CR_CHAN_SENDER) + if (arg->ch->waiters.front && arg->ch->waiters.front->val.op == _CR_SELECT_OP_SEND) return CR_SELECT_CLASS_NONBLOCK; else return CR_SELECT_CLASS_BLOCKING; case _CR_SELECT_OP_SEND: - if (arg.ch->waiters.front && arg.ch->waiter_typ == _CR_CHAN_RECVER) + if (arg->ch->waiters.front && arg->ch->waiters.front->val.op == _CR_SELECT_OP_RECV) return CR_SELECT_CLASS_NONBLOCK; else return CR_SELECT_CLASS_BLOCKING; case _CR_SELECT_OP_DEFAULT: return CR_SELECT_CLASS_DEFAULT; default: - assert_notreached("invalid arg.op"); + assert_notreached("invalid arg->op"); } } -void cr_select_dequeue(void *_waiters, size_t idx) { - struct cr_select_waiters *waiters = _waiters; - for (size_t i = 0; i < waiters->cnt; i++) - cr_ipc_dll_remove(&(waiters->args[i].ch->waiters), - &(waiters->nodes[i])); - waiters->cnt = idx; -} - -size_t cr_select_v(size_t arg_cnt, struct cr_select_arg arg_vec[]) { +size_t cr_select_v(size_t arg_cnt, struct _cr_select_arg_list_node arg_vec[]) { size_t cnt_blocking = 0; size_t cnt_nonblock = 0; size_t cnt_default = 0; @@ -110,7 +56,7 @@ size_t cr_select_v(size_t arg_cnt, struct cr_select_arg arg_vec[]) { cr_assert_in_coroutine(); for (size_t i = 0; i < arg_cnt; i++) { - switch (cr_select_getclass(arg_vec[i])) { + switch (cr_select_getclass(&arg_vec[i].val)) { case CR_SELECT_CLASS_BLOCKING: cnt_blocking++; break; @@ -124,46 +70,65 @@ size_t cr_select_v(size_t arg_cnt, struct cr_select_arg arg_vec[]) { } if (cnt_nonblock) { - size_t choice = rand_uint63n(cnt_nonblock); - for (size_t i = 0, seen = 0; i < arg_cnt; i++) { - if (cr_select_getclass(arg_vec[i]) == CR_SELECT_CLASS_NONBLOCK) { - if (seen == choice) { - _cr_chan_xfer(arg_vec[i].op == _CR_SELECT_OP_RECV - ? _CR_CHAN_RECVER - : _CR_CHAN_SENDER, - arg_vec[i].ch, - arg_vec[i].val_ptr, - arg_vec[i].val_siz); - return i; - } + size_t choice_among_nonblock = rand_uint63n(cnt_nonblock); + size_t choice_among_all = arg_cnt; + for (size_t i = 0, seen = 0; i < choice_among_all; i++) { + if (cr_select_getclass(&arg_vec[i].val) == CR_SELECT_CLASS_NONBLOCK) { + if (seen == choice_among_nonblock) + choice_among_all = i; seen++; } } - assert_notreached("should have returned from inside for() loop"); + assert(choice_among_all < arg_cnt); + + struct _cr_select_arg *this = &arg_vec[choice_among_all].val; + assert(this->ch->waiters.front); + struct _cr_select_arg *other = &this->ch->waiters.front->val; + assert(this->val_siz == other->val_siz); + assert(this->ch == other->ch); + switch (this->op) { + case _CR_SELECT_OP_SEND: + assert(other->op == _CR_SELECT_OP_RECV); + memcpy(other->val_ptr, this->val_ptr, this->val_siz); + break; + case _CR_SELECT_OP_RECV: + assert(other->op == _CR_SELECT_OP_SEND); + memcpy(this->val_ptr, other->val_ptr, this->val_siz); + break; + case _CR_SELECT_OP_DEFAULT: + assert_notreached("_CR_SELECT_OP_DEFAULT is not CR_SELECT_CLASS_NONBLOCK"); + } + struct _cr_select_waiter *waiter = other->waiter; + for (size_t i = 0; i < waiter->arg_cnt; i++) { + waiter->arg_vec[i].val.ch->nwaiters--; + dlist_remove(&waiter->arg_vec[i].val.ch->waiters, &waiter->arg_vec[i]); + if (&waiter->arg_vec[i].val == other) + waiter->ret = i; + } + cr_unpause(waiter->cid); + cr_yield(); + return choice_among_all; } if (cnt_default) { for (size_t i = 0; i < arg_cnt; i++) - if (cr_select_getclass(arg_vec[i]) == CR_SELECT_CLASS_DEFAULT) + if (cr_select_getclass(&arg_vec[i].val) == CR_SELECT_CLASS_DEFAULT) return i; assert_notreached("should have returned from inside for() loop"); } - struct cr_select_waiters waiters = { - .cnt = arg_cnt, - .args = arg_vec, - .nodes = alloca(sizeof(struct cr_chan_waiter) * arg_cnt), + assert(cnt_blocking && cnt_blocking == arg_cnt); + + struct _cr_select_waiter waiter = { + .cid = cr_getcid(), + .arg_vec = arg_vec, + .arg_cnt = arg_cnt, }; for (size_t i = 0; i < arg_cnt; i++) { - waiters.nodes[i] = (struct cr_chan_waiter){ - .cid = cr_getcid(), - .val_ptr = arg_vec[i].val_ptr, - .dequeue = cr_select_dequeue, - .dequeue_arg1 = &waiters, - .dequeue_arg2 = i, - }; - cr_ipc_dll_push_to_rear(&arg_vec[i].ch->waiters, &waiters.nodes[i]); + arg_vec[i].val.waiter = &waiter; + arg_vec[i].val.ch->nwaiters++; + dlist_push_to_rear(&arg_vec[i].val.ch->waiters, &arg_vec[i]); } cr_pause_and_yield(); - return waiters.cnt; + return waiter.ret; } diff --git a/libcr_ipc/include/libcr_ipc/_linkedlist_pub.h b/libcr_ipc/include/libcr_ipc/_linkedlist_pub.h deleted file mode 100644 index 6719ba4..0000000 --- a/libcr_ipc/include/libcr_ipc/_linkedlist_pub.h +++ /dev/null @@ -1,26 +0,0 @@ -/* libcr_ipc/_linkedlist_pub.h - Common low-level linked lists for use in libcr_ipc - * - * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -#ifndef _LIBCR_IPC__LINKEDLIST_PUB_H_ -#define _LIBCR_IPC__LINKEDLIST_PUB_H_ - -/* singly linked list *********************************************************/ - -struct _cr_ipc_sll_node; - -typedef struct { - struct _cr_ipc_sll_node *front, *rear; -} _cr_ipc_sll_root; - -/* doubly linked list *********************************************************/ - -struct _cr_ipc_dll_node; - -typedef struct { - struct _cr_ipc_dll_node *front, *rear; -} _cr_ipc_dll_root; - -#endif /* _LIBCR_IPC__LINKEDLIST_PUB_H_ */ diff --git a/libcr_ipc/include/libcr_ipc/chan.h b/libcr_ipc/include/libcr_ipc/chan.h index ad311a0..c57979a 100644 --- a/libcr_ipc/include/libcr_ipc/chan.h +++ b/libcr_ipc/include/libcr_ipc/chan.h @@ -10,17 +10,13 @@ #include <stdbool.h> /* for bool */ #include <stddef.h> /* for size_t */ -#include <libmisc/macro.h> /* LM_CAT2_() */ - -#include <libcr_ipc/_linkedlist_pub.h> +#include <libmisc/linkedlist.h> /* for DLIST_DECLARE() */ +#include <libmisc/private.h> /* base channels **************************************************************/ /** - * CR_CHAN_DECLARE(NAME, VAL_T) declares the following type and - * methods: - * - * type: + * CR_CHAN_DECLARE(NAME, VAL_T) declares the following type: * * / ** * * A NAME##_t is a fair unbuffered channel that transports @@ -33,143 +29,163 @@ * * something from an interrupt handler. * * / * typedef ... NAME##_t; + */ +#define CR_CHAN_DECLARE(NAME, VAL_T) \ + typedef struct { \ + struct _cr_chan core; \ + VAL_T val_typ[0]; \ + } NAME##_t + +/** + * cr_chan_send(ch, val) sends `val` over `ch`. * - * methods: + * @runs_in coroutine + * @cr_pauses maybe + * @cr_yields always * - * / ** - * * NAME##_send(ch, val) sends `val` over `ch`. - * * - * * @runs_in coroutine - * * @cr_pauses maybe - * * @cr_yields always - * * / - * void NAME##_send(NAME##_t *ch, VAL_T val); + * void cr_chan_send(NAME##_t *ch, VAL_T val); + */ +#define cr_chan_send(CH, VAL) do { \ + typeof((CH)->val_typ[0]) _val_lvalue = VAL; \ + (void)cr_select_l(CR_SELECT_SEND(CH, &_val_lvalue)); \ +} while (0) + +/** + * cr_chan_recv(ch) reads and returns a value from ch. * - * / ** - * * NAME##_recv(ch) reads and returns a value from ch. - * * - * * @runs_in coroutine - * * @cr_pauses maybe - * * @cr_yields always - * * / - * VAL_T NAME##_recv(NAME##_t *ch); + * @runs_in coroutine + * @cr_pauses maybe + * @cr_yields always * - * / ** - * * NAME##_can_send(ch) returns whether NAME##_send(ch, val) - * * would run without pausing. - * * - * * @runs_in coroutine - * * @cr_pauses never - * * @cr_yields never - * * / - * bool NAME##_can_send(NAME##_t *ch); + * VAL_T cr_chan_recv(NAME##_T ch); + */ +#define cr_chan_recv(CH) ({ \ + typeof((CH)->val_typ[0]) _val_lvalue; \ + (void)cr_select_l(CR_SELECT_RECV(CH, &_val_lvalue)); \ + _val_lvalue; \ +}) + +/** + * cr_chan_can_send(ch) returns whether cr_chan_send(ch, val) would + * run without pausing. * - * / ** - * * NAME##_can_recv(ch) returns whether NAME##_recv(ch) would - * * return without pausing. - * * - * * @runs_in coroutine - * * @cr_pauses never - * * @cr_yields never - * * / - * NAME##_can_recv(NAME##_t *ch); + * @runs_in coroutine + * @cr_pauses never + * @cr_yields never + * + * bool cr_chan_can_send(NAME##_t *ch); */ -#define CR_CHAN_DECLARE(NAME, VAL_T) \ - typedef struct { \ - struct _cr_chan core; \ - VAL_T vals[0]; \ - } NAME##_t; \ - \ - static inline void NAME##_send(NAME##_t *ch, VAL_T val) { \ - cr_assert_in_coroutine(); \ - _cr_chan_xfer(_CR_CHAN_SENDER, &ch->core, &val, sizeof(val)); \ - } \ - \ - static inline VAL_T NAME##_recv(NAME##_t *ch) { \ - cr_assert_in_coroutine(); \ - VAL_T val; \ - _cr_chan_xfer(_CR_CHAN_RECVER, &ch->core, &val, sizeof(val)); \ - return val; \ - } \ - \ - static inline bool NAME##_can_send(NAME##_t *ch) { \ - cr_assert_in_coroutine(); \ - return ch->core.waiters.front && \ - ch->core.waiter_typ == _CR_CHAN_RECVER; \ - } \ - \ - static inline bool NAME##_can_recv(NAME##_t *ch) { \ - cr_assert_in_coroutine(); \ - return ch->core.waiters.front && \ - ch->core.waiter_typ == _CR_CHAN_SENDER; \ - } \ - \ - extern int LM_CAT2_(_CR_CHAN_FORCE_SEMICOLON_, __COUNTER__) - -enum _cr_chan_waiter_typ { - _CR_CHAN_SENDER, - _CR_CHAN_RECVER, -}; +#define cr_chan_can_send(CH) ({ \ + cr_assert_in_coroutine(); \ + (bool)((CH)->core.waiters.front && \ + (CH)->core.waiters.front->val.op == _CR_SELECT_OP_RECV); \ +}) + +/** + * cr_chan_can_recv(ch) returns whether cr_chan_recv(ch) would return + * without pausing. + * + * @runs_in coroutine + * @cr_pauses never + * @cr_yields never + * + * bool cr_chan_can_recv(NAME##_t *ch); + */ +#define cr_chan_can_recv(CH) ({ \ + cr_assert_in_coroutine(); \ + (bool)((CH)->core.waiters.front && \ + (CH)->core.waiters.front->val.op == _CR_SELECT_OP_SEND); \ +}) +/** + * cr_chan_num_waiters(ch) returns the number of coroutines currently + * blocked on the channel. + * + * @runs_in coroutine + * @cr_pauses never + * @cr_yields never + * + * size_t cr_chan_num_waiters(NAME##_t *ch); + */ +#define cr_chan_num_waiters(CH) ({ \ + cr_assert_in_coroutine(); \ + ((CH)->core.nwaiters); \ +}) + +DLIST_DECLARE(_cr_select_arg_list); struct _cr_chan { - enum _cr_chan_waiter_typ waiter_typ; - _cr_ipc_dll_root waiters; + struct _cr_select_arg_list waiters; + size_t nwaiters; }; -void _cr_chan_xfer(enum _cr_chan_waiter_typ self_typ, struct _cr_chan *ch, void *val_ptr, size_t val_size); - /* cr_select arguments ********************************************************/ /** * Do not populate cr_select_arg yourself; use the * CR_SELECT_{RECV,SEND,DEFAULT} macros. */ -struct cr_select_arg { +struct _cr_select_waiter; +struct _cr_select_arg { enum { _CR_SELECT_OP_RECV, _CR_SELECT_OP_SEND, _CR_SELECT_OP_DEFAULT, - } op; - struct _cr_chan *ch; - void *val_ptr; - size_t val_siz; + } op; + struct _cr_chan *ch; + void *val_ptr; + size_t val_siz; + BEGIN_PRIVATE(LIBCR_IPC_CHAN_H); + struct _cr_select_waiter *waiter; + END_PRIVATE(LIBCR_IPC_CHAN_H); }; +DLIST_DECLARE_NODE(_cr_select_arg_list, struct _cr_select_arg); +#define cr_select_arg _cr_select_arg_list_node + +#define CR_SELECT_RECV(CH, VALP) ((struct cr_select_arg){ .val = { \ + .op = _CR_SELECT_OP_RECV, \ + .ch = &((CH)->core), \ + /* The _valp temporary variable is to get the compiler to check that \ + * the types are compatible. */ \ + .val_ptr = ({ typeof((CH)->val_typ[0]) *_valp = VALP; _valp; }), \ + .val_siz = sizeof((CH)->val_typ[0]), \ +}}) -#define CR_SELECT_RECV(CH, VALP) \ - /* The _valp temporary variable is to get the compiler to check that \ - * the types are compatible. */ \ - ((struct cr_select_arg){ \ - .op = _CR_SELECT_OP_RECV, \ - .ch = &((CH)->core), \ - .val_ptr = ({ typeof((CH)->vals[0]) *_valp = VALP; _valp; }), \ - .val_siz = sizeof((CH)->vals[0]), \ - }) /* BUG: It's bogus that CR_SELECT_SEND takes VALP instead of VAL, but * since we need an address, taking VAL would introduce uncomfortable * questions about where VAL sits on the stack. */ -#define CR_SELECT_SEND(CH, VALP) \ - /* The _valp temporary variable is to get the compiler to check that \ - * the types are compatible. */ \ - ((struct cr_select_arg){ \ - .op = _CR_SELECT_OP_SEND, \ - .ch = &((CH)->core), \ - .val_ptr = ({ typeof((CH)->vals[0]) *_valp = VALP; _valp; }), \ - .val_siz = sizeof((CH)->vals[0]), \ - }) -#define CR_SELECT_DEFAULT \ - ((struct cr_select_arg){ \ - .op = _CR_SELECT_OP_DEFAULT, \ - }) +#define CR_SELECT_SEND(CH, VALP) ((struct cr_select_arg){ .val = { \ + .op = _CR_SELECT_OP_SEND, \ + .ch = &((CH)->core), \ + /* The _valp temporary variable is to get the compiler to check that \ + * the types are compatible. */ \ + .val_ptr = ({ typeof((CH)->val_typ[0]) *_valp = VALP; _valp; }), \ + .val_siz = sizeof((CH)->val_typ[0]), \ +}}) + +#define CR_SELECT_DEFAULT ((struct cr_select_arg){ .val = { \ + .op = _CR_SELECT_OP_DEFAULT, \ +}}) /* cr_select_v(arg_cnt, arg_vec) **********************************************/ +/** + * @runs_in coroutine + * @cr_pauses maybe + * @cr_yields always + */ size_t cr_select_v(size_t arg_cnt, struct cr_select_arg arg_vec[]); /* cr_select_l(arg1, arg2, arg3, ...) ******************************************/ -#define cr_select_l(...) ({ \ - struct cr_select_arg _cr_select_args[] = { __VA_ARGS__ }; \ - cr_select_v(sizeof(_cr_select_args)/sizeof(_cr_select_args[0])); \ +/** + * @runs_in coroutine + * @cr_pauses maybe + * @cr_yields always + */ +#define cr_select_l(...) ({ \ + struct cr_select_arg _cr_select_args[] = { __VA_ARGS__ }; \ + cr_select_v(sizeof(_cr_select_args)/sizeof(_cr_select_args[0]), \ + _cr_select_args); \ }) #endif /* _LIBCR_IPC_CHAN_H_ */ diff --git a/libcr_ipc/include/libcr_ipc/mutex.h b/libcr_ipc/include/libcr_ipc/mutex.h index ec40f5c..e5f43c8 100644 --- a/libcr_ipc/include/libcr_ipc/mutex.h +++ b/libcr_ipc/include/libcr_ipc/mutex.h @@ -9,9 +9,10 @@ #include <stdbool.h> /* for bool */ +#include <libmisc/linkedlist.h> /* for SLIST_DECLARE() */ #include <libmisc/private.h> -#include <libcr_ipc/_linkedlist_pub.h> +SLIST_DECLARE(_cr_mutex_waiter_list); /** * A cr_mutex_t is a fair mutex. @@ -23,8 +24,8 @@ */ typedef struct { BEGIN_PRIVATE(LIBCR_IPC_MUTEX_H); - bool locked; - _cr_ipc_sll_root waiters; + bool locked; + struct _cr_mutex_waiter_list waiters; END_PRIVATE(LIBCR_IPC_MUTEX_H); } cr_mutex_t; diff --git a/libcr_ipc/include/libcr_ipc/rpc.h b/libcr_ipc/include/libcr_ipc/rpc.h index 07ace95..bfa0a04 100644 --- a/libcr_ipc/include/libcr_ipc/rpc.h +++ b/libcr_ipc/include/libcr_ipc/rpc.h @@ -9,15 +9,10 @@ #include <stdbool.h> /* for bool */ -#include <libmisc/macro.h> /* for LM_CAT2_() */ - -#include <libcr_ipc/_linkedlist_pub.h> +#include <libmisc/linkedlist.h> /* for SLIST_DECLARE() */ /** - * CR_RPC_DECLARE(NAME, REQ_T, RESP_T) declares the following types - * and methods: - * - * type: + * CR_RPC_DECLARE(NAME, REQ_T, RESP_T) declares the following types: * * / ** * * A NAME##_t is a fair rpc-channel on which the requester submits a @@ -39,114 +34,109 @@ * * the response RESP_T to the correct requester. `REQ_T req` is the * * only public member. * typedef struct { REQ_T req; ... } NAME##_req_t; + */ +#define CR_RPC_DECLARE(NAME, REQ_T, RESP_T) \ + typedef struct { \ + REQ_T req; \ + \ + RESP_T *_resp; /* where to write resp to */ \ + cid_t _requester; \ + } NAME##_req_t; \ + \ + typedef struct { \ + struct _cr_rpc core; \ + NAME##_req_t handle_typ[0]; \ + } NAME##_t + +/* Methods for NAME##_t *******************************************************/ + +/** + * cr_rpc_send_req(ch, req) submits the `req` request over `ch` and + * returns the response. * - * methods: + * @runs_in coroutine + * @cr_pauses always + * @cr_yields always * - * / ** - * * NAME##_send_req(ch, req) submits the `req` request over `ch` and - * * returns the response. - * * - * * @runs_in coroutine - * * @cr_pauses always - * * @cr_yields always - * * / - * RESP_T NAME##_send_req(NAME##_t *ch, REQ_T req); + * RESP_T cr_rpc_send_req(NAME##_t *ch, REQ_T req); + */ +#define cr_rpc_send_req(CH, REQ) ({ \ + cr_assert_in_coroutine(); \ + typeof((CH)->handle_typ[0].req) _req_lvalue = REQ; \ + typeof(*(CH)->handle_typ[0]._resp) _resp_lvalue; \ + _cr_rpc_send_req(&(CH)->core, \ + &_req_lvalue, sizeof(_req_lvalue), \ + &_resp_lvalue); \ + _resp_lvalue; \ +}) + +/** + * cr_rpc_recv_req(ch) reads a request from ch, and returns a + * NAME##_req_t handle wrapping that request. * - * / ** - * * NAME##_recv_req(ch) reads a request from ch, and returns a - * * NAME##_req_t handle wrapping that request. - * * - * * @runs_in coroutine - * * @cr_pauses maybe - * * @cr_yields maybe - * * / - * NAME##_req_t NAME##_recv_req(NAME##_t *ch); + * @runs_in coroutine + * @cr_pauses maybe + * @cr_yields maybe * - * / ** - * * NAME##_can_recv_req(ch) returns whether NAME##_recv_req(ch) - * * would return without pausing. - * * - * * @runs_in coroutine - * * @cr_pauses never - * * @cr_yields never - * * / - * bool NAME##_can_recv_req(NAME##_t *ch); + * NAME##_req_t cr_rcp_recv_req(NAME##_t *ch); + */ +#define cr_rpc_recv_req(CH) ({ \ + cr_assert_in_coroutine(); \ + typeof((CH)->handle_typ[0]) ret; \ + _cr_rpc_recv_req(&(CH)->core, \ + &ret.req, sizeof(ret.req), \ + (void **)&ret._resp, \ + &ret._requester); \ + ret; \ +}) + +/** + * cr_rpc_can_recv_req(ch) returns whether NAME##_recv_req(ch) + * would return without pausing. * - * type: + * @runs_in coroutine + * @cr_pauses never + * @cr_yields never * - * / ** - * * A NAME##_req_t is a handle that wraps a REQ_T, and is a channel - * * that a response may be written to. - * * / - * typedef ... NAME##_req_t; + * bool cr_rpc_can_recv_req(NAME##_t *ch); + */ +#define cr_rpc_can_recv_req(CH) ({ \ + cr_assert_in_coroutine(); \ + (bool)((CH)->core.waiters.front && \ + (CH)->core.waiter_typ == _CR_RPC_REQUESTER); \ +}) + +/* Methods for NAME##_req_t ***************************************************/ + +/** + * cr_rpc_send_resp(req, resp) sends the given response to the given + * request. * - * methods: + * @runs_in coroutine + * @cr_pauses never + * @cr_yields always * - * / ** - * * cr_rpc_send_resp(req, resp) sends the given response to the given - * * request. - * * - * * @runs_in coroutine - * * @cr_pauses never - * * @cr_yields always - * * / - * void NAME##_send_resp(NAME##_req_t req, RESP_T resp); + * void cr_rpc_send_resp(NAME##_req_t req, RESP_T resp); */ -#define CR_RPC_DECLARE(NAME, REQ_T, RESP_T) \ - typedef struct { \ - REQ_T req; \ - \ - RESP_T *_resp; /* where to write resp to */ \ - cid_t _requester; \ - } NAME##_req_t; \ - \ - typedef struct { \ - struct _cr_rpc core; \ - NAME##_req_t handle[0]; \ - } NAME##_t; \ - \ - static inline RESP_T NAME##_send_req(NAME##_t *ch, REQ_T req) { \ - cr_assert_in_coroutine(); \ - RESP_T resp; \ - _cr_rpc_send_req(&ch->core, \ - &req, sizeof(req), \ - &resp); \ - return resp; \ - } \ - \ - static inline NAME##_req_t NAME##_recv_req(NAME##_t *ch) { \ - cr_assert_in_coroutine(); \ - NAME##_req_t ret; \ - _cr_rpc_recv_req(&ch->core, \ - &ret.req, sizeof(ret.req), \ - (void **)&ret._resp, \ - &ret._requester); \ - return ret; \ - } \ - \ - static inline bool NAME##_can_recv_req(NAME##_t *ch) { \ - cr_assert_in_coroutine(); \ - return ch->core.waiters.front && \ - ch->core.waiter_typ == _CR_RPC_REQUESTER; \ - } \ - \ - static inline void NAME##_send_resp(NAME##_req_t req, RESP_T resp) { \ - cr_assert_in_coroutine(); \ - *(req._resp) = resp; \ - cr_unpause(req._requester); \ - cr_yield(); \ - } \ - \ - extern int LM_CAT2_(_CR_RPC_FORCE_SEMICOLON_, __COUNTER__) +#define cr_rpc_send_resp(REQ, RESP) { \ + cr_assert_in_coroutine(); \ + *((REQ)._resp) = RESP; \ + cr_unpause(REQ._requester); \ + cr_yield(); \ +} while (0) + +/* Background details *********************************************************/ enum _cr_rpc_waiter_typ { _CR_RPC_REQUESTER, _CR_RPC_RESPONDER, }; +SLIST_DECLARE(_cr_rpc_waiter_list); + struct _cr_rpc { enum _cr_rpc_waiter_typ waiter_typ; - _cr_ipc_sll_root waiters; + struct _cr_rpc_waiter_list waiters; }; void _cr_rpc_send_req(struct _cr_rpc *ch, void *req_ptr, size_t req_size, void *resp_ptr); diff --git a/libcr_ipc/include/libcr_ipc/rwmutex.h b/libcr_ipc/include/libcr_ipc/rwmutex.h index 924acce..8ccae63 100644 --- a/libcr_ipc/include/libcr_ipc/rwmutex.h +++ b/libcr_ipc/include/libcr_ipc/rwmutex.h @@ -9,9 +9,10 @@ #include <stdbool.h> +#include <libmisc/linkedlist.h> /* for SLIST_DECLARE() */ #include <libmisc/private.h> -#include <libcr_ipc/_linkedlist_pub.h> +SLIST_DECLARE(_cr_rwmutex_waiter_list); /** * A cr_rwmutex_t is a fair read/write mutex. @@ -26,10 +27,10 @@ */ typedef struct { BEGIN_PRIVATE(LIBCR_IPC_RWMUTEX_H); - unsigned nreaders; - bool locked; - bool unpausing; - _cr_ipc_sll_root waiters; + unsigned nreaders; + bool locked; + bool unpausing; + struct _cr_rwmutex_waiter_list waiters; END_PRIVATE(LIBCR_IPC_RWMUTEX_H); } cr_rwmutex_t; diff --git a/libcr_ipc/include/libcr_ipc/sema.h b/libcr_ipc/include/libcr_ipc/sema.h index ae8d93d..8b5ac5b 100644 --- a/libcr_ipc/include/libcr_ipc/sema.h +++ b/libcr_ipc/include/libcr_ipc/sema.h @@ -9,9 +9,10 @@ #include <stdbool.h> +#include <libmisc/linkedlist.h> /* for SLIST_DECLARE() */ #include <libmisc/private.h> -#include <libcr_ipc/_linkedlist_pub.h> +SLIST_DECLARE(_cr_sema_waiter_list); /** * A cr_sema_t is a fair unbounded[1] counting semaphore. @@ -20,9 +21,9 @@ */ typedef struct { BEGIN_PRIVATE(LIBCR_IPC_SEMA_H); - unsigned int cnt; - bool unpausing; - _cr_ipc_sll_root waiters; + unsigned int cnt; + bool unpausing; + struct _cr_sema_waiter_list waiters; END_PRIVATE(LIBCR_IPC_SEMA_H); } cr_sema_t; diff --git a/libcr_ipc/mutex.c b/libcr_ipc/mutex.c index 28debba..1b4e626 100644 --- a/libcr_ipc/mutex.c +++ b/libcr_ipc/mutex.c @@ -5,16 +5,15 @@ */ #include <libcr/coroutine.h> /* for cid_t, cr_* */ +#include <libmisc/assert.h> #define IMPLEMENTATION_FOR_LIBCR_IPC_MUTEX_H YES #include <libcr_ipc/mutex.h> -#include "_linkedlist.h" - struct cr_mutex_waiter { - cr_ipc_sll_node; cid_t cid; }; +SLIST_DECLARE_NODE(_cr_mutex_waiter_list, struct cr_mutex_waiter); void cr_mutex_lock(cr_mutex_t *mu) { assert(mu); @@ -23,10 +22,10 @@ void cr_mutex_lock(cr_mutex_t *mu) { if (!mu->locked) /* non-blocking fast-path */ mu->locked = true; else { /* blocking slow-path */ - struct cr_mutex_waiter self = { + struct _cr_mutex_waiter_list_node self = { .val = { .cid = cr_getcid(), - }; - cr_ipc_sll_push_to_rear(&mu->waiters, &self); + }}; + slist_push_to_rear(&mu->waiters, &self); cr_pause_and_yield(); } assert(mu->locked); @@ -38,8 +37,8 @@ void cr_mutex_unlock(cr_mutex_t *mu) { assert(mu->locked); if (mu->waiters.front) { - cr_unpause(cr_ipc_sll_node_cast(struct cr_mutex_waiter, mu->waiters.front)->cid); - cr_ipc_sll_pop_from_front(&mu->waiters); + cr_unpause(mu->waiters.front->val.cid); + slist_pop_from_front(&mu->waiters); } else mu->locked = false; } diff --git a/libcr_ipc/rpc.c b/libcr_ipc/rpc.c index a648fde..fcf51ba 100644 --- a/libcr_ipc/rpc.c +++ b/libcr_ipc/rpc.c @@ -7,25 +7,26 @@ #include <string.h> /* for memcpy() */ #include <libcr/coroutine.h> /* for cid_t, cr_* */ +#include <libmisc/assert.h> #include <libcr_ipc/rpc.h> -#include "_linkedlist.h" - struct cr_rpc_requester { - cr_ipc_sll_node; cid_t cid; void *req_ptr; /* where to read req from */ void *resp_ptr; /* where to write resp to */ }; - struct cr_rpc_responder { - cr_ipc_sll_node; /* before enqueued | after dequeued */ /* -------------------+-------------------- */ cid_t cid; /* responder cid | requester cid */ void *ptr; /* where to write req | where to write resp */ }; +union cr_rpc_waiter { + struct cr_rpc_requester requester; + struct cr_rpc_responder responder; +}; +SLIST_DECLARE_NODE(_cr_rpc_waiter_list, union cr_rpc_waiter); void _cr_rpc_send_req(struct _cr_rpc *ch, void *req_ptr, size_t req_size, void *resp_ptr) { assert(ch); @@ -33,9 +34,8 @@ void _cr_rpc_send_req(struct _cr_rpc *ch, void *req_ptr, size_t req_size, void * assert(resp_ptr); if (ch->waiters.front && ch->waiter_typ != _CR_RPC_REQUESTER) { /* fast-path (still blocks) */ - struct cr_rpc_responder *responder = - cr_ipc_sll_node_cast(struct cr_rpc_responder, ch->waiters.front); - cr_ipc_sll_pop_from_front(&ch->waiters); + struct cr_rpc_responder *responder = &ch->waiters.front->val.responder; + slist_pop_from_front(&ch->waiters); /* Copy the req to the responder's stack. */ memcpy(responder->ptr, req_ptr, req_size); /* Notify the responder that we have done so. */ @@ -45,12 +45,12 @@ void _cr_rpc_send_req(struct _cr_rpc *ch, void *req_ptr, size_t req_size, void * /* Wait for the responder to set `*resp_ptr`. */ cr_pause_and_yield(); } else { /* blocking slow-path */ - struct cr_rpc_requester self = { + struct _cr_rpc_waiter_list_node self = { .val = { .requester = { .cid = cr_getcid(), .req_ptr = req_ptr, .resp_ptr = resp_ptr, - }; - cr_ipc_sll_push_to_rear(&ch->waiters, &self); + }}}; + slist_push_to_rear(&ch->waiters, &self); /* Wait for a responder to both copy our req and sed * `*resp_ptr`. */ cr_pause_and_yield(); @@ -64,22 +64,21 @@ void _cr_rpc_recv_req(struct _cr_rpc *ch, void *req_ptr, size_t req_size, void * assert(ret_requester); if (ch->waiters.front && ch->waiter_typ != _CR_RPC_RESPONDER) { /* non-blocking fast-path */ - struct cr_rpc_requester *requester = - cr_ipc_sll_node_cast(struct cr_rpc_requester, ch->waiters.front); - cr_ipc_sll_pop_from_front(&ch->waiters); + struct cr_rpc_requester *requester = &ch->waiters.front->val.requester; + slist_pop_from_front(&ch->waiters); memcpy(req_ptr, requester->req_ptr, req_size); *ret_requester = requester->cid; *ret_resp_ptr = requester->resp_ptr; } else { /* blocking slow-path */ - struct cr_rpc_responder self = { + struct _cr_rpc_waiter_list_node self = { .val = { .responder = { .cid = cr_getcid(), .ptr = req_ptr, - }; - cr_ipc_sll_push_to_rear(&ch->waiters, &self); + }}}; + slist_push_to_rear(&ch->waiters, &self); ch->waiter_typ = _CR_RPC_RESPONDER; cr_pause_and_yield(); - *ret_requester = self.cid; - *ret_resp_ptr = self.ptr; + *ret_requester = self.val.responder.cid; + *ret_resp_ptr = self.val.responder.ptr; } } diff --git a/libcr_ipc/rwmutex.c b/libcr_ipc/rwmutex.c index 04016d6..191b7fe 100644 --- a/libcr_ipc/rwmutex.c +++ b/libcr_ipc/rwmutex.c @@ -5,33 +5,32 @@ */ #include <libcr/coroutine.h> /* for cid_t, cr_* */ +#include <libmisc/assert.h> #define IMPLEMENTATION_FOR_LIBCR_IPC_RWMUTEX_H YES #include <libcr_ipc/rwmutex.h> -#include "_linkedlist.h" - struct cr_rwmutex_waiter { - cr_ipc_sll_node; bool is_reader; cid_t cid; }; +SLIST_DECLARE_NODE(_cr_rwmutex_waiter_list, struct cr_rwmutex_waiter); void cr_rwmutex_lock(cr_rwmutex_t *mu) { assert(mu); cr_assert_in_coroutine(); - struct cr_rwmutex_waiter self = { + struct _cr_rwmutex_waiter_list_node self = { .val = { .is_reader = false, .cid = cr_getcid(), - }; - cr_ipc_sll_push_to_rear(&mu->waiters, &self); - if (mu->waiters.front != &self.cr_ipc_sll_node || mu->locked) + }}; + slist_push_to_rear(&mu->waiters, &self); + if (mu->waiters.front != &self || mu->locked) cr_pause_and_yield(); - assert(mu->waiters.front == &self.cr_ipc_sll_node); + assert(mu->waiters.front == &self); /* We now hold the lock (and are mu->waiters.front). */ - cr_ipc_sll_pop_from_front(&mu->waiters); + slist_pop_from_front(&mu->waiters); assert(mu->nreaders == 0); mu->locked = true; mu->unpausing = false; @@ -41,25 +40,23 @@ void cr_rwmutex_rlock(cr_rwmutex_t *mu) { assert(mu); cr_assert_in_coroutine(); - struct cr_rwmutex_waiter self = { + struct _cr_rwmutex_waiter_list_node self = { .val = { .is_reader = true, .cid = cr_getcid(), - }; - cr_ipc_sll_push_to_rear(&mu->waiters, &self); - if (mu->waiters.front != &self.cr_ipc_sll_node || (mu->locked && mu->nreaders == 0)) + }}; + slist_push_to_rear(&mu->waiters, &self); + if (mu->waiters.front != &self || (mu->locked && mu->nreaders == 0)) cr_pause_and_yield(); - assert(mu->waiters.front == &self.cr_ipc_sll_node); + assert(mu->waiters.front == &self); /* We now hold the lock (and are mu->waiters.front). */ - cr_ipc_sll_pop_from_front(&mu->waiters); + slist_pop_from_front(&mu->waiters); mu->nreaders++; mu->locked = true; - struct cr_rwmutex_waiter *waiter = mu->waiters.front - ? cr_ipc_sll_node_cast(struct cr_rwmutex_waiter, mu->waiters.front) - : NULL; - if (waiter && waiter->is_reader) { + struct _cr_rwmutex_waiter_list_node *waiter = mu->waiters.front; + if (waiter && waiter->val.is_reader) { assert(mu->unpausing); - cr_unpause(waiter->cid); + cr_unpause(waiter->val.cid); } else { mu->unpausing = false; } @@ -73,10 +70,9 @@ void cr_rwmutex_unlock(cr_rwmutex_t *mu) { assert(mu->nreaders == 0); assert(!mu->unpausing); if (mu->waiters.front) { - struct cr_rwmutex_waiter *waiter = - cr_ipc_sll_node_cast(struct cr_rwmutex_waiter, mu->waiters.front); + struct _cr_rwmutex_waiter_list_node *waiter = mu->waiters.front; mu->unpausing = true; - cr_unpause(waiter->cid); + cr_unpause(waiter->val.cid); } else { mu->locked = false; } @@ -91,11 +87,10 @@ void cr_rwmutex_runlock(cr_rwmutex_t *mu) { mu->nreaders--; if (mu->nreaders == 0 && !mu->unpausing) { if (mu->waiters.front) { - struct cr_rwmutex_waiter *waiter = - cr_ipc_sll_node_cast(struct cr_rwmutex_waiter, mu->waiters.front); - assert(!waiter->is_reader); + struct _cr_rwmutex_waiter_list_node *waiter = mu->waiters.front; + assert(!waiter->val.is_reader); mu->unpausing = true; - cr_unpause(waiter->cid); + cr_unpause(waiter->val.cid); } else { mu->locked = false; } diff --git a/libcr_ipc/sema.c b/libcr_ipc/sema.c index 85add6c..f2ac9b6 100644 --- a/libcr_ipc/sema.c +++ b/libcr_ipc/sema.c @@ -5,16 +5,15 @@ */ #include <libcr/coroutine.h> /* for cid_t, cr_* */ +#include <libmisc/assert.h> #define IMPLEMENTATION_FOR_LIBCR_IPC_SEMA_H YES #include <libcr_ipc/sema.h> -#include "_linkedlist.h" - struct cr_sema_waiter { - cr_ipc_sll_node; - cid_t cid; + cid_t cid; }; +SLIST_DECLARE_NODE(_cr_sema_waiter_list, struct cr_sema_waiter); void cr_sema_signal(cr_sema_t *sema) { assert(sema); @@ -23,8 +22,7 @@ void cr_sema_signal(cr_sema_t *sema) { bool saved = cr_save_and_disable_interrupts(); sema->cnt++; if (sema->waiters.front && !sema->unpausing) { - cr_unpause( - cr_ipc_sll_node_cast(struct cr_sema_waiter, sema->waiters.front)->cid); + cr_unpause(sema->waiters.front->val.cid); sema->unpausing = true; } cr_restore_interrupts(saved); @@ -36,8 +34,7 @@ void cr_sema_signal_from_intrhandler(cr_sema_t *sema) { sema->cnt++; if (sema->waiters.front && !sema->unpausing) { - cr_unpause_from_intrhandler( - cr_ipc_sll_node_cast(struct cr_sema_waiter, sema->waiters.front)->cid); + cr_unpause_from_intrhandler(sema->waiters.front->val.cid); sema->unpausing = true; } } @@ -48,18 +45,17 @@ void cr_sema_wait(cr_sema_t *sema) { bool saved = cr_save_and_disable_interrupts(); - struct cr_sema_waiter self = { + struct _cr_sema_waiter_list_node self = { .val = { .cid = cr_getcid(), - }; - cr_ipc_sll_push_to_rear(&sema->waiters, &self); - if (sema->waiters.front != &self.cr_ipc_sll_node || !sema->cnt) + }}; + slist_push_to_rear(&sema->waiters, &self); + if (sema->waiters.front != &self || !sema->cnt) cr_pause_and_yield(); - assert(sema->waiters.front == &self.cr_ipc_sll_node && sema->cnt); - cr_ipc_sll_pop_from_front(&sema->waiters); + assert(sema->waiters.front == &self && sema->cnt); + slist_pop_from_front(&sema->waiters); sema->cnt--; if (sema->cnt && sema->waiters.front) - cr_unpause( - cr_ipc_sll_node_cast(struct cr_sema_waiter, sema->waiters.front)->cid); + cr_unpause(sema->waiters.front->val.cid); else sema->unpausing = false; cr_restore_interrupts(saved); diff --git a/libcr_ipc/tests/test_chan.c b/libcr_ipc/tests/test_chan.c index 9b6f018..4788dd4 100644 --- a/libcr_ipc/tests/test_chan.c +++ b/libcr_ipc/tests/test_chan.c @@ -11,30 +11,30 @@ CR_CHAN_DECLARE(intchan, int); -COROUTINE cr_producer(void *_ch) { +COROUTINE producer_cr(void *_ch) { intchan_t *ch = _ch; cr_begin(); - intchan_send(ch, 1); + cr_chan_send(ch, 1); - while (!intchan_can_send(ch)) + while (!cr_chan_can_send(ch)) cr_yield(); - intchan_send(ch, 2); + cr_chan_send(ch, 2); cr_end(); } -COROUTINE cr_consumer(void *_ch) { +COROUTINE consumer_cr(void *_ch) { int x; intchan_t *ch = _ch; cr_begin(); - x = intchan_recv(ch); + x = cr_chan_recv(ch); test_assert(x == 1); - x = intchan_recv(ch); + x = cr_chan_recv(ch); test_assert(x == 2); cr_end(); @@ -42,8 +42,8 @@ COROUTINE cr_consumer(void *_ch) { int main() { intchan_t ch = {0}; - coroutine_add("producer", cr_producer, &ch); - coroutine_add("consumer", cr_consumer, &ch); + 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 index 43714c9..d08315d 100644 --- a/libcr_ipc/tests/test_mutex.c +++ b/libcr_ipc/tests/test_mutex.c @@ -11,7 +11,7 @@ int counter = 0; -COROUTINE cr_worker(void *_mu) { +COROUTINE worker_cr(void *_mu) { cr_mutex_t *mu = _mu; cr_begin(); @@ -29,8 +29,8 @@ COROUTINE cr_worker(void *_mu) { int main() { cr_mutex_t mu = {}; - coroutine_add("a", cr_worker, &mu); - coroutine_add("b", cr_worker, &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 index 1e3c471..1461450 100644 --- a/libcr_ipc/tests/test_rpc.c +++ b/libcr_ipc/tests/test_rpc.c @@ -14,46 +14,46 @@ 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 cr_caller(void *_ch) { +COROUTINE caller_cr(void *_ch) { intrpc_t *ch = _ch; cr_begin(); - int resp = intrpc_send_req(ch, 1); + int resp = cr_rpc_send_req(ch, 1); test_assert(resp == 2); - resp = intrpc_send_req(ch, 3); + resp = cr_rpc_send_req(ch, 3); test_assert(resp == 4); cr_exit(); } -COROUTINE cr_worker1(void *_ch) { +COROUTINE worker1_cr(void *_ch) { intrpc_t *ch = _ch; cr_begin(); - intrpc_req_t req = intrpc_recv_req(ch); + intrpc_req_t req = cr_rpc_recv_req(ch); test_assert(req.req == 1); - intrpc_send_resp(req, 2); + cr_rpc_send_resp(req, 2); cr_exit(); } -COROUTINE cr_worker2(void *_ch) { +COROUTINE worker2_cr(void *_ch) { intrpc_t *ch = _ch; cr_begin(); - intrpc_req_t req = intrpc_recv_req(ch); + intrpc_req_t req = cr_rpc_recv_req(ch); test_assert(req.req == 3); - intrpc_send_resp(req, 4); + cr_rpc_send_resp(req, 4); cr_exit(); } int main() { intrpc_t ch = {0}; - coroutine_add("worker1", cr_worker1, &ch); - coroutine_add("caller", cr_caller, &ch); - coroutine_add("worker2", cr_worker2, &ch); + 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_select.c b/libcr_ipc/tests/test_select.c index 1db645b..9b5d117 100644 --- a/libcr_ipc/tests/test_select.c +++ b/libcr_ipc/tests/test_select.c @@ -14,7 +14,7 @@ CR_CHAN_DECLARE(intchan, int); intchan_t ch[10] = {0}; intchan_t fch = {0}; -COROUTINE cr_consumer(void *) { +COROUTINE consumer_cr(void *) { cr_begin(); struct cr_select_arg args[11]; @@ -53,27 +53,26 @@ COROUTINE cr_consumer(void *) { test_assert(ret_arg == 0); send = 890; - args[0] = CR_SELECT_SEND(&fch, &send); - args[1] = CR_SELECT_DEFAULT; - ret_arg = cr_select_v(2, args); + ret_arg = cr_select_l(CR_SELECT_SEND(&fch, &send), + CR_SELECT_DEFAULT); test_assert(ret_arg == 1); cr_end(); } -COROUTINE cr_producer(void *_n) { +COROUTINE producer_cr(void *_n) { int n = *(int *)_n; cr_begin(); - intchan_send(&ch[n], n); + cr_chan_send(&ch[n], n); cr_end(); } -COROUTINE cr_final(void *) { +COROUTINE final_cr(void *) { cr_begin(); - int ret = intchan_recv(&fch); + int ret = cr_chan_recv(&fch); printf("ret=%d\n", ret); test_assert(ret == 567); @@ -82,9 +81,9 @@ COROUTINE cr_final(void *) { int main() { for (int i = 0; i < 10; i++) - coroutine_add("producer", cr_producer, &i); - coroutine_add("consumer", cr_consumer, NULL); - coroutine_add("final", cr_final, NULL); + 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 index e5b22a5..435c01a 100644 --- a/libcr_ipc/tests/test_sema.c +++ b/libcr_ipc/tests/test_sema.c @@ -13,7 +13,7 @@ int counter = 0; -COROUTINE cr_first(void *_sema) { +COROUTINE first_cr(void *_sema) { cr_sema_t *sema = _sema; cr_begin(); @@ -24,7 +24,7 @@ COROUTINE cr_first(void *_sema) { cr_exit(); } -COROUTINE cr_second(void *_sema) { +COROUTINE second_cr(void *_sema) { cr_sema_t *sema = _sema; cr_begin(); @@ -35,7 +35,7 @@ COROUTINE cr_second(void *_sema) { cr_exit(); } -COROUTINE cr_producer(void *_sema) { +COROUTINE producer_cr(void *_sema) { cr_sema_t *sema = _sema; cr_begin(); @@ -45,7 +45,7 @@ COROUTINE cr_producer(void *_sema) { cr_end(); } -COROUTINE cr_consumer(void *_sema) { +COROUTINE consumer_cr(void *_sema) { cr_sema_t *sema = _sema; cr_begin(); @@ -59,16 +59,16 @@ int main() { cr_sema_t sema = {}; printf("== test 1 =========================================\n"); - coroutine_add("first", cr_first, &sema); - coroutine_add("second", cr_second, &sema); + 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", cr_consumer, &sema); - coroutine_add("producer", cr_producer, &sema); + coroutine_add("consumer", consumer_cr, &sema); + coroutine_add("producer", producer_cr, &sema); coroutine_main(); - coroutine_add("consumer", cr_consumer, &sema); + coroutine_add("consumer", consumer_cr, &sema); coroutine_main(); test_assert(sema.cnt == 0); |