summaryrefslogtreecommitdiff
path: root/libcr_ipc/include
diff options
context:
space:
mode:
authorLuke T. Shumaker <lukeshu@lukeshu.com>2024-09-29 10:56:18 -0600
committerLuke T. Shumaker <lukeshu@lukeshu.com>2024-09-29 10:56:18 -0600
commit7b34cb7741c683dc623ece652032f1bf09d34140 (patch)
treee131e4973f47bcfc93131c9eed7c78d4c614a4be /libcr_ipc/include
parentf54d6bfcc488b644926b962c230f8f12d0d65646 (diff)
wip fixes
Diffstat (limited to 'libcr_ipc/include')
-rw-r--r--libcr_ipc/include/libcr_ipc/_common.h41
-rw-r--r--libcr_ipc/include/libcr_ipc/chan.h1
-rw-r--r--libcr_ipc/include/libcr_ipc/mutex.h32
-rw-r--r--libcr_ipc/include/libcr_ipc/rpc.h6
-rw-r--r--libcr_ipc/include/libcr_ipc/sema.h89
5 files changed, 136 insertions, 33 deletions
diff --git a/libcr_ipc/include/libcr_ipc/_common.h b/libcr_ipc/include/libcr_ipc/_common.h
index 5efe964..547ab81 100644
--- a/libcr_ipc/include/libcr_ipc/_common.h
+++ b/libcr_ipc/include/libcr_ipc/_common.h
@@ -7,13 +7,46 @@
#ifndef _COROUTINE__COMMON_H_
#define _COROUTINE__COMMON_H_
-struct _cr_ipc_cid_list {
- cid_t val;
- struct _cr_ipc_cid_list *next;
-};
+#include <assert.h>
+
+#include <libcr/coroutine.h>
#define _cr_ipc_static_assert_sametype(a, b, msg) \
static_assert(_Generic(a, typeof(b): 1, default: 0), msg)
#define _cr_ipc_str(a) #a
+struct _cr_ipc_cid_fifo_node {
+ cid_t val;
+ struct _cr_ipc_cid_fifo_node *next;
+};
+
+struct _cr_ipc_cid_fifo {
+ struct _cr_ipc_cid_fifo_node *head, **tail;
+};
+
+
+#define _cr_ipc_cid_fifo_self(name) \
+ struct _cr_ipc_cid_fifo_node name = { \
+ .val = cr_getcid(), \
+ .next = NULL, \
+ }
+
+static inline void _cr_ipc_cid_fifo_push(struct _cr_ipc_cid_fifo *fifo, struct _cr_ipc_cid_fifo_node *self) {
+ if (!fifo->tail)
+ fifo->tail = &(fifo->head);
+ *(fifo->tail) = self;
+}
+
+static inline cid_t _cr_ipc_cid_fifo_pop(struct _cr_ipc_cid_fifo *fifo) {
+ if (!fifo->tail)
+ fifo->tail = &(fifo->head);
+ cid_t cid = 0;
+ if (fifo->head) {
+ cid = fifo->head->val;
+ if (!(( fifo->head = fifo->head->next )) )
+ fifo->tail = &(fifo->head);
+ }
+ return cid;
+}
+
#endif /* _COROUTINE__COMMON_H_ */
diff --git a/libcr_ipc/include/libcr_ipc/chan.h b/libcr_ipc/include/libcr_ipc/chan.h
index ca53fc2..4bb8f66 100644
--- a/libcr_ipc/include/libcr_ipc/chan.h
+++ b/libcr_ipc/include/libcr_ipc/chan.h
@@ -13,7 +13,6 @@
#define _COROUTINE_CHAN_H_
#include <assert.h>
-
#include <libcr/coroutine.h>
/**
diff --git a/libcr_ipc/include/libcr_ipc/mutex.h b/libcr_ipc/include/libcr_ipc/mutex.h
index 1a82423..79424e3 100644
--- a/libcr_ipc/include/libcr_ipc/mutex.h
+++ b/libcr_ipc/include/libcr_ipc/mutex.h
@@ -1,4 +1,4 @@
-/* libcr_ipc/mutex.h - Simple mutexes for libcr (header file)
+/* libcr_ipc/mutex.h - Simple mutexes for libcr
*
* Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-Licence-Identifier: AGPL-3.0-or-later
@@ -7,18 +7,15 @@
#ifndef _COROUTINE_MUTEX_H_
#define _COROUTINE_MUTEX_H_
-#include <stdbool.h> /* for bool */
-
-#include <libcr/coroutine.h> /* for cid_t */
-
-#include <libcr_ipc/_common.h> /* for struct _cr_ipc_list_t */
+#include <stdbool.h>
+#include <libcr_ipc/_common.h>
/**
* A cr_mutex_t is a fair mutex.
*/
typedef struct {
bool locked;
- struct _cr_ipc_cid_list *head, **tail;
+ struct _cr_ipc_cid_fifo waiters;
} cr_mutex_t;
/**
@@ -28,7 +25,16 @@ typedef struct {
* @yields maybe
* @run_in coroutine
*/
-void cr_mutex_lock(cr_mutex_t *);
+static inline void cr_mutex_lock(cr_mutex_t *mu) {
+ assert(mu);
+ if (!mu->locked) {
+ mu->locked = true;
+ return;
+ }
+ _cr_ipc_cid_fifo_self(self);
+ _cr_ipc_cid_fifo_push(&mu->waiters, &self);
+ cr_pause_and_yield();
+}
/**
* Unlock the mutex. Unblocks a coroutine that is blocked on
@@ -38,6 +44,14 @@ void cr_mutex_lock(cr_mutex_t *);
* @yields never
* @may_run_in coroutine
*/
-void cr_mutex_unlock(cr_mutex_t *);
+static inline void cr_mutex_unlock(cr_mutex_t *mu) {
+ assert(mu);
+ assert(mu->locked);
+ cid_t next = _cr_ipc_cid_fifo_pop(&mu->waiters);
+ if (next)
+ cr_unpause(next);
+ else
+ mu->locked = false;
+}
#endif /* _COROUTINE_MUTEX_H_ */
diff --git a/libcr_ipc/include/libcr_ipc/rpc.h b/libcr_ipc/include/libcr_ipc/rpc.h
index 2525ba8..abdb3b6 100644
--- a/libcr_ipc/include/libcr_ipc/rpc.h
+++ b/libcr_ipc/include/libcr_ipc/rpc.h
@@ -11,11 +11,7 @@
#ifndef _COROUTINE_RPC_H_
#define _COROUTINE_RPC_H_
-#include <assert.h>
-
-#include <libcr/coroutine.h>
-
-#include <libcr_ipc/_common.h> /* for _cr_ipc_* */
+#include <libcr_ipc/_common.h>
/**
* cr_rpc_t(req_t, resp_t) returns the type definition for a
diff --git a/libcr_ipc/include/libcr_ipc/sema.h b/libcr_ipc/include/libcr_ipc/sema.h
index 236e7e5..8d71c69 100644
--- a/libcr_ipc/include/libcr_ipc/sema.h
+++ b/libcr_ipc/include/libcr_ipc/sema.h
@@ -1,4 +1,4 @@
-/* libcr_ipc/sema.h - Simple semaphores for libcr (header file)
+/* libcr_ipc/sema.h - Simple semaphores for libcr
*
* Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-Licence-Identifier: AGPL-3.0-or-later
@@ -7,35 +7,81 @@
#ifndef _COROUTINE_SEMA_H_
#define _COROUTINE_SEMA_H_
-#include <stdbool.h> /* for bool */
-
-#include <libcr/coroutine.h> /* for cid_t */
-
-#include <libcr_ipc/_common.h> /* for struct _cr_ipc_list_t */
+#include <stdbool.h>
+#include <libcr_ipc/_common.h>
/**
* A cr_sema_t is a fair unbounded[1] counting semaphore.
*
* [1]: Well, INT_MAX
*/
-typedef volatile struct {
- int cnt;
+typedef struct {
+ volatile int cnt;
- struct _cr_ipc_cid_list *head, **tail;
+ struct _cr_ipc_cid_fifo waiters;
/* 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;
+ * messing with ->waiters, so a signal handler can't read it.
+ * Use `asm volatile ("":::"memory")` after setting =true and
+ * before setting =false to make sure the compiler doesn't
+ * re-order writes! */
+ volatile bool locked;
} cr_sema_t;
/**
+ * Drain a maximum of sema->cnt coroutines from the sema->waiters
+ * list. Returns true if cr_getcid() was drained.
+ */
+static inline bool _cr_sema_drain(cr_sema_t *sema) {
+ assert(!sema->locked);
+ cid_t self = cr_getcid();
+
+ enum drain_result {
+ DRAINING,
+ DRAINED_SELF, /* stopped because drained `self` */
+ DRAINED_ALL, /* stopped because sema->waiters is empty */
+ DRAINED_SOME, /* stopped because sema->cnt == 0 */
+ } state = DRAINING;
+ do {
+ sema->locked = true;
+ asm volatile ("":::"memory");
+ while (state == DRAINING) {
+ if (!sema->waiters.head) {
+ state = DRAINED_ALL;
+ } else if (!sema->cnt) {
+ state = DRAINED_SOME;
+ } else {
+ sema->cnt--;
+ cid_t cid = _cr_ipc_cid_fifo_pop(&sema->waiters);
+ if (cid == self)
+ state = DRAINED_SELF;
+ else
+ cr_unpause_from_sighandler(cid);
+ }
+ }
+ asm volatile ("":::"memory");
+ sema->locked = false;
+ /* If there are still coroutines in sema->waiters,
+ * check that sema->cnt wasn't incremented between `if
+ * (!sema->cnt)` and `sema->locked = false`. */
+ } 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->waiters.head);
+ return state == DRAINED_SELF;
+}
+
+/**
* Increment the semaphore,
*
* @blocks never
* @yields never
* @run_in anywhere (coroutine, sighandler)
*/
-void cr_sema_signal(cr_sema_t *sema);
+static inline void cr_sema_signal(cr_sema_t *sema) {
+ sema->cnt++;
+ if (!sema->locked)
+ _cr_sema_drain(sema);
+}
/**
* Wait until the semaphore is >0, then decrement it.
@@ -44,6 +90,21 @@ void cr_sema_signal(cr_sema_t *sema);
* @yields maybe
* @may_run_in coroutine
*/
-void cr_sema_wait(cr_sema_t *sema);
+static inline void cr_sema_wait(cr_sema_t *sema) {
+ _cr_ipc_cid_fifo_self(self);
+
+ sema->locked = true;
+ asm volatile ("":::"memory");
+ _cr_ipc_cid_fifo_push(&sema->waiters, &self);
+ asm volatile ("":::"memory");
+ sema->locked = false;
+
+ if (_cr_sema_drain(sema))
+ /* DRAINED_SELF: (1) No need to pause+yield, (2) we
+ * better have been the last item in the list! */
+ assert(!self.next);
+ else
+ cr_pause_and_yield();
+}
#endif /* _COROUTINE_SEMA_H_ */