8 #include <talloc/talloc.h>
24 struct timeval timeout;
30 struct list_item list;
34 struct waiter **waiters;
38 struct timeval next_timeout;
40 /* These are kept consistent over each call to waiter_poll, as
41 * set->waiters may be updated (by waiters' callbacks calling
42 * waiter_register or waiter_remove) during iteration. */
43 struct pollfd *pollfds;
45 struct waiter **io_waiters;
47 struct waiter **time_waiters;
50 struct list free_list;
53 struct waitset *waitset_create(void *ctx)
55 struct waitset *set = talloc_zero(ctx, struct waitset);
56 list_init(&set->free_list);
60 void waitset_destroy(struct waitset *set)
65 static struct waiter *waiter_new(struct waitset *set)
67 struct waiter **waiters, *waiter;
69 waiter = talloc(set, struct waiter);
73 waiters = talloc_realloc(set, set->waiters,
74 struct waiter *, set->n_waiters + 1);
81 set->waiters_changed = true;
82 set->waiters = waiters;
85 set->waiters[set->n_waiters - 1] = waiter;
86 waiter->active = true;
90 struct waiter *waiter_register_io(struct waitset *set, int fd, int events,
91 waiter_cb callback, void *arg)
93 struct waiter *waiter = waiter_new(set);
95 waiter->type = WAITER_IO;
98 waiter->io.events = events;
99 waiter->callback = callback;
105 struct waiter *waiter_register_timeout(struct waitset *set, int delay_ms,
106 waiter_cb callback, void *arg)
108 struct waiter *waiter = waiter_new(set);
109 struct timeval now, delay;
111 delay.tv_sec = delay_ms / 1000;
112 delay.tv_usec = 1000 * (delay_ms % 1000);
114 gettimeofday(&now, NULL);
116 timeradd(&now, &delay, &waiter->timeout);
118 waiter->type = WAITER_TIME;
120 waiter->callback = callback;
126 void waiter_remove(struct waiter *waiter)
128 struct waitset *set = waiter->set;
131 for (i = 0; i < set->n_waiters; i++)
132 if (set->waiters[i] == waiter)
135 assert(i < set->n_waiters);
138 memmove(&set->waiters[i], &set->waiters[i+1],
139 (set->n_waiters - i) * sizeof(set->waiters[0]));
141 set->waiters = talloc_realloc(set, set->waiters,
142 struct waiter *, set->n_waiters);
143 set->waiters_changed = true;
145 waiter->active = false;
146 list_add(&set->free_list, &waiter->list);
149 static void update_waiters(struct waitset *set)
151 int n_io, n_time, i_io, i_time, i;
153 if (!set->waiters_changed)
158 for (i = 0; i < set->n_waiters; i++) {
159 if (set->waiters[i]->type == WAITER_IO)
161 else if (set->waiters[i]->type == WAITER_TIME)
165 /* realloc if counts have changed */
166 if (set->n_io_waiters != n_io) {
167 set->io_waiters = talloc_realloc(set, set->io_waiters,
168 struct waiter *, n_io);
169 set->pollfds = talloc_realloc(set, set->pollfds,
170 struct pollfd, n_io);
171 set->n_io_waiters = n_io;
173 if (set->n_time_waiters != n_time) {
174 set->time_waiters = talloc_realloc(set, set->time_waiters,
175 struct waiter *, n_time);
176 set->n_time_waiters = n_time;
182 timerclear(&set->next_timeout);
184 for (i = 0; i < set->n_waiters; i++) {
185 struct waiter *waiter = set->waiters[i];
187 /* IO waiters: copy to io_waiters, populate pollfds */
188 if (waiter->type == WAITER_IO) {
189 set->pollfds[i_io].fd = waiter->io.fd;
190 set->pollfds[i_io].events = waiter->io.events;
191 set->io_waiters[i_io] = waiter;
195 /* time waiters: copy to time_waiters, calculate next expiry */
196 if (waiter->type == WAITER_TIME) {
197 if (!timerisset(&set->next_timeout) ||
198 timercmp(&waiter->timeout,
199 &set->next_timeout, <))
200 set->next_timeout = waiter->timeout;
202 set->time_waiters[i_time] = waiter;
208 int waiter_poll(struct waitset *set)
210 struct timeval now, timeout;
211 struct waiter *waiter, *tmp;
215 /* If the waiters have been updated, we need to update our
219 if (timerisset(&set->next_timeout)) {
220 gettimeofday(&now, NULL);
221 timersub(&set->next_timeout, &now, &timeout);
222 timeout_ms = timeout.tv_sec * 1000 +
223 timeout.tv_usec / 1000;
231 rc = poll(set->pollfds, set->n_io_waiters, timeout_ms);
236 for (i = 0; i < set->n_io_waiters; i++) {
237 struct waiter *waiter = set->io_waiters[i];
242 if (!set->pollfds[i].revents)
244 rc = waiter->callback(waiter->arg);
247 waiter_remove(waiter);
250 if (set->n_time_waiters > 0)
251 gettimeofday(&now, NULL);
253 for (i = 0; i < set->n_time_waiters; i++) {
254 struct waiter *waiter = set->time_waiters[i];
259 if (timercmp(&waiter->timeout, &now, >))
262 waiter->callback(waiter->arg);
264 waiter_remove(waiter);
270 /* free any waiters that have been removed */
271 list_for_each_entry_safe(&set->free_list, waiter, tmp, list)
273 list_init(&set->free_list);