]> git.ozlabs.org Git - petitboot/blobdiff - lib/waiter/waiter.c
ui/ncurses: Add plugin menu and nc-plugin screen
[petitboot] / lib / waiter / waiter.c
index 513ab608af3a3115ec6a39d58a0645dee129cd56..d684348f4fc9566be5bc6ab9023793b169e5580f 100644 (file)
@@ -3,23 +3,32 @@
 #include <stdbool.h>
 #include <string.h>
 #include <assert.h>
+#include <errno.h>
 #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 {
@@ -38,24 +47,22 @@ 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;
 }
 
-void waitset_destroy(struct waitset *set)
-{
-       talloc_free(set);
-}
-
 static struct waiter *waiter_new(struct waitset *set)
 {
        struct waiter **waiters, *waiter;
 
-       waiter = talloc(set->waiters, struct waiter);
+       waiter = talloc(set, struct waiter);
        if (!waiter)
                return NULL;
 
@@ -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;
 }
 
@@ -82,8 +90,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 +134,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 +172,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];
-
-               if (waiter->type != WAITER_IO)
-                       continue;
+       i_io = 0;
+       i_time = 0;
 
-               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;
 
@@ -215,15 +223,20 @@ int waiter_poll(struct waitset *set)
                timeout_ms = -1;
        }
 
-
        rc = poll(set->pollfds, set->n_io_waiters, timeout_ms);
 
-       if (rc < 0)
-               return rc;
+       if (rc < 0) {
+               if (errno == EINTR)
+                       rc = 0;
+               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;
 }