summaryrefslogtreecommitdiff
path: root/libcr_ipc/include
diff options
context:
space:
mode:
authorLuke T. Shumaker <lukeshu@lukeshu.com>2025-04-07 14:28:17 -0600
committerLuke T. Shumaker <lukeshu@lukeshu.com>2025-04-07 20:28:56 -0600
commita1a20d71f6d9f6b26893b0f2d641da47cd59e74e (patch)
treed6a692b3858f2c222dd8eeed371bf7ed4ec27db7 /libcr_ipc/include
parent4d5a8b2f99be5e04954c5067080d1725af8c0ae7 (diff)
libcr_ipc: Add waitgrouplukeshu/waitgroup
Diffstat (limited to 'libcr_ipc/include')
-rw-r--r--libcr_ipc/include/libcr_ipc/waitgroup.h65
1 files changed, 65 insertions, 0 deletions
diff --git a/libcr_ipc/include/libcr_ipc/waitgroup.h b/libcr_ipc/include/libcr_ipc/waitgroup.h
new file mode 100644
index 0000000..32369cf
--- /dev/null
+++ b/libcr_ipc/include/libcr_ipc/waitgroup.h
@@ -0,0 +1,65 @@
+/* libcr_ipc/waitgroup.h - Go-like WaitGroups for libcr
+ *
+ * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#ifndef _LIBCR_IPC_WAITGROUP_H_
+#define _LIBCR_IPC_WAITGROUP_H_
+
+#include <stdbool.h>
+
+#include <libmisc/private.h>
+
+#include <libcr_ipc/_linkedlist_pub.h>
+
+/**
+ * A cr_waitgroup_t is a fair read/write mutex.
+ *
+ * A waiting writer blocks any new readers; this ensures that the
+ * writer is able to eventually get the lock.
+ *
+ * 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 {
+ BEGIN_PRIVATE(LIBCR_IPC_WAITGROUP_H);
+ int count;
+ bool unpausing;
+ _cr_ipc_sll_root waiters;
+ END_PRIVATE(LIBCR_IPC_WAITGROUP_H);
+} cr_waitgroup_t;
+
+/**
+ * Add delta (which may be negative) to the counter. If the counter
+ * becomes zero, all cr_waitgroup_wait() are unblocked. The counter
+ * must not become negative.
+ *
+ * @runs_in coroutine
+ * @cr_pauses never
+ * @cr_yields never
+ */
+void cr_waitgroup_add(cr_waitgroup_t *wg, int delta);
+
+/**
+ * Like cr_waitgroup_add(), but for use from an interrupt handler.
+ *
+ * @runs_in intrhandler
+ */
+void cr_waitgroup_add_from_intrhandler(cr_waitgroup_t *wg, int delta);
+
+#define cr_waitgroup_done(WG) cr_waitgroup_add(WG, -1)
+#define cr_waitgroup_done_from_intrhandler(WG) cr_waitgroup_add_from_intrhandler(WG, -1)
+
+/**
+ * Wait until the counter becomes zero. If the counter is already zero, returns immediately.
+ *
+ * @runs_in coroutine
+ * @cr_pauses maybe
+ * @cr_yields maybe
+ */
+void cr_waitgroup_wait(cr_waitgroup_t *wg);
+
+#endif /* _LIBCR_IPC_WAITGROUP_H_ */