From cd0b080d638005bff762f1f8cae9a6c76648265b Mon Sep 17 00:00:00 2001
From: "Luke T. Shumaker" <lukeshu@lukeshu.com>
Date: Sun, 29 Sep 2024 12:14:45 -0600
Subject: tidy, s/sighandler/intrhandler/

---
 libcr_ipc/include/libcr_ipc/sema.h | 49 ++++++++++++++++++++++++++++----------
 1 file changed, 36 insertions(+), 13 deletions(-)

(limited to 'libcr_ipc')

diff --git a/libcr_ipc/include/libcr_ipc/sema.h b/libcr_ipc/include/libcr_ipc/sema.h
index 257c8d5..9fe3223 100644
--- a/libcr_ipc/include/libcr_ipc/sema.h
+++ b/libcr_ipc/include/libcr_ipc/sema.h
@@ -10,6 +10,10 @@
 #include <stdbool.h>
 #include <libcr_ipc/_common.h>
 
+/* Most of the complexity in this file is so that
+ * cr_sema_signal_from_intrhandler() can actually be safe when called
+ * in an interrupt handler.  */
+
 /**
  * A cr_sema_t is a fair unbounded[1] counting semaphore.
  *
@@ -20,18 +24,20 @@ typedef struct {
 
 	struct _cr_ipc_cid_fifo          waiters;
 	/* locked indicates that a call from within a coroutine is is
-	 * 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!  */
+	 * messing with ->waiters, so an interrupt 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 to ->waiters to be outside of the critical
+	 * section!  */
 	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.
+ * list.  Returns true if cr_getcid() was drained and we're not in an
+ * interrupt handler.
  */
-static inline bool _cr_sema_drain(cr_sema_t *sema) {
+static inline bool _cr_sema_drain(cr_sema_t *sema, bool in_intrhandler) {
 	assert(!sema->locked);
 	cid_t self = cr_getcid();
 
@@ -52,10 +58,14 @@ static inline bool _cr_sema_drain(cr_sema_t *sema) {
 			} 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);
+				if (in_intrhandler)
+					cr_unpause_from_intrhandler(cid);
+				else {
+					if (cid == self)
+						state = DRAINED_SELF;
+					else
+						cr_unpause(cid);
+				}
 			}
 		}
 		asm volatile ("":::"memory");
@@ -75,12 +85,25 @@ static inline bool _cr_sema_drain(cr_sema_t *sema) {
  *
  * @blocks never
  * @yields never
- * @run_in anywhere (coroutine, sighandler)
+ * @run_in coroutine
  */
 static inline void cr_sema_signal(cr_sema_t *sema)  {
 	sema->cnt++;
 	if (!sema->locked)
-		_cr_sema_drain(sema);
+		assert(!_cr_sema_drain(sema, false));
+}
+
+/**
+ * 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)  {
+	sema->cnt++;
+	if (!sema->locked)
+		assert(!_cr_sema_drain(sema, true));
 }
 
 /**
@@ -99,7 +122,7 @@ static inline void cr_sema_wait(cr_sema_t *sema) {
 	asm volatile ("":::"memory");
 	sema->locked = false;
 
-	if (_cr_sema_drain(sema))
+	if (_cr_sema_drain(sema, false))
 		/* DRAINED_SELF: (1) No need to pause+yield, (2) we
 		 * better have been the last item in the list!  */
 		assert(!self.next);
-- 
cgit v1.2.3-2-g168b