summaryrefslogtreecommitdiff
path: root/libcr_ipc/chan.c
blob: 7dd11321168db399dbb2f297a273d54673649f40 (plain)
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();
	}
}