summaryrefslogtreecommitdiffstats
path: root/lib/waiter/waiter.c
blob: ac284366745121436e748cdd58af75fa48d58732 (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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108

#include <poll.h>
#include <string.h>
#include <assert.h>

#include <talloc/talloc.h>

#include "waiter.h"

struct waiter {
	struct waitset	*set;
	int		fd;
	int		events;
	waiter_cb	callback;
	void		*arg;
};

struct waitset {
	struct waiter	*waiters;
	int		n_waiters;
	struct pollfd	*pollfds;
	int		n_pollfds;
};

struct waitset *waitset_create(void *ctx)
{
	struct waitset *set = talloc_zero(ctx, struct waitset);
	return set;
}

void waitset_destroy(struct waitset *set)
{
	talloc_free(set);
}

struct waiter *waiter_register(struct waitset *set, int fd, int events,
		waiter_cb callback, void *arg)
{
	struct waiter *waiters, *waiter;

	waiters = talloc_realloc(set, set->waiters,
			struct waiter, set->n_waiters + 1);

	if (!waiters)
		return NULL;

	set->n_waiters++;
	set->waiters = waiters;

	waiter = &set->waiters[set->n_waiters - 1];

	waiter->set = set;
	waiter->fd = fd;
	waiter->events = events;
	waiter->callback = callback;
	waiter->arg = arg;

	return waiter;
}

void waiter_remove(struct waiter *waiter)
{
	struct waitset *set = waiter->set;
	int i;

	i = waiter - set->waiters;
	assert(i >= 0 && i < set->n_waiters);

	set->n_waiters--;
	memmove(&set->waiters[i], &set->waiters[i+1],
		(set->n_waiters - i) * sizeof(set->waiters[0]));

	set->waiters = talloc_realloc(set->waiters, set->waiters, struct waiter,
			set->n_waiters);
}

int waiter_poll(struct waitset *set)
{
	int i, rc;

	if (set->n_waiters != set->n_pollfds) {
		set->pollfds = talloc_realloc(set, set->pollfds,
				struct pollfd, set->n_waiters);
		set->n_pollfds = set->n_waiters;
	}

	for (i = 0; i < set->n_waiters; i++) {
		set->pollfds[i].fd = set->waiters[i].fd;
		set->pollfds[i].events = set->waiters[i].events;
		set->pollfds[i].revents = 0;
	}

	rc = poll(set->pollfds, set->n_waiters, -1);

	if (rc <= 0)
		return rc;

	for (i = 0; i < set->n_waiters; i++) {
		if (set->pollfds[i].revents) {
			rc = set->waiters[i].callback(set->waiters[i].arg);

			if (rc)
				waiter_remove(&set->waiters[i]);
		}
	}

	return 0;
}
OpenPOWER on IntegriCloud