#include <sys/time.h>
#include <talloc/talloc.h>
+#include <list/list.h>
#include "waiter.h"
struct waiter {
+ struct waitset *set;
enum {
WAITER_IO,
WAITER_TIME,
- } type;
- struct waitset *set;
- int fd;
- int events;
- struct timeval timeout;
+ } type;
+ union {
+ struct {
+ int fd;
+ int events;
+ } io;
+ struct timeval timeout;
+ };
waiter_cb callback;
void *arg;
+
+ bool active;
+ struct list_item list;
};
struct waitset {
int n_io_waiters;
struct waiter **time_waiters;
int n_time_waiters;
+
+ struct list free_list;
};
struct waitset *waitset_create(void *ctx)
{
struct waitset *set = talloc_zero(ctx, struct waitset);
+ list_init(&set->free_list);
return set;
}
set->n_waiters++;
set->waiters[set->n_waiters - 1] = waiter;
+ waiter->active = true;
return waiter;
}
waiter->type = WAITER_IO;
waiter->set = set;
- waiter->fd = fd;
- waiter->events = events;
+ waiter->io.fd = fd;
+ waiter->io.events = events;
waiter->callback = callback;
waiter->arg = arg;
struct waiter *, set->n_waiters);
set->waiters_changed = true;
- talloc_free(waiter);
+ waiter->active = false;
+ list_add(&set->free_list, &waiter->list);
}
static void update_waiters(struct waitset *set)
if (waiter->type != WAITER_IO)
continue;
- set->pollfds[i_io].fd = waiter->fd;
- set->pollfds[i_io].events = waiter->events;
+ set->pollfds[i_io].fd = waiter->io.fd;
+ set->pollfds[i_io].events = waiter->io.events;
set->io_waiters[i_io] = waiter;
i_io++;
}
int waiter_poll(struct waitset *set)
{
struct timeval now, timeout;
+ struct waiter *waiter, *tmp;
int timeout_ms;
int i, rc;
rc = poll(set->pollfds, set->n_io_waiters, timeout_ms);
if (rc < 0)
- return rc;
+ goto out;
for (i = 0; i < set->n_io_waiters; i++) {
struct waiter *waiter = set->io_waiters[i];
+ if (!waiter->active)
+ continue;
+
if (!set->pollfds[i].revents)
continue;
rc = waiter->callback(waiter->arg);
for (i = 0; i < set->n_time_waiters; i++) {
struct waiter *waiter = set->time_waiters[i];
+ if (!waiter->active)
+ continue;
+
if (timercmp(&waiter->timeout, &now, >))
continue;
waiter_remove(waiter);
}
- return 0;
+ rc = 0;
+
+out:
+ /* free any waiters that have been removed */
+ list_for_each_entry_safe(&set->free_list, waiter, tmp, list)
+ talloc_free(waiter);
+ list_init(&set->free_list);
+
+ return rc;
}