summaryrefslogtreecommitdiff
path: root/libcr_ipc/include
diff options
context:
space:
mode:
authorLuke T. Shumaker <lukeshu@lukeshu.com>2025-04-16 09:05:28 -0600
committerLuke T. Shumaker <lukeshu@lukeshu.com>2025-04-16 09:05:28 -0600
commit29ad1efc7c6de44a965db9f181165b72a9ef8ff1 (patch)
treee13794366a09d0480253076d458b413faa5680a5 /libcr_ipc/include
parent802ed1e3cd0252cafd1be2aada0addf4d3f7eb2e (diff)
parenta5061fa634af1e7011182e1c115151dd96af8393 (diff)
Merge branch 'lukeshu/9p-fix-flush'
Diffstat (limited to 'libcr_ipc/include')
-rw-r--r--libcr_ipc/include/libcr_ipc/chan.h110
1 files changed, 65 insertions, 45 deletions
diff --git a/libcr_ipc/include/libcr_ipc/chan.h b/libcr_ipc/include/libcr_ipc/chan.h
index 5a87643..853b4ad 100644
--- a/libcr_ipc/include/libcr_ipc/chan.h
+++ b/libcr_ipc/include/libcr_ipc/chan.h
@@ -11,6 +11,7 @@
#include <stddef.h> /* for size_t */
#include <libmisc/linkedlist.h> /* for DLIST_DECLARE() */
+#include <libmisc/private.h>
/* base channels **************************************************************/
@@ -44,11 +45,9 @@
*
* void cr_chan_send(NAME##_t *ch, VAL_T val);
*/
-#define cr_chan_send(CH, VAL) do { \
- cr_assert_in_coroutine(); \
- typeof((CH)->val_typ[0]) _val_lvalue = VAL; \
- _cr_chan_xfer(_CR_CHAN_SENDER, &(CH)->core, \
- &_val_lvalue, sizeof(_val_lvalue)); \
+#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)
/**
@@ -60,12 +59,10 @@
*
* VAL_T cr_chan_recv(NAME##_T ch);
*/
-#define cr_chan_recv(CH) ({ \
- cr_assert_in_coroutine(); \
- typeof((CH)->val_typ[0]) _val_lvalue; \
- _cr_chan_xfer(_CR_CHAN_RECVER, &(CH)->core, \
- &_val_lvalue, sizeof(_val_lvalue)); \
- _val_lvalue; \
+#define cr_chan_recv(CH) ({ \
+ typeof((CH)->val_typ[0]) _val_lvalue; \
+ (void)cr_select_l(CR_SELECT_RECV(CH, &_val_lvalue)); \
+ _val_lvalue; \
})
/**
@@ -78,10 +75,10 @@
*
* bool cr_chan_can_send(NAME##_t *ch);
*/
-#define cr_chan_can_send(CH) ({ \
- cr_assert_in_coroutine(); \
- (bool)((CH)->core.waiters.front && \
- (CH)->core.waiter_typ == _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); \
})
/**
@@ -94,78 +91,101 @@
*
* 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.waiter_typ == _CR_CHAN_SENDER); \
+#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); \
+})
-enum _cr_chan_waiter_typ {
- _CR_CHAN_SENDER,
- _CR_CHAN_RECVER,
-};
-
-DLIST_DECLARE(_cr_chan_waiter_list);
-
+DLIST_DECLARE(_cr_select_arg_list);
struct _cr_chan {
- enum _cr_chan_waiter_typ waiter_typ;
- struct _cr_chan_waiter_list 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){ \
+#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]), \
-})
+}})
/* 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) ((struct cr_select_arg){ \
+#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){ \
- .op = _CR_SELECT_OP_DEFAULT, \
-})
+#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_ */