9 #include <talloc/talloc.h>
10 #include <list/list.h>
25 struct timeval timeout;
31 struct list_item list;
35 struct waiter **waiters;
39 struct timeval next_timeout;
41 /* These are kept consistent over each call to waiter_poll, as
42 * set->waiters may be updated (by waiters' callbacks calling
43 * waiter_register or waiter_remove) during iteration. */
44 struct pollfd *pollfds;
46 struct waiter **io_waiters;
48 struct waiter **time_waiters;
51 struct list free_list;
54 struct waitset *waitset_create(void *ctx)
56 struct waitset *set = talloc_zero(ctx, struct waitset);
57 list_init(&set->free_list);
61 static struct waiter *waiter_new(struct waitset *set)
63 struct waiter **waiters, *waiter;
65 waiter = talloc(set, struct waiter);
69 waiters = talloc_realloc(set, set->waiters,
70 struct waiter *, set->n_waiters + 1);
77 set->waiters_changed = true;
78 set->waiters = waiters;
81 set->waiters[set->n_waiters - 1] = waiter;
82 waiter->active = true;
86 struct waiter *waiter_register_io(struct waitset *set, int fd, int events,
87 waiter_cb callback, void *arg)
89 struct waiter *waiter = waiter_new(set);
91 waiter->type = WAITER_IO;
94 waiter->io.events = events;
95 waiter->callback = callback;
101 struct waiter *waiter_register_timeout(struct waitset *set, int delay_ms,
102 waiter_cb callback, void *arg)
104 struct waiter *waiter = waiter_new(set);
105 struct timeval now, delay;
107 delay.tv_sec = delay_ms / 1000;
108 delay.tv_usec = 1000 * (delay_ms % 1000);
110 gettimeofday(&now, NULL);
112 timeradd(&now, &delay, &waiter->timeout);
114 waiter->type = WAITER_TIME;
116 waiter->callback = callback;
122 void waiter_remove(struct waiter *waiter)
124 struct waitset *set = waiter->set;
127 for (i = 0; i < set->n_waiters; i++)
128 if (set->waiters[i] == waiter)
131 assert(i < set->n_waiters);
134 memmove(&set->waiters[i], &set->waiters[i+1],
135 (set->n_waiters - i) * sizeof(set->waiters[0]));
137 set->waiters = talloc_realloc(set, set->waiters,
138 struct waiter *, set->n_waiters);
139 set->waiters_changed = true;
141 waiter->active = false;
142 list_add(&set->free_list, &waiter->list);
145 static void update_waiters(struct waitset *set)
147 int n_io, n_time, i_io, i_time, i;
149 if (!set->waiters_changed)
154 for (i = 0; i < set->n_waiters; i++) {
155 if (set->waiters[i]->type == WAITER_IO)
157 else if (set->waiters[i]->type == WAITER_TIME)
161 /* realloc if counts have changed */
162 if (set->n_io_waiters != n_io) {
163 set->io_waiters = talloc_realloc(set, set->io_waiters,
164 struct waiter *, n_io);
165 set->pollfds = talloc_realloc(set, set->pollfds,
166 struct pollfd, n_io);
167 set->n_io_waiters = n_io;
169 if (set->n_time_waiters != n_time) {
170 set->time_waiters = talloc_realloc(set, set->time_waiters,
171 struct waiter *, n_time);
172 set->n_time_waiters = n_time;
178 timerclear(&set->next_timeout);
180 for (i = 0; i < set->n_waiters; i++) {
181 struct waiter *waiter = set->waiters[i];
183 /* IO waiters: copy to io_waiters, populate pollfds */
184 if (waiter->type == WAITER_IO) {
185 set->pollfds[i_io].fd = waiter->io.fd;
186 set->pollfds[i_io].events = waiter->io.events;
187 set->io_waiters[i_io] = waiter;
191 /* time waiters: copy to time_waiters, calculate next expiry */
192 if (waiter->type == WAITER_TIME) {
193 if (!timerisset(&set->next_timeout) ||
194 timercmp(&waiter->timeout,
195 &set->next_timeout, <))
196 set->next_timeout = waiter->timeout;
198 set->time_waiters[i_time] = waiter;
204 int waiter_poll(struct waitset *set)
206 struct timeval now, timeout;
207 struct waiter *waiter, *tmp;
211 /* If the waiters have been updated, we need to update our
215 if (timerisset(&set->next_timeout)) {
216 gettimeofday(&now, NULL);
217 timersub(&set->next_timeout, &now, &timeout);
218 timeout_ms = timeout.tv_sec * 1000 +
219 timeout.tv_usec / 1000;
226 rc = poll(set->pollfds, set->n_io_waiters, timeout_ms);
234 for (i = 0; i < set->n_io_waiters; i++) {
235 struct waiter *waiter = set->io_waiters[i];
240 if (!set->pollfds[i].revents)
242 rc = waiter->callback(waiter->arg);
245 waiter_remove(waiter);
248 if (set->n_time_waiters > 0)
249 gettimeofday(&now, NULL);
251 for (i = 0; i < set->n_time_waiters; i++) {
252 struct waiter *waiter = set->time_waiters[i];
257 if (timercmp(&waiter->timeout, &now, >))
260 waiter->callback(waiter->arg);
262 waiter_remove(waiter);
268 /* free any waiters that have been removed */
269 list_for_each_entry_safe(&set->free_list, waiter, tmp, list)
271 list_init(&set->free_list);