#include <sys/time.h>
 
 #include <talloc/talloc.h>
+#include <list/list.h>
 
 #include "waiter.h"
 
        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;
 }
 
                        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)
 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;
 }