waiter: Don't rely on global variables to keep waiter state
[petitboot] / lib / waiter / waiter.c
1
2 #include <poll.h>
3 #include <string.h>
4 #include <assert.h>
5
6 #include <talloc/talloc.h>
7
8 #include "waiter.h"
9
10 struct waiter {
11         struct waitset  *set;
12         int             fd;
13         int             events;
14         waiter_cb       callback;
15         void            *arg;
16 };
17
18 struct waitset {
19         struct waiter   *waiters;
20         int             n_waiters;
21         struct pollfd   *pollfds;
22         int             n_pollfds;
23 };
24
25 struct waitset *waitset_create(void *ctx)
26 {
27         struct waitset *set = talloc_zero(ctx, struct waitset);
28         return set;
29 }
30
31 void waitset_destroy(struct waitset *set)
32 {
33         talloc_free(set);
34 }
35
36 struct waiter *waiter_register(struct waitset *set, int fd, int events,
37                 waiter_cb callback, void *arg)
38 {
39         struct waiter *waiters, *waiter;
40
41         waiters = talloc_realloc(set, set->waiters,
42                         struct waiter, set->n_waiters + 1);
43
44         if (!waiters)
45                 return NULL;
46
47         set->n_waiters++;
48         set->waiters = waiters;
49
50         waiter = &set->waiters[set->n_waiters - 1];
51
52         waiter->set = set;
53         waiter->fd = fd;
54         waiter->events = events;
55         waiter->callback = callback;
56         waiter->arg = arg;
57
58         return waiter;
59 }
60
61 void waiter_remove(struct waiter *waiter)
62 {
63         struct waitset *set = waiter->set;
64         int i;
65
66         i = waiter - set->waiters;
67         assert(i >= 0 && i < set->n_waiters);
68
69         set->n_waiters--;
70         memmove(&set->waiters[i], &set->waiters[i+1],
71                 (set->n_waiters - i) * sizeof(set->waiters[0]));
72
73         set->waiters = talloc_realloc(set->waiters, set->waiters, struct waiter,
74                         set->n_waiters);
75 }
76
77 int waiter_poll(struct waitset *set)
78 {
79         int i, rc;
80
81         if (set->n_waiters != set->n_pollfds) {
82                 set->pollfds = talloc_realloc(set, set->pollfds,
83                                 struct pollfd, set->n_waiters);
84                 set->n_pollfds = set->n_waiters;
85         }
86
87         for (i = 0; i < set->n_waiters; i++) {
88                 set->pollfds[i].fd = set->waiters[i].fd;
89                 set->pollfds[i].events = set->waiters[i].events;
90                 set->pollfds[i].revents = 0;
91         }
92
93         rc = poll(set->pollfds, set->n_waiters, -1);
94
95         if (rc <= 0)
96                 return rc;
97
98         for (i = 0; i < set->n_waiters; i++) {
99                 if (set->pollfds[i].revents) {
100                         rc = set->waiters[i].callback(set->waiters[i].arg);
101
102                         if (rc)
103                                 waiter_remove(&set->waiters[i]);
104                 }
105         }
106
107         return 0;
108 }