X-Git-Url: https://git.ozlabs.org/?p=petitboot;a=blobdiff_plain;f=lib%2Fwaiter%2Fwaiter.c;h=13b0d68fc05ac6a32a03aea748377d0da03c226e;hp=513ab608af3a3115ec6a39d58a0645dee129cd56;hb=ba40c0ea7bedec01513537fd2dc3e0b75f439929;hpb=658d9e98eec02f92e3cf263a1bb27beb3d395b2f diff --git a/lib/waiter/waiter.c b/lib/waiter/waiter.c index 513ab60..13b0d68 100644 --- a/lib/waiter/waiter.c +++ b/lib/waiter/waiter.c @@ -6,20 +6,28 @@ #include #include +#include #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 { @@ -38,11 +46,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 +83,7 @@ static struct waiter *waiter_new(struct waitset *set) set->n_waiters++; set->waiters[set->n_waiters - 1] = waiter; + waiter->active = true; return waiter; } @@ -82,8 +94,8 @@ struct waiter *waiter_register_io(struct waitset *set, int fd, int events, 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; @@ -126,11 +138,12 @@ void waiter_remove(struct waiter *waiter) memmove(&set->waiters[i], &set->waiters[i+1], (set->n_waiters - i) * sizeof(set->waiters[0])); - set->waiters = talloc_realloc(set->waiters, set->waiters, + set->waiters = talloc_realloc(set, set->waiters, 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) @@ -163,40 +176,39 @@ static void update_waiters(struct waitset *set) set->n_time_waiters = n_time; } - /* IO waiters: copy to io_waiters, populate pollfds */ - for (i = i_io = 0; i < set->n_waiters; i++) { - struct waiter *waiter = set->waiters[i]; + i_io = 0; + i_time = 0; - if (waiter->type != WAITER_IO) - continue; - - set->pollfds[i_io].fd = waiter->fd; - set->pollfds[i_io].events = waiter->events; - set->io_waiters[i_io] = waiter; - i_io++; - } - - /* time waiters: copy to time_waiters, calculate next expiry */ timerclear(&set->next_timeout); - for (i = i_time = 0; i < set->n_waiters; i++) { - struct waiter *waiter = set->waiters[i]; - if (waiter->type != WAITER_TIME) - continue; - - if (!timerisset(&set->next_timeout) || - timercmp(&waiter->timeout, - &set->next_timeout, <)) - set->next_timeout = waiter->timeout; + for (i = 0; i < set->n_waiters; i++) { + struct waiter *waiter = set->waiters[i]; - set->time_waiters[i_time] = waiter; - i_time++; + /* IO waiters: copy to io_waiters, populate pollfds */ + if (waiter->type == WAITER_IO) { + set->pollfds[i_io].fd = waiter->io.fd; + set->pollfds[i_io].events = waiter->io.events; + set->io_waiters[i_io] = waiter; + i_io++; + } + + /* time waiters: copy to time_waiters, calculate next expiry */ + if (waiter->type == WAITER_TIME) { + if (!timerisset(&set->next_timeout) || + timercmp(&waiter->timeout, + &set->next_timeout, <)) + set->next_timeout = waiter->timeout; + + set->time_waiters[i_time] = waiter; + i_time++; + } } } int waiter_poll(struct waitset *set) { struct timeval now, timeout; + struct waiter *waiter, *tmp; int timeout_ms; int i, rc; @@ -219,11 +231,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 +253,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 +264,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; }