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>
This commit is contained in:
David Herrmann 2013-01-13 11:42:04 +01:00
parent 8fa28926cb
commit 5ee2338b60
4 changed files with 28 additions and 15 deletions

View 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);
}
/**

View 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;

View 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,

View 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,