X-Git-Url: http://git.ozlabs.org/?a=blobdiff_plain;f=lib%2Fwaiter%2Fwaiter.c;h=78ba045f8b18fe5088d8c11422175b4654f87752;hb=a610837ff38f5cc80bcbad465a80ab920e67927d;hp=68f483acac03adaea7955cf91dd1fc2f2197a75a;hpb=e058e90117300125af7b6e93eb0e5aeb23543af9;p=petitboot diff --git a/lib/waiter/waiter.c b/lib/waiter/waiter.c index 68f483a..78ba045 100644 --- a/lib/waiter/waiter.c +++ b/lib/waiter/waiter.c @@ -1,5 +1,6 @@ #include +#include #include #include @@ -8,76 +9,131 @@ #include "waiter.h" struct waiter { + struct waitset *set; int fd; int events; waiter_cb callback; void *arg; }; -static struct waiter *waiters; -static int n_waiters; +struct waitset { + struct waiter **waiters; + int n_waiters; + bool waiters_changed; + + /* These are kept consistent over each call to waiter_poll, as + * set->waiters may be updated (by waiters' callbacks calling + * waiter_register or waiter_remove) during iteration. */ + struct pollfd *pollfds; + struct waiter **cur_waiters; + int cur_n_waiters; +}; -struct waiter *waiter_register(int fd, int events, +struct waitset *waitset_create(void *ctx) +{ + struct waitset *set = talloc_zero(ctx, struct waitset); + return set; +} + +void waitset_destroy(struct waitset *set) +{ + talloc_free(set); +} + +struct waiter *waiter_register(struct waitset *set, int fd, int events, waiter_cb callback, void *arg) { - struct waiter *waiter; + struct waiter **waiters, *waiter; + + waiter = talloc(set->waiters, struct waiter); + if (!waiter) + return NULL; + + waiters = talloc_realloc(set, set->waiters, + struct waiter *, set->n_waiters + 1); - n_waiters++; + if (!waiters) { + talloc_free(waiter); + return NULL; + } + + set->waiters_changed = true; + set->waiters = waiters; + set->n_waiters++; - waiters = talloc_realloc(NULL, waiters, struct waiter, n_waiters); - waiter = &waiters[n_waiters - 1]; + set->waiters[set->n_waiters - 1] = waiter; + waiter->set = set; waiter->fd = fd; waiter->events = events; waiter->callback = callback; waiter->arg = arg; - return 0; + return waiter; } void waiter_remove(struct waiter *waiter) { + struct waitset *set = waiter->set; int i; - i = waiter - waiters; - assert(i >= 0 && i < n_waiters); + for (i = 0; i < set->n_waiters; i++) + if (set->waiters[i] == waiter) + break; + + assert(i < set->n_waiters); + + set->n_waiters--; + memmove(&set->waiters[i], &set->waiters[i+1], + (set->n_waiters - i) * sizeof(set->waiters[0])); - n_waiters--; - memmove(&waiters[i], &waiters[i+1], - (n_waiters - i) * sizeof(waiters[0])); + set->waiters = talloc_realloc(set->waiters, set->waiters, + struct waiter *, set->n_waiters); + set->waiters_changed = true; - waiters = talloc_realloc(NULL, waiters, struct waiter, n_waiters); + talloc_free(waiter); } -int waiter_poll(void) +int waiter_poll(struct waitset *set) { - static struct pollfd *pollfds; - static int n_pollfds; int i, rc; - if (n_waiters != n_pollfds) { - pollfds = talloc_realloc(NULL, pollfds, - struct pollfd, n_waiters); - n_pollfds = n_waiters; - } + /* If the waiters have been updated, we need to update our + * consistent copy */ + if (set->waiters_changed) { + + /* We need to reallocate if the count has changes */ + if (set->cur_n_waiters != set->n_waiters) { + set->cur_waiters = talloc_realloc(set, set->cur_waiters, + struct waiter *, set->n_waiters); + set->pollfds = talloc_realloc(set, set->pollfds, + struct pollfd, set->n_waiters); + set->cur_n_waiters = set->n_waiters; + } + + /* Populate cur_waiters and pollfds from ->waiters data */ + for (i = 0; i < set->n_waiters; i++) { + set->pollfds[i].fd = set->waiters[i]->fd; + set->pollfds[i].events = set->waiters[i]->events; + set->pollfds[i].revents = 0; + set->cur_waiters[i] = set->waiters[i]; + } - for (i = 0; i < n_waiters; i++) { - pollfds[i].fd = waiters[i].fd; - pollfds[i].events = waiters[i].events; - pollfds[i].revents = 0; + set->waiters_changed = false; } - rc = poll(pollfds, n_waiters, -1); + rc = poll(set->pollfds, set->cur_n_waiters, -1); if (rc <= 0) return rc; - for (i = 0; i < n_waiters; i++) { - if (pollfds[i].revents) { - rc = waiters[i].callback(waiters[i].arg); + for (i = 0; i < set->cur_n_waiters; i++) { + if (set->pollfds[i].revents) { + rc = set->cur_waiters[i]->callback( + set->cur_waiters[i]->arg); if (rc) - waiter_remove(&waiters[i]); + waiter_remove(set->cur_waiters[i]); } }