diff options
-rw-r--r-- | libcr_ipc/include/libcr_ipc/_common.h | 2 | ||||
-rw-r--r-- | libcr_ipc/include/libcr_ipc/chan.h | 31 | ||||
-rw-r--r-- | libcr_ipc/include/libcr_ipc/mutex.h | 17 | ||||
-rw-r--r-- | libcr_ipc/include/libcr_ipc/rpc.h | 37 | ||||
-rw-r--r-- | libcr_ipc/include/libcr_ipc/sema.h | 16 |
5 files changed, 66 insertions, 37 deletions
diff --git a/libcr_ipc/include/libcr_ipc/_common.h b/libcr_ipc/include/libcr_ipc/_common.h index 247ba3d..8d7f656 100644 --- a/libcr_ipc/include/libcr_ipc/_common.h +++ b/libcr_ipc/include/libcr_ipc/_common.h @@ -1,4 +1,4 @@ -/* libcr_ipc/_common.h - TODO +/* libcr_ipc/_common.h - Common low-level utilities for use in libcr_ipc * * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-Licence-Identifier: AGPL-3.0-or-later diff --git a/libcr_ipc/include/libcr_ipc/chan.h b/libcr_ipc/include/libcr_ipc/chan.h index 4bb8f66..6e9865a 100644 --- a/libcr_ipc/include/libcr_ipc/chan.h +++ b/libcr_ipc/include/libcr_ipc/chan.h @@ -1,14 +1,9 @@ -/* coroutine_chan.h - Simple channel system for coroutine.{h,c} +/* libcr_ipc/chan.h - Simple channel system for libcr * * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-Licence-Identifier: AGPL-3.0-or-later */ -/** - * The cr_chan_* macros form a simple Go-like unbuffered channel - * mechanism built on top of the cr_pause_and_yeild() and cr_unpause() - * primitives. - */ #ifndef _COROUTINE_CHAN_H_ #define _COROUTINE_CHAN_H_ @@ -16,8 +11,12 @@ #include <libcr/coroutine.h> /** - * cr_chan_t(val_t) returns the type definition for a channel on - * that transports values of type `val_t`. + * cr_chan_t(val_t) is a simple unbuffered (Go-like) channel that + * transports values of type `val_t`. + * + * None of the methods have `_from_intrhandler` variants because + * either end of a channel may block, and interrupt handlers must not + * block. */ #define cr_chan_t(val_t) struct { \ bool ok_to_write; \ @@ -35,6 +34,10 @@ /** * ch_chan_send(*ch, val) sends `val` over `ch`. + * + * @runs_in coroutine + * @cr_pauses maybe + * @cr_yields maybe */ #define cr_chan_send(ch, _val) do { \ _cr_ipc_static_assert_sametype(_val, *(ch)->reader_val, \ @@ -73,6 +76,10 @@ /** * cr_chan_recv(ch, val_p) reads a value from ch into `*val_p`. + * + * @runs_in coroutine + * @cr_pauses maybe + * @cr_yields maybe */ #define cr_chan_recv(ch, _val_p) do { \ _cr_ipc_static_assert_sametype(_val_p, (ch)->reader_val, \ @@ -111,12 +118,20 @@ /** * cr_chan_can_send(ch) returns whether cr_chan_send(ch, val) would * run without blocking. + * + * @runs_in coroutine + * @cr_pauses never + * @cr_yields never */ #define cr_chan_can_send(ch) ((ch)->ok_to_write) /** * cr_chan_can_recv(ch) returns whether cr_chan_recv(ch, &val) would * run without blocking. + * + * @runs_in coroutine + * @cr_pauses never + * @cr_yields never */ #define cr_chan_can_recv(ch) ((ch)->ok_to_read) diff --git a/libcr_ipc/include/libcr_ipc/mutex.h b/libcr_ipc/include/libcr_ipc/mutex.h index 79424e3..01693cf 100644 --- a/libcr_ipc/include/libcr_ipc/mutex.h +++ b/libcr_ipc/include/libcr_ipc/mutex.h @@ -12,6 +12,11 @@ /** * A cr_mutex_t is a fair mutex. + * + * None of the methods have `_from_intrhandler` variants because (1) + * an interrupt handler can't block, so it shouldn't ever lock a mutex + * because that can block; and (2) if it can't lock a mutex in the + * first place, then it has no business unlocking one. */ typedef struct { bool locked; @@ -21,9 +26,9 @@ typedef struct { /** * Lock the mutex. Blocks if it is already locked. * - * @blocks maybe - * @yields maybe - * @run_in coroutine + * @runs_in coroutine + * @cr_pauses maybe + * @cr_yields maybe */ static inline void cr_mutex_lock(cr_mutex_t *mu) { assert(mu); @@ -40,9 +45,9 @@ static inline void cr_mutex_lock(cr_mutex_t *mu) { * Unlock the mutex. Unblocks a coroutine that is blocked on * cr_mutex_lock(). * - * @blocks never - * @yields never - * @may_run_in coroutine + * @runs_in coroutine + * @cr_pauses never + * @cr_yields never */ static inline void cr_mutex_unlock(cr_mutex_t *mu) { assert(mu); diff --git a/libcr_ipc/include/libcr_ipc/rpc.h b/libcr_ipc/include/libcr_ipc/rpc.h index abdb3b6..2351569 100644 --- a/libcr_ipc/include/libcr_ipc/rpc.h +++ b/libcr_ipc/include/libcr_ipc/rpc.h @@ -1,26 +1,27 @@ -/* coroutine_rpc.h - Simple request/response system for coroutine.{h,c} +/* libcr_ipc/rpc.h - Simple request/response system for libcr * * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-Licence-Identifier: AGPL-3.0-or-later */ -/** - * The cr_rpc_* macros form a simple request/response mechanism built - * on top of the cr_pause_and_yeild() and cr_unpause() primitives. - */ #ifndef _COROUTINE_RPC_H_ #define _COROUTINE_RPC_H_ #include <libcr_ipc/_common.h> /** - * cr_rpc_t(req_t, resp_t) returns the type definition for a + * cr_rpc_t(req_t, resp_t) evaluates to the type definition for a * 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 * concurrent responder. If you need multiple concurrent responders, - * set up a system of coroutine_chan.h channels. + * set up a system of <libcr_ipc/chan.h> channels. + * + * None of the methods have `_from_intrhandler` variants, because both + * ends may block, and interrupt handlers must not block. Perhaps you + * would be better served with a <libcr_ipc/sema.h> semaphore if you + * need to signal something from an interrupt handler. */ #define cr_rpc_t(req_t, resp_t) struct { \ cid_t requester, *tail_requester; \ @@ -31,14 +32,18 @@ /* 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*`. */ + * having these functions take `void*`. */ /** * ch_rpc_req(cr_rpc_t(req_t, resp_t) *ch, resp_t *resp, req_t req) * submits the `req` request to `ch` puts the response in `*resp_p`. * - * Blocking: Always; until the responder has called both - * cr_rpc_recv_req() and cr_rpc_send_resp(). + * Blocking: Always; until the + * + * @runs_in coroutine + * @cr_pauses always; until the responder has called both + * cr_rpc_recv_req() and cr_rpc_send_resp(). + * @cr_yields always */ #define cr_rpc_req(ch, _resp_p, _req) do { \ typeof(_req) _req_lvalue = _req; \ @@ -79,7 +84,9 @@ * to check whether or not there is a request waiting to be received * (with cr_rpc_recv_req()) without blocking if there is not. * - * Blocking: Never. + * @runs_in coroutine + * @cr_pauses never + * @cr_yields never */ #define cr_rpc_have_req(ch) ((ch)->req_p != NULL) @@ -89,7 +96,9 @@ * * If there is not a pending request on `ch`, blocks until there is. * - * Blocking: Maybe. + * @runs_in coroutine + * @cr_pauses maybe + * @cr_yields maybe */ #define cr_rpc_recv_req(ch, _req_p) do { \ _cr_ipc_static_assert_sametype(_req_p, (ch)->req_p, \ @@ -108,7 +117,9 @@ * cr_rpc_send_resp(cr_rpc_t(req_t, resp_t) *ch, resp_t resp) sends * the reply to the most-recently-read request. * - * Blocking: Never. + * @runs_in coroutine + * @cr_pauses never + * @cr_yields never */ #define cr_rpc_send_resp(ch, _resp) do { \ _cr_ipc_static_assert_sametype(_resp, *(ch)->resp_p, \ diff --git a/libcr_ipc/include/libcr_ipc/sema.h b/libcr_ipc/include/libcr_ipc/sema.h index 9fe3223..81787d6 100644 --- a/libcr_ipc/include/libcr_ipc/sema.h +++ b/libcr_ipc/include/libcr_ipc/sema.h @@ -17,7 +17,7 @@ /** * A cr_sema_t is a fair unbounded[1] counting semaphore. * - * [1]: Well, INT_MAX + * [1]: Well, UINT_MAX */ typedef struct { volatile int cnt; @@ -47,7 +47,7 @@ static inline bool _cr_sema_drain(cr_sema_t *sema, bool in_intrhandler) { DRAINED_ALL, /* stopped because sema->waiters is empty */ DRAINED_SOME, /* stopped because sema->cnt == 0 */ } state = DRAINING; - do { + do { sema->locked = true; asm volatile ("":::"memory"); while (state == DRAINING) { @@ -83,9 +83,9 @@ static inline bool _cr_sema_drain(cr_sema_t *sema, bool in_intrhandler) { /** * Increment the semaphore, * - * @blocks never - * @yields never * @run_in coroutine + * @cr_pauses never + * @cr_yields never */ static inline void cr_sema_signal(cr_sema_t *sema) { sema->cnt++; @@ -96,8 +96,6 @@ static inline void cr_sema_signal(cr_sema_t *sema) { /** * Like cr_sema_signal(), but safe to call from an interrupt handler. * - * @blocks never - * @yields never * @run_in intrhandler */ static inline void cr_sema_signal_from_intrhandler(cr_sema_t *sema) { @@ -109,9 +107,9 @@ static inline void cr_sema_signal_from_intrhandler(cr_sema_t *sema) { /** * Wait until the semaphore is >0, then decrement it. * - * @blocks maybe - * @yields maybe - * @may_run_in coroutine + * @run_in coroutine + * @cr_pauses maybe + * @cr_yields maybe */ static inline void cr_sema_wait(cr_sema_t *sema) { _cr_ipc_cid_fifo_self(self); |