From 0b7bd5db8b2539d2e03b3a13b91ee6b21101460d Mon Sep 17 00:00:00 2001 From: "Luke T. Shumaker" Date: Tue, 24 Sep 2024 14:44:46 -0600 Subject: coroutine_rpc.h: Support multiple requesters --- coroutine_rpc.h | 53 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 18 deletions(-) (limited to 'coroutine_rpc.h') diff --git a/coroutine_rpc.h b/coroutine_rpc.h index b51445e..11d40d7 100644 --- a/coroutine_rpc.h +++ b/coroutine_rpc.h @@ -11,6 +11,8 @@ #ifndef _COROUTINE_RPC_H_ #define _COROUTINE_RPC_H_ +#include + #include "coroutine.h" /** @@ -18,15 +20,15 @@ * rcp-channel on which the requester submits a value of type `req_t` * and the responder responds with a value of type `resp_t`. * - * There must only ever be 1 concurrent writer and 1 concurrent - * reader. If you need 1:n, n:1, or m:n; then you should instead use a - * series of coroutine_chan.h. + * There may be multiple concurrent requesters, but only one + * concurrent responder. If you need multiple concurrent responders, + * set up a system of coroutine_chan.h channels. */ -#define cr_rpc_t(req_t, resp_t) struct { \ - cid_t requester; \ - cid_t responder; \ - req_t *req_p; \ - resp_t *resp_p; \ +#define cr_rpc_t(req_t, resp_t) struct { \ + cid_t requester, *tail_requester; \ + cid_t responder; \ + req_t *req_p; \ + resp_t *resp_p; \ } /* These "functions" are preprocessor macros instead of real C @@ -40,13 +42,29 @@ * Blocking: Always; until the responder has called both * cr_rpc_recv_req() and cr_rpc_send_resp(). */ -#define cr_rpc_req(ch, _resp_p, _req) do { \ - (ch)->requester = cr_getcid(); \ - (ch)->req_p = &(_req); \ - (ch)->resp_p = (_resp_p; \ - if ((ch)->responder != 0) \ - cr_unpause((ch)->responder); \ - cr_pause_and_yield(); \ +#define cr_rpc_req(ch, _resp_p, _req) do { \ + cid_t next = 0; \ + if ((ch)->requester) { \ + *((ch)->tail_requester = cr_getcid(); \ + (ch)->tail_requester = &next; \ + cr_pause_and_yield(); \ + } else { \ + (ch)->requester = cr_getcid(); \ + (ch)->tail_requester = &next; \ + } \ + assert((ch)->requester == cr_getcid()); \ + (ch)->req_p = &(_req); \ + (ch)->resp_p = (_resp_p; \ + if ((ch)->responder != 0) \ + cr_unpause((ch)->responder); \ + cr_pause_and_yield(); \ + if (next) { \ + (ch)->requester = next; \ + cr_unpause(next); \ + } else { \ + (ch)->requester = 0; \ + (ch)->tail_requester = NULL; \ + } } while (0) /** @@ -56,7 +74,7 @@ * * Blocking: Never. */ -#define cr_rpc_have_req(ch) ((ch)->requester != 0) +#define cr_rpc_have_req(ch) ((ch)->req_p != NULL) /** * cr_rpc_recv_req(cr_rpc_t(req_t, resp_t) *ch, req_t *req_p) reads @@ -81,11 +99,10 @@ * Blocking: Never. */ #define cr_rpc_send_resp(ch, _resp) do { \ - cr_unpause((ch)->requester); \ (ch)->responder = 0; \ - (ch)->requester = 0; \ *((ch)->resp_p) = (_resp); \ (ch)->resp_p = NULL; \ + cr_unpause((ch)->requester); \ } while (0) #endif /* _COROUTINE_RPC_H_ */ -- cgit v1.2.3-2-g168b