1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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();
}
}
|