shl: hook: add 'oneshot' flag
authorDavid Herrmann <dh.herrmann@googlemail.com>
Sun, 13 Jan 2013 10:42:04 +0000 (11:42 +0100)
committerDavid Herrmann <dh.herrmann@googlemail.com>
Sun, 13 Jan 2013 10:42:04 +0000 (11:42 +0100)
If an entry is marked as 'oneshot' then it will get deleted after it has
been called once. Note that the entry is unlinked _before_ the callback is
called.

If you use 'oneshot'-entries and normal entries with the same cb+data
combination, then you will probably get unexpected behavior. It is not
recommended to do that. In detail, you cannot control which entry is
deleted via a shl_hook_rm() call so you can never be sure whether the
oneshot entry or a normal entry is deleted.

Do not mix oneshot entries with normal entries!

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
src/eloop.c
src/shl_hook.h
src/uterm_input.c
src/uterm_video.c

index 55e8136..c9a7c05 100644 (file)
@@ -2196,7 +2196,7 @@ int ev_eloop_register_signal_cb(struct ev_eloop *loop, int signum,
                        return ret;
        }
 
-       ret = shl_hook_add_cast(sig->hook, cb, data);
+       ret = shl_hook_add_cast(sig->hook, cb, data, false);
        if (ret) {
                signal_free(sig);
                return ret;
@@ -2257,7 +2257,7 @@ int ev_eloop_register_child_cb(struct ev_eloop *loop, ev_child_cb cb,
                return -EINVAL;
 
        empty = !shl_hook_num(loop->chlds);
-       ret = shl_hook_add_cast(loop->chlds, cb, data);
+       ret = shl_hook_add_cast(loop->chlds, cb, data, false);
        if (ret)
                return ret;
 
@@ -2311,7 +2311,7 @@ int ev_eloop_register_idle_cb(struct ev_eloop *eloop, ev_idle_cb cb,
        if (!eloop)
                return -EINVAL;
 
-       ret = shl_hook_add_cast(eloop->idlers, cb, data);
+       ret = shl_hook_add_cast(eloop->idlers, cb, data, false);
        if (ret)
                return ret;
 
@@ -2371,7 +2371,7 @@ int ev_eloop_register_pre_cb(struct ev_eloop *eloop, ev_idle_cb cb,
        if (!eloop)
                return -EINVAL;
 
-       return shl_hook_add_cast(eloop->pres, cb, data);
+       return shl_hook_add_cast(eloop->pres, cb, data, false);
 }
 
 /**
@@ -2420,7 +2420,7 @@ int ev_eloop_register_post_cb(struct ev_eloop *eloop, ev_idle_cb cb,
        if (!eloop)
                return -EINVAL;
 
-       return shl_hook_add_cast(eloop->posts, cb, data);
+       return shl_hook_add_cast(eloop->posts, cb, data, false);
 }
 
 /**
index 73afbb5..f1a4454 100644 (file)
@@ -43,8 +43,8 @@ struct shl_hook;
 struct shl_hook_entry;
 typedef void (*shl_hook_cb) (void *parent, void *arg, void *data);
 
-#define shl_hook_add_cast(hook, cb, data) \
-       shl_hook_add((hook), (shl_hook_cb)(cb), (data))
+#define shl_hook_add_cast(hook, cb, data, oneshot) \
+       shl_hook_add((hook), (shl_hook_cb)(cb), (data), (oneshot))
 #define shl_hook_rm_cast(hook, cb, data) \
        shl_hook_rm((hook), (shl_hook_cb)(cb), (data))
 
@@ -52,6 +52,7 @@ struct shl_hook_entry {
        struct shl_dlist list;
        shl_hook_cb cb;
        void *data;
+       bool oneshot;
 };
 
 struct shl_hook {
@@ -110,7 +111,7 @@ static inline unsigned int shl_hook_num(struct shl_hook *hook)
 }
 
 static inline int shl_hook_add(struct shl_hook *hook, shl_hook_cb cb,
-                              void *data)
+                              void *data, bool oneshot)
 {
        struct shl_hook_entry *entry;
 
@@ -123,14 +124,18 @@ static inline int shl_hook_add(struct shl_hook *hook, shl_hook_cb cb,
        memset(entry, 0, sizeof(*entry));
        entry->cb = cb;
        entry->data = data;
+       entry->oneshot = oneshot;
 
        shl_dlist_link_tail(&hook->entries, &entry->list);
        hook->num++;
        return 0;
 }
 
+/* This adds an entry only if it is not already in the list. But notice that if
+ * the entry is already registered twice or with a different \oneshot flag, the
+ * list will _not_ be changed! */
 static inline int shl_hook_add_single(struct shl_hook *hook, shl_hook_cb cb,
-                                     void *data)
+                                     void *data, bool oneshot)
 {
        struct shl_hook_entry *entry;
        struct shl_dlist *iter;
@@ -144,7 +149,7 @@ static inline int shl_hook_add_single(struct shl_hook *hook, shl_hook_cb cb,
                        return 0;
        }
 
-       return shl_hook_add(hook, cb, data);
+       return shl_hook_add(hook, cb, data, oneshot);
 }
 
 static inline void shl_hook_rm(struct shl_hook *hook, shl_hook_cb cb,
@@ -204,9 +209,17 @@ static inline void shl_hook_call(struct shl_hook *hook, void *parent,
             hook->cur_entry != &hook->entries; ) {
                entry = shl_dlist_entry(hook->cur_entry,
                                        struct shl_hook_entry, list);
+               hook->cur_entry = entry->list.next;
+
+               if (entry->oneshot)
+                       shl_dlist_unlink(&entry->list);
+
                entry->cb(parent, arg, entry->data);
-               if (hook->cur_entry == &entry->list)
-                       hook->cur_entry = hook->cur_entry->next;
+
+               if (entry->oneshot) {
+                       free(entry);
+                       --hook->num;
+               }
        }
 
        hook->cur_entry = NULL;
index 64caf58..b20a128 100644 (file)
@@ -394,7 +394,7 @@ int uterm_input_register_cb(struct uterm_input *input,
        if (!input || !cb)
                return -EINVAL;
 
-       return shl_hook_add_cast(input->hook, cb, data);
+       return shl_hook_add_cast(input->hook, cb, data, false);
 }
 
 void uterm_input_unregister_cb(struct uterm_input *input,
index e7d6691..1b76d68 100644 (file)
@@ -324,7 +324,7 @@ int uterm_display_register_cb(struct uterm_display *disp, uterm_display_cb cb,
        if (!disp)
                return -EINVAL;
 
-       return shl_hook_add_cast(disp->hook, cb, data);
+       return shl_hook_add_cast(disp->hook, cb, data, false);
 }
 
 void uterm_display_unregister_cb(struct uterm_display *disp,
@@ -589,7 +589,7 @@ int uterm_video_register_cb(struct uterm_video *video, uterm_video_cb cb,
        if (!video || !cb)
                return -EINVAL;
 
-       return shl_hook_add_cast(video->hook, cb, data);
+       return shl_hook_add_cast(video->hook, cb, data, false);
 }
 
 void uterm_video_unregister_cb(struct uterm_video *video, uterm_video_cb cb,