diff options
Diffstat (limited to 'libcr_ipc/chan.c')
-rw-r--r-- | libcr_ipc/chan.c | 40 |
1 files changed, 40 insertions, 0 deletions
diff --git a/libcr_ipc/chan.c b/libcr_ipc/chan.c new file mode 100644 index 0000000..7dd1132 --- /dev/null +++ b/libcr_ipc/chan.c @@ -0,0 +1,40 @@ +/* libcr_ipc/chan.c - Simple channels for libcr + * + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#include <libcr_ipc/chan.h> + +void _cr_chan_dequeue(void *_ch, size_t) { + struct _cr_chan *ch = _ch; + _cr_ipc_dll_pop_from_front(&ch->waiters); +} + +void _cr_chan_xfer(enum _cr_chan_waiter_typ self_typ, struct _cr_chan *ch, void *val_ptr, size_t val_size) { + assert(ch); + assert(val_ptr); + + if (ch->waiters.front && ch->waiter_typ != self_typ) { /* non-blocking fast-path */ + /* Copy. */ + struct _cr_chan_waiter *front = _cr_ipc_dll_node_cast(struct _cr_chan_waiter, ch->waiters.front); + if (self_typ == _CR_CHAN_SENDER) + memcpy(front->val_ptr, val_ptr, val_size); + else + memcpy(val_ptr, front->val_ptr, val_size); + cr_unpause(front->cid); + front->dequeue(front->dequeue_arg1, + front->dequeue_arg2); + cr_yield(); + } else { /* blocking slow-path */ + struct _cr_chan_waiter self = { + .cid = cr_getcid(), + .val_ptr = val_ptr, + .dequeue = _cr_chan_dequeue, + .dequeue_arg1 = ch, + }; + _cr_ipc_dll_push_to_rear(&ch->waiters, &self); + ch->waiter_typ = self_typ; + cr_pause_and_yield(); + } +} |