8 #include <talloc/talloc.h>
20 struct timeval timeout;
26 struct waiter **waiters;
30 struct timeval next_timeout;
32 /* These are kept consistent over each call to waiter_poll, as
33 * set->waiters may be updated (by waiters' callbacks calling
34 * waiter_register or waiter_remove) during iteration. */
35 struct pollfd *pollfds;
37 struct waiter **io_waiters;
39 struct waiter **time_waiters;
43 struct waitset *waitset_create(void *ctx)
45 struct waitset *set = talloc_zero(ctx, struct waitset);
49 void waitset_destroy(struct waitset *set)
54 static struct waiter *waiter_new(struct waitset *set)
56 struct waiter **waiters, *waiter;
58 waiter = talloc(set->waiters, struct waiter);
62 waiters = talloc_realloc(set, set->waiters,
63 struct waiter *, set->n_waiters + 1);
70 set->waiters_changed = true;
71 set->waiters = waiters;
74 set->waiters[set->n_waiters - 1] = waiter;
78 struct waiter *waiter_register_io(struct waitset *set, int fd, int events,
79 waiter_cb callback, void *arg)
81 struct waiter *waiter = waiter_new(set);
83 waiter->type = WAITER_IO;
86 waiter->events = events;
87 waiter->callback = callback;
93 struct waiter *waiter_register_timeout(struct waitset *set, int delay_ms,
94 waiter_cb callback, void *arg)
96 struct waiter *waiter = waiter_new(set);
97 struct timeval now, delay;
99 delay.tv_sec = delay_ms / 1000;
100 delay.tv_usec = 1000 * (delay_ms % 1000);
102 gettimeofday(&now, NULL);
104 timeradd(&now, &delay, &waiter->timeout);
106 waiter->type = WAITER_TIME;
108 waiter->callback = callback;
114 void waiter_remove(struct waiter *waiter)
116 struct waitset *set = waiter->set;
119 for (i = 0; i < set->n_waiters; i++)
120 if (set->waiters[i] == waiter)
123 assert(i < set->n_waiters);
126 memmove(&set->waiters[i], &set->waiters[i+1],
127 (set->n_waiters - i) * sizeof(set->waiters[0]));
129 set->waiters = talloc_realloc(set->waiters, set->waiters,
130 struct waiter *, set->n_waiters);
131 set->waiters_changed = true;
136 static void update_waiters(struct waitset *set)
138 int n_io, n_time, i_io, i_time, i;
140 if (!set->waiters_changed)
145 for (i = 0; i < set->n_waiters; i++) {
146 if (set->waiters[i]->type == WAITER_IO)
148 else if (set->waiters[i]->type == WAITER_TIME)
152 /* realloc if counts have changed */
153 if (set->n_io_waiters != n_io) {
154 set->io_waiters = talloc_realloc(set, set->io_waiters,
155 struct waiter *, n_io);
156 set->pollfds = talloc_realloc(set, set->pollfds,
157 struct pollfd, n_io);
158 set->n_io_waiters = n_io;
160 if (set->n_time_waiters != n_time) {
161 set->time_waiters = talloc_realloc(set, set->time_waiters,
162 struct waiter *, n_time);
163 set->n_time_waiters = n_time;
166 /* IO waiters: copy to io_waiters, populate pollfds */
167 for (i = i_io = 0; i < set->n_waiters; i++) {
168 struct waiter *waiter = set->waiters[i];
170 if (waiter->type != WAITER_IO)
173 set->pollfds[i_io].fd = waiter->fd;
174 set->pollfds[i_io].events = waiter->events;
175 set->io_waiters[i_io] = waiter;
179 /* time waiters: copy to time_waiters, calculate next expiry */
180 timerclear(&set->next_timeout);
181 for (i = i_time = 0; i < set->n_waiters; i++) {
182 struct waiter *waiter = set->waiters[i];
184 if (waiter->type != WAITER_TIME)
187 if (!timerisset(&set->next_timeout) ||
188 timercmp(&waiter->timeout,
189 &set->next_timeout, <))
190 set->next_timeout = waiter->timeout;
192 set->time_waiters[i_time] = waiter;
197 int waiter_poll(struct waitset *set)
199 struct timeval now, timeout;
203 /* If the waiters have been updated, we need to update our
207 if (timerisset(&set->next_timeout)) {
208 gettimeofday(&now, NULL);
209 timersub(&set->next_timeout, &now, &timeout);
210 timeout_ms = timeout.tv_sec * 1000 +
211 timeout.tv_usec / 1000;
219 rc = poll(set->pollfds, set->n_io_waiters, timeout_ms);
224 for (i = 0; i < set->n_io_waiters; i++) {
225 struct waiter *waiter = set->io_waiters[i];
227 if (!set->pollfds[i].revents)
229 rc = waiter->callback(waiter->arg);
232 waiter_remove(waiter);
235 if (set->n_time_waiters > 0)
236 gettimeofday(&now, NULL);
238 for (i = 0; i < set->n_time_waiters; i++) {
239 struct waiter *waiter = set->time_waiters[i];
241 if (timercmp(&waiter->timeout, &now, >))
244 waiter->callback(waiter->arg);
246 waiter_remove(waiter);