/* libcr_ipc/sema.c - Simple semaphores for libcr * * Copyright (C) 2024-2025 Luke T. Shumaker * SPDX-License-Identifier: AGPL-3.0-or-later */ #include /* for cid_t, cr_* */ #define IMPLEMENTATION_FOR_LIBCR_IPC_SEMA_H YES #include struct cr_sema_waiter { lm_sll_node; cid_t cid; }; void cr_sema_signal(cr_sema_t *sema) { assert(sema); cr_assert_in_coroutine(); bool saved = cr_save_and_disable_interrupts(); sema->cnt++; if (sema->waiters.front && !sema->unpausing) { cr_unpause( lm_sll_node_cast(struct cr_sema_waiter, sema->waiters.front)->cid); sema->unpausing = true; } cr_restore_interrupts(saved); } void cr_sema_signal_from_intrhandler(cr_sema_t *sema) { assert(sema); cr_assert_in_intrhandler(); sema->cnt++; if (sema->waiters.front && !sema->unpausing) { cr_unpause_from_intrhandler( lm_sll_node_cast(struct cr_sema_waiter, sema->waiters.front)->cid); sema->unpausing = true; } } void cr_sema_wait(cr_sema_t *sema) { assert(sema); cr_assert_in_coroutine(); bool saved = cr_save_and_disable_interrupts(); struct cr_sema_waiter self = { .cid = cr_getcid(), }; lm_sll_push_to_rear(&sema->waiters, &self); if (sema->waiters.front != &self.lm_sll_node || !sema->cnt) cr_pause_and_yield(); assert(sema->waiters.front == &self.lm_sll_node && sema->cnt); lm_sll_pop_from_front(&sema->waiters); sema->cnt--; if (sema->cnt && sema->waiters.front) cr_unpause( lm_sll_node_cast(struct cr_sema_waiter, sema->waiters.front)->cid); else sema->unpausing = false; cr_restore_interrupts(saved); }