diff options
Diffstat (limited to 'libcr_ipc/include')
-rw-r--r-- | libcr_ipc/include/libcr_ipc/chan.h | 6 | ||||
-rw-r--r-- | libcr_ipc/include/libcr_ipc/mutex.h | 4 | ||||
-rw-r--r-- | libcr_ipc/include/libcr_ipc/owned_mutex.h | 79 | ||||
-rw-r--r-- | libcr_ipc/include/libcr_ipc/rpc.h | 6 | ||||
-rw-r--r-- | libcr_ipc/include/libcr_ipc/select.h | 1 | ||||
-rw-r--r-- | libcr_ipc/include/libcr_ipc/sema.h | 5 |
6 files changed, 97 insertions, 4 deletions
diff --git a/libcr_ipc/include/libcr_ipc/chan.h b/libcr_ipc/include/libcr_ipc/chan.h index 3c4095c..da4f08e 100644 --- a/libcr_ipc/include/libcr_ipc/chan.h +++ b/libcr_ipc/include/libcr_ipc/chan.h @@ -11,7 +11,7 @@ #include <stddef.h> /* for size_t */ #include <string.h> /* for memcpy */ -#include <libcr/coroutine.h> /* for cid_t, cr_unpause(), cr_pause_and_yield() */ +#include <libcr/coroutine.h> /* for cid_t, cr_* */ #include <libcr_ipc/_linkedlist.h> @@ -80,21 +80,25 @@ } NAME##_t; \ \ static inline void NAME##_send(NAME##_t *ch, VAL_T val) { \ + cr_assert_in_coroutine(); \ _cr_chan_xfer(_CR_CHAN_SENDER, &ch->core, &val, sizeof(val)); \ } \ \ static inline VAL_T NAME##_recv(NAME##_t *ch) { \ + cr_assert_in_coroutine(); \ VAL_T val; \ _cr_chan_xfer(_CR_CHAN_RECVER, &ch->core, &val, sizeof(val)); \ return val; \ } \ \ static inline bool NAME##_can_send(NAME##_t *ch) { \ + cr_assert_in_coroutine(); \ return ch->core.waiters.front && \ ch->core.waiter_typ == _CR_CHAN_RECVER; \ } \ \ static inline bool NAME##_can_recv(NAME##_t *ch) { \ + cr_assert_in_coroutine(); \ return ch->core.waiters.front && \ ch->core.waiter_typ == _CR_CHAN_SENDER; \ } diff --git a/libcr_ipc/include/libcr_ipc/mutex.h b/libcr_ipc/include/libcr_ipc/mutex.h index eee4f01..cba8c19 100644 --- a/libcr_ipc/include/libcr_ipc/mutex.h +++ b/libcr_ipc/include/libcr_ipc/mutex.h @@ -9,7 +9,7 @@ #include <stdbool.h> /* for bool */ -#include <libcr/coroutine.h> /* for cid_t, cr_unpause(), cr_pause_and_yield() */ +#include <libcr/coroutine.h> /* for cid_t, cr_* */ #include <libcr_ipc/_linkedlist.h> @@ -40,6 +40,7 @@ typedef struct { */ static inline void cr_mutex_lock(cr_mutex_t *mu) { assert(mu); + cr_assert_in_coroutine(); if (!mu->locked) /* non-blocking fast-path */ mu->locked = true; @@ -63,6 +64,7 @@ static inline void cr_mutex_lock(cr_mutex_t *mu) { */ static inline void cr_mutex_unlock(cr_mutex_t *mu) { assert(mu); + cr_assert_in_coroutine(); assert(mu->locked); if (mu->waiters.front) { diff --git a/libcr_ipc/include/libcr_ipc/owned_mutex.h b/libcr_ipc/include/libcr_ipc/owned_mutex.h new file mode 100644 index 0000000..c66240f --- /dev/null +++ b/libcr_ipc/include/libcr_ipc/owned_mutex.h @@ -0,0 +1,79 @@ +/* libcr_ipc/owned_mutex.h - Owned mutexes for libcr + * + * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#ifndef _LIBCR_IPC_OWNED_MUTEX_H_ +#define _LIBCR_IPC_OWNED_MUTEX_H_ + +#include <stdbool.h> /* for bool */ + +#include <libcr/coroutine.h> /* for cid_t, cr_unpause(), cr_pause_and_yield() */ + +#include <libcr_ipc/_linkedlist.h> + +struct _cr_owned_mutex_waiter { + _cr_ipc_sll_node; + cid_t cid; +}; + +/** + * A cr_owned_mutex_t is a fair mutex that tracks not just whether it + * is locked, but which coroutine has it locked. + * + * 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 { + cid_t owner; + _cr_ipc_sll_root waiters; +} cr_owned_mutex_t; + +/** + * Lock the mutex. Blocks if it is already locked. + * + * @runs_in coroutine + * @cr_pauses maybe + * @cr_yields maybe + */ +static inline void cr_owned_mutex_lock(cr_owned_mutex_t *mu) { + assert(mu); + + if (!mu->owner) /* non-blocking fast-path */ + mu->owner = cr_getcid(); + else { /* blocking slow-path */ + struct _cr_owned_mutex_waiter self = { + .cid = cr_getcid(), + }; + _cr_ipc_sll_push_to_rear(&mu->waiters, &self); + cr_pause_and_yield(); + } + assert(mu->owner == cr_getcid()); +} + +/** + * Unlock the mutex. Unblocks a coroutine that is blocked on + * cr_owned_mutex_lock(). Must be the called from the same coroutine + * that called cr_owned_mutex_lock(). + * + * @runs_in coroutine + * @cr_pauses never + * @cr_yields never + */ +static inline void cr_owned_mutex_unlock(cr_owned_mutex_t *mu) { + assert(mu); + + assert(mu->owner == cr_getcid()); + if (mu->waiters.front) { + cid_t waiter = _cr_ipc_sll_node_cast(struct _cr_owned_mutex_waiter, mu->waiters.front)->cid; + cr_unpause(waiter); + mu->owner = waiter; + _cr_ipc_sll_pop_from_front(&mu->waiters); + } else + mu->owner = 0; +} + +#endif /* _LIBCR_IPC_OWNED_MUTEX_H_ */ diff --git a/libcr_ipc/include/libcr_ipc/rpc.h b/libcr_ipc/include/libcr_ipc/rpc.h index 0d47514..0d6d25e 100644 --- a/libcr_ipc/include/libcr_ipc/rpc.h +++ b/libcr_ipc/include/libcr_ipc/rpc.h @@ -9,7 +9,7 @@ #include <stdbool.h> /* for bool */ -#include <libcr/coroutine.h> /* for cid_t, cr_unpause(), cr_pause_and_yield() */ +#include <libcr/coroutine.h> /* for cid_t, cr_* */ #include <libcr_ipc/_linkedlist.h> @@ -112,6 +112,7 @@ } NAME##_t; \ \ static inline RESP_T NAME##_send_req(NAME##_t *ch, REQ_T req) { \ + cr_assert_in_coroutine(); \ RESP_T resp; \ struct _##NAME##_waiting_req self = { \ .req = &req, \ @@ -126,6 +127,7 @@ } \ \ static inline NAME##_req_t NAME##_recv_req(NAME##_t *ch) { \ + cr_assert_in_coroutine(); \ if (!ch->waiting_reqs.front) { \ struct _##NAME##_waiting_resp self = { \ .cid = cr_getcid(), \ @@ -146,10 +148,12 @@ } \ \ static inline bool NAME##_can_recv_req(NAME##_t *ch) { \ + cr_assert_in_coroutine(); \ return ch->waiting_reqs.front != NULL; \ } \ \ static inline void NAME##_send_resp(NAME##_req_t req, RESP_T resp) { \ + cr_assert_in_coroutine(); \ *(req._resp) = resp; \ cr_unpause(req._requester); \ cr_yield(); \ diff --git a/libcr_ipc/include/libcr_ipc/select.h b/libcr_ipc/include/libcr_ipc/select.h index 788bf53..ee49cca 100644 --- a/libcr_ipc/include/libcr_ipc/select.h +++ b/libcr_ipc/include/libcr_ipc/select.h @@ -109,6 +109,7 @@ static size_t cr_select_v(size_t arg_cnt, struct cr_select_arg arg_vec[]) { assert(arg_cnt); assert(arg_vec); + cr_assert_in_coroutine(); for (size_t i = 0; i < arg_cnt; i++) { switch (_cr_select_getclass(arg_vec[i])) { diff --git a/libcr_ipc/include/libcr_ipc/sema.h b/libcr_ipc/include/libcr_ipc/sema.h index db840fe..1064182 100644 --- a/libcr_ipc/include/libcr_ipc/sema.h +++ b/libcr_ipc/include/libcr_ipc/sema.h @@ -7,7 +7,7 @@ #ifndef _LIBCR_IPC_SEMA_H_ #define _LIBCR_IPC_SEMA_H_ -#include <libcr/coroutine.h> /* for cid_t, cr_unpause(), cr_pause_and_yield() */ +#include <libcr/coroutine.h> /* for cid_t, cr_* */ #include <libcr_ipc/_linkedlist.h> @@ -35,6 +35,7 @@ typedef struct { */ static inline void cr_sema_signal(cr_sema_t *sema) { assert(sema); + cr_assert_in_coroutine(); bool saved = cr_save_and_disable_interrupts(); sema->cnt++; @@ -53,6 +54,7 @@ static inline void cr_sema_signal(cr_sema_t *sema) { */ static inline void cr_sema_signal_from_intrhandler(cr_sema_t *sema) { assert(sema); + cr_assert_in_intrhandler(); sema->cnt++; if (sema->waiters.front) { @@ -71,6 +73,7 @@ static inline void cr_sema_signal_from_intrhandler(cr_sema_t *sema) { */ static inline void cr_sema_wait(cr_sema_t *sema) { assert(sema); + cr_assert_in_coroutine(); bool saved = cr_save_and_disable_interrupts(); if (!sema->cnt) { |