summaryrefslogtreecommitdiffstats
path: root/src/ifc.c
blob: 2dfafe840fe63d9f75bfe8eb5c43c7ac5a244bf5 (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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/* ifc.c - inter fiber communications
 *
 * Copyright (C) 2010 Timo Teräs <timo.teras@iki.fi>
 * All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 or later as
 * published by the Free Software Foundation.
 *
 * See http://www.gnu.org/ for details.
 */

#include <libtf/atomic.h>
#include <libtf/fiber.h>

void tf_ifc_queue(void *fiber, struct tf_ifc *ifc, tf_ifc_handler_t handler)
{
	struct tf_fiber *f = container_of(fiber, struct tf_fiber, data);
	struct tf_ifc *old;

	TF_BUG_ON(ifc->next != NULL);
	ifc->handler = handler;
	do {
		old = f->pending_ifc;
		ifc->next = old;
	} while (!tf_atomic_cmpxchg(&f->pending_ifc, old, ifc));

	tf_fiber_wakeup(f);
}

void tf_ifc_complete(void *fiber, struct tf_ifc *ifc, tf_ifc_handler_t handler)
{
	ifc->sender = tf_vmach_get_current_fiber();
	tf_ifc_queue(fiber, ifc, handler);
	while (ifc->sender != NULL)
		tf_fiber_schedule();
}

void tf_ifc_process_unordered(void)
{
	struct tf_fiber *f = tf_vmach_get_current_fiber(), *s;
	struct tf_ifc *pending, *ifc;

	while (f->pending_ifc != NULL) {
		pending = tf_atomic_xchg(&f->pending_ifc, NULL);
		while (pending) {
			ifc = pending;
			pending = ifc->next;
			ifc->handler(f->data, ifc);
			s = ifc->sender;
			ifc->next = NULL;
			ifc->sender = NULL;
			if (s != NULL)
				tf_fiber_wakeup(s);
		}
	}
}