summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libcr_ipc/include/libcr_ipc/_common.h2
-rw-r--r--libcr_ipc/include/libcr_ipc/chan.h31
-rw-r--r--libcr_ipc/include/libcr_ipc/mutex.h17
-rw-r--r--libcr_ipc/include/libcr_ipc/rpc.h37
-rw-r--r--libcr_ipc/include/libcr_ipc/sema.h16
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);