summaryrefslogtreecommitdiffstats
path: root/lib/waiter
diff options
context:
space:
mode:
authorJeremy Kerr <jk@ozlabs.org>2013-07-10 15:50:43 +0800
committerGeoff Levand <geoff@infradead.org>2013-07-23 09:44:45 -0700
commit45c7385acbd1299cacfa5cc335ffa6a0f0523980 (patch)
tree3b82b5611556d352078373c04360b754ea5a845d /lib/waiter
parentd92fff7d8898acc1a56607fbb5a6897a70041344 (diff)
downloadpetitboot-45c7385acbd1299cacfa5cc335ffa6a0f0523980.zip
petitboot-45c7385acbd1299cacfa5cc335ffa6a0f0523980.tar.gz
lib/waiter: Defer free of removed waiters
We may end up calling remove()-d time waiters if the timeout expires as we're processing an IO waiter. Instead of freeing the waiter in waiter_remove, mark the waiter as inactive, and defer the free until the end of waiter_poll(). Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Diffstat (limited to 'lib/waiter')
-rw-r--r--lib/waiter/waiter.c30
1 files changed, 27 insertions, 3 deletions
diff --git a/lib/waiter/waiter.c b/lib/waiter/waiter.c
index 513ab60..89fa9cb 100644
--- a/lib/waiter/waiter.c
+++ b/lib/waiter/waiter.c
@@ -6,6 +6,7 @@
#include <sys/time.h>
#include <talloc/talloc.h>
+#include <list/list.h>
#include "waiter.h"
@@ -20,6 +21,9 @@ struct waiter {
struct timeval timeout;
waiter_cb callback;
void *arg;
+
+ bool active;
+ struct list_item list;
};
struct waitset {
@@ -38,11 +42,14 @@ 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;
}
@@ -72,6 +79,7 @@ static struct waiter *waiter_new(struct waitset *set)
set->n_waiters++;
set->waiters[set->n_waiters - 1] = waiter;
+ waiter->active = true;
return waiter;
}
@@ -130,7 +138,8 @@ void waiter_remove(struct waiter *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)
@@ -197,6 +206,7 @@ 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;
@@ -219,11 +229,14 @@ int waiter_poll(struct waitset *set)
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);
@@ -238,6 +251,9 @@ int waiter_poll(struct waitset *set)
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;
@@ -246,5 +262,13 @@ int waiter_poll(struct waitset *set)
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;
}
OpenPOWER on IntegriCloud