diff options
Diffstat (limited to 'libcr_ipc')
-rw-r--r-- | libcr_ipc/CMakeLists.txt | 3 | ||||
-rw-r--r-- | libcr_ipc/include/libcr_ipc/chan.h | 2 | ||||
-rw-r--r-- | libcr_ipc/include/libcr_ipc/rpc.h | 94 | ||||
-rw-r--r-- | libcr_ipc/include/libcr_ipc/sema.h | 15 | ||||
-rw-r--r-- | libcr_ipc/sema.c | 34 |
5 files changed, 85 insertions, 63 deletions
diff --git a/libcr_ipc/CMakeLists.txt b/libcr_ipc/CMakeLists.txt index b794908..3388fcd 100644 --- a/libcr_ipc/CMakeLists.txt +++ b/libcr_ipc/CMakeLists.txt @@ -8,3 +8,6 @@ target_include_directories(libcr_ipc SYSTEM INTERFACE ${CMAKE_CURRENT_LIST_DIR}/ target_sources(libcr_ipc INTERFACE sema.c ) +target_link_libraries(libcr_ipc INTERFACE + libcr +) diff --git a/libcr_ipc/include/libcr_ipc/chan.h b/libcr_ipc/include/libcr_ipc/chan.h index a3621a6..66ea1c4 100644 --- a/libcr_ipc/include/libcr_ipc/chan.h +++ b/libcr_ipc/include/libcr_ipc/chan.h @@ -14,7 +14,7 @@ #include <assert.h> -#include "coroutine.h" +#include <libcr/coroutine.h> /** * cr_chan_t(val_t) returns the type definition for a channel on diff --git a/libcr_ipc/include/libcr_ipc/rpc.h b/libcr_ipc/include/libcr_ipc/rpc.h index 11d40d7..3c42f34 100644 --- a/libcr_ipc/include/libcr_ipc/rpc.h +++ b/libcr_ipc/include/libcr_ipc/rpc.h @@ -13,11 +13,11 @@ #include <assert.h> -#include "coroutine.h" +#include <libcr/coroutine.h> /** * cr_rpc_t(req_t, resp_t) returns the type definition for a - * rcp-channel on which the requester submits a value of type `req_t` + * rpc-channel on which the requester submits a value of type `req_t` * and the responder responds with a value of type `resp_t`. * * There may be multiple concurrent requesters, but only one @@ -31,6 +31,10 @@ resp_t *resp_p; \ } +#define _cr_rpc_static_assert_sametype(a, b, msg) \ + static_assert(_Generic(a, typeof(b): 1, default: 0), msg) +#define _cr_rpc_str(a) #a + /* These "functions" are preprocessor macros instead of real C * functions so that the compiler can do type-checking instead of * having these functions take `void*`. */ @@ -42,29 +46,38 @@ * 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 { \ - 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; \ - } +#define cr_rpc_req(ch, _resp_p, _req) do { \ + typeof(_req) _req_lvalue = _req; \ + _cr_rpc_static_assert_sametype(_resp_p, (ch)->resp_p, \ + "wrong resp_p type for rpc chan: " \ + _cr_rpc_str(_resp_p)); \ + _cr_rpc_static_assert_sametype(&_req_lvalue, (ch)->req_p, \ + "wrong req type for rpc chan: " \ + _cr_rpc_str(_req)); \ + assert(ch); \ + assert(_resp_p); \ + 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_lvalue; \ + (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) /** @@ -84,12 +97,17 @@ * * Blocking: Maybe. */ -#define cr_rpc_recv_req(ch, _req_p) do { \ - (ch)->responder = cr_getcid(); \ - if ((ch)->requester == 0) \ - cr_pause_and_yield(); \ - *(_req_p) = *((ch)->req_p); \ - (ch)->req_p = NULL; \ +#define cr_rpc_recv_req(ch, _req_p) do { \ + _cr_rpc_static_assert_sametype(_req_p, (ch)->req_p, \ + "wrong req_p type for rpc chan: " \ + _cr_rpc_str(_req_p)); \ + assert(ch); \ + assert(_req_p); \ + (ch)->responder = cr_getcid(); \ + if ((ch)->requester == 0) \ + cr_pause_and_yield(); \ + *(_req_p) = *((ch)->req_p); \ + (ch)->req_p = NULL; \ } while (0) /** @@ -98,11 +116,15 @@ * * Blocking: Never. */ -#define cr_rpc_send_resp(ch, _resp) do { \ - (ch)->responder = 0; \ - *((ch)->resp_p) = (_resp); \ - (ch)->resp_p = NULL; \ - cr_unpause((ch)->requester); \ +#define cr_rpc_send_resp(ch, _resp) do { \ + _cr_rpc_static_assert_sametype(_resp, *(ch)->resp_p, \ + "wrong resp type for rpc chan: " \ + _cr_rpc_str(_reps)); \ + assert(ch); \ + (ch)->responder = 0; \ + *((ch)->resp_p) = (_resp); \ + (ch)->resp_p = NULL; \ + cr_unpause((ch)->requester); \ } while (0) #endif /* _COROUTINE_RPC_H_ */ diff --git a/libcr_ipc/include/libcr_ipc/sema.h b/libcr_ipc/include/libcr_ipc/sema.h index 57d5855..a2a176d 100644 --- a/libcr_ipc/include/libcr_ipc/sema.h +++ b/libcr_ipc/include/libcr_ipc/sema.h @@ -7,12 +7,25 @@ #ifndef _COROUTINE_SEMA_H_ #define _COROUTINE_SEMA_H_ +struct _cr_sema_cid_list { + cid_t val; + struct _cr_sema_cid_list *next; +}; + /** * A cr_sema_t is a fair unbounded[1] counting semaphore. * * [1]: Well, INT_MAX */ -typedef struct sema_t cr_sema_t; +typedef volatile struct { + int cnt; + + struct _cr_sema_cid_list *head, **tail; + /* locked indicates that a call from within a coroutine is is + * messing with ->{head,tail}, so a signal handler can't read + * it. */ + bool locked; +} cr_sema_t; /** * Increment the semaphore, diff --git a/libcr_ipc/sema.c b/libcr_ipc/sema.c index a8b5ec4..5f489aa 100644 --- a/libcr_ipc/sema.c +++ b/libcr_ipc/sema.c @@ -6,27 +6,11 @@ #include <assert.h> -#include "coroutine_sema.h" - -struct cid_list { - cid_t val; - struct cid_list *next; -}; - -/* head->next->next->tail */ - -struct _cr_sema { - int cnt; - - struct cid_list *head, **tail; - /* locked indicates that a call from within a coroutine is is - * messing with ->{head,tail}, so a signal handler can't read - * it. */ - bool locked; -}; +#include <libcr/coroutine.h> +#include <libcr_ipc/sema.h> /** Drain the sema->{head,tail} list. Returns true if cr_getcid() was drained. */ -static inline bool drain(volatile cr_sema_t *sema) { +static inline bool drain(cr_sema_t *sema) { assert(!sema->locked); cid_t self = cr_getcid(); @@ -59,21 +43,21 @@ static inline bool drain(volatile cr_sema_t *sema) { /* If there are still coroutines in sema->head, check * that sema->cnt wasn't incremented between `if * (!sema->cnt)` and `sema->locked = false`. */ - } while (state == DRAINED_SOME && cnt); + } while (state == DRAINED_SOME && sema->cnt); /* If state == DRAINED_SELF, then we better have been the last * item in the list! */ assert(state != DRAINED_SELF || !sema->head); return state == DRAINED_SELF; } -void cr_sema_signal(volatile cr_sema_t *sema) { +void cr_sema_signal(cr_sema_t *sema) { sema->cnt++; if (!sema->locked) - drain(); + drain(sema); } -void cr_sema_wait(volatile cr_sema_t *sema) { - struct cid_list self = { +void cr_sema_wait(cr_sema_t *sema) { + struct _cr_sema_cid_list self = { .val = cr_getcid(), .next = NULL, }; @@ -86,7 +70,7 @@ void cr_sema_wait(volatile cr_sema_t *sema) { sema->tail = &(self.next); sema->locked = false; - if (drain()) + if (drain(sema)) /* DRAINED_SELF: (1) No need to pause+yield, (2) we * better have been the last item in the list! */ assert(!self.next); |