]> git.ozlabs.org Git - petitboot/blob - lib/waiter/waiter.c
lib/waiter: allocate waiters separately from set->waiters
[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->waiters = waiters;
48         set->n_waiters++;
49
50         waiter = talloc(set->waiters, struct waiter);
51         if (!waiter)
52                 return NULL;
53
54         set->waiters[set->n_waiters - 1] = waiter;
55
56         waiter->set = set;
57         waiter->fd = fd;
58         waiter->events = events;
59         waiter->callback = callback;
60         waiter->arg = arg;
61
62         return waiter;
63 }
64
65 void waiter_remove(struct waiter *waiter)
66 {
67         struct waitset *set = waiter->set;
68         int i;
69
70         for (i = 0; i < set->n_waiters; i++)
71                 if (set->waiters[i] == waiter)
72                         break;
73
74         assert(i < set->n_waiters);
75
76         set->n_waiters--;
77         memmove(&set->waiters[i], &set->waiters[i+1],
78                 (set->n_waiters - i) * sizeof(set->waiters[0]));
79
80         set->waiters = talloc_realloc(set->waiters, set->waiters,
81                         struct waiter *, set->n_waiters);
82
83         talloc_free(waiter);
84 }
85
86 int waiter_poll(struct waitset *set)
87 {
88         int i, rc;
89
90         if (set->n_waiters != set->n_pollfds) {
91                 set->pollfds = talloc_realloc(set, set->pollfds,
92                                 struct pollfd, set->n_waiters);
93                 set->n_pollfds = set->n_waiters;
94         }
95
96         for (i = 0; i < set->n_waiters; i++) {
97                 set->pollfds[i].fd = set->waiters[i]->fd;
98                 set->pollfds[i].events = set->waiters[i]->events;
99                 set->pollfds[i].revents = 0;
100         }
101
102         rc = poll(set->pollfds, set->n_waiters, -1);
103
104         if (rc <= 0)
105                 return rc;
106
107         for (i = 0; i < set->n_waiters; i++) {
108                 if (set->pollfds[i].revents) {
109                         rc = set->waiters[i]->callback(set->waiters[i]->arg);
110
111                         if (rc)
112                                 waiter_remove(set->waiters[i]);
113                 }
114         }
115
116         return 0;
117 }