/* libcr_ipc/waitgroup.c - Go-like WaitGroups for libcr * * Copyright (C) 2025 Luke T. Shumaker * SPDX-License-Identifier: AGPL-3.0-or-later */ #include /* for cid_t, cr_* */ #define IMPLEMENTATION_FOR_LIBCR_IPC_WAITGROUP_H YES #include #include "_linkedlist.h" struct cr_waitgroup_waiter { cr_ipc_sll_node; cid_t cid; }; void cr_waitgroup_wait(cr_waitgroup_t *wg) { assert(wg); cr_assert_in_coroutine(); struct cr_waitgroup_waiter self = { .cid = cr_getcid(), }; cr_ipc_sll_push_to_rear(&wg->waiters, &self); if (wg->waiters.front != &self.cr_ipc_sll_node || wg->count > 0) cr_pause_and_yield(); assert(wg->waiters.front == &self.cr_ipc_sll_node); cr_ipc_sll_pop_from_front(&wg->waiters); if (wg->waiters.front) { assert(wg->unpausing); cr_unpause(cr_ipc_sll_node_cast(struct cr_waitgroup_waiter, wg->waiters.front)->cid); } else { wg->unpausing = false; } } void cr_waitgroup_add(cr_waitgroup_t *wg, int delta) { assert(wg); cr_assert_in_coroutine(); if (delta == 0) return; bool saved = cr_save_and_disable_interrupts(); wg->count += delta; assert(wg->count >= 0); if (wg->count == 0 && !wg->unpausing && wg->waiters.front) { wg->unpausing = true; cr_unpause(cr_ipc_sll_node_cast(struct cr_waitgroup_waiter, wg->waiters.front)->cid); } cr_restore_interrupts(saved); } void cr_waitgroup_add_from_intrhandler(cr_waitgroup_t *wg, int delta) { assert(wg); cr_assert_in_intrhandler(); if (delta == 0) return; wg->count += delta; assert(wg->count >= 0); if (wg->count == 0 && !wg->unpausing && wg->waiters.front) { wg->unpausing = true; cr_unpause_from_intrhandler(cr_ipc_sll_node_cast(struct cr_waitgroup_waiter, wg->waiters.front)->cid); } }