summaryrefslogtreecommitdiff
path: root/libcr_ipc
diff options
context:
space:
mode:
Diffstat (limited to 'libcr_ipc')
-rw-r--r--libcr_ipc/CMakeLists.txt1
-rw-r--r--libcr_ipc/_linkedlist.c62
-rw-r--r--libcr_ipc/_linkedlist.h51
-rw-r--r--libcr_ipc/chan.c153
-rw-r--r--libcr_ipc/include/libcr_ipc/_linkedlist_pub.h26
-rw-r--r--libcr_ipc/include/libcr_ipc/chan.h240
-rw-r--r--libcr_ipc/include/libcr_ipc/mutex.h7
-rw-r--r--libcr_ipc/include/libcr_ipc/rpc.h186
-rw-r--r--libcr_ipc/include/libcr_ipc/rwmutex.h11
-rw-r--r--libcr_ipc/include/libcr_ipc/sema.h9
-rw-r--r--libcr_ipc/mutex.c15
-rw-r--r--libcr_ipc/rpc.c37
-rw-r--r--libcr_ipc/rwmutex.c49
-rw-r--r--libcr_ipc/sema.c28
-rw-r--r--libcr_ipc/tests/test_chan.c18
-rw-r--r--libcr_ipc/tests/test_mutex.c6
-rw-r--r--libcr_ipc/tests/test_rpc.c24
-rw-r--r--libcr_ipc/tests/test_select.c21
-rw-r--r--libcr_ipc/tests/test_sema.c18
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);