diff options
author | David Herrmann <dh.herrmann@googlemail.com> | 2013-01-13 11:42:04 +0100 |
---|---|---|
committer | David Herrmann <dh.herrmann@googlemail.com> | 2013-01-13 11:42:04 +0100 |
commit | 5ee2338b6095c5fa996f4d77a6cd9103f1d589d3 (patch) | |
tree | 873b33dcbb46de4df171268f89ba95ba44a4c159 | |
parent | 8fa28926cbe8fdcf0ec8f96d932e160399a1ac8a (diff) |
shl: hook: add 'oneshot' flag
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>
-rw-r--r-- | src/eloop.c | 10 | ||||
-rw-r--r-- | src/shl_hook.h | 27 | ||||
-rw-r--r-- | src/uterm_input.c | 2 | ||||
-rw-r--r-- | src/uterm_video.c | 4 |
4 files changed, 28 insertions, 15 deletions
diff --git a/src/eloop.c b/src/eloop.c index 55e8136..c9a7c05 100644 --- a/src/eloop.c +++ b/src/eloop.c @@ -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); } /** diff --git a/src/shl_hook.h b/src/shl_hook.h index 73afbb5..f1a4454 100644 --- a/src/shl_hook.h +++ b/src/shl_hook.h @@ -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; diff --git a/src/uterm_input.c b/src/uterm_input.c index 64caf58..b20a128 100644 --- a/src/uterm_input.c +++ b/src/uterm_input.c @@ -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, diff --git a/src/uterm_video.c b/src/uterm_video.c index e7d6691..1b76d68 100644 --- a/src/uterm_video.c +++ b/src/uterm_video.c @@ -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, |