diff options
author | Luke T. Shumaker <lukeshu@lukeshu.com> | 2025-04-16 09:05:28 -0600 |
---|---|---|
committer | Luke T. Shumaker <lukeshu@lukeshu.com> | 2025-04-16 09:05:28 -0600 |
commit | 29ad1efc7c6de44a965db9f181165b72a9ef8ff1 (patch) | |
tree | e13794366a09d0480253076d458b413faa5680a5 /libcr_ipc/include | |
parent | 802ed1e3cd0252cafd1be2aada0addf4d3f7eb2e (diff) | |
parent | a5061fa634af1e7011182e1c115151dd96af8393 (diff) |
Merge branch 'lukeshu/9p-fix-flush'
Diffstat (limited to 'libcr_ipc/include')
-rw-r--r-- | libcr_ipc/include/libcr_ipc/chan.h | 110 |
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_ */ |