summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Herrmann <dh.herrmann@googlemail.com>2013-01-13 11:42:04 +0100
committerDavid Herrmann <dh.herrmann@googlemail.com>2013-01-13 11:42:04 +0100
commit5ee2338b6095c5fa996f4d77a6cd9103f1d589d3 (patch)
tree873b33dcbb46de4df171268f89ba95ba44a4c159
parent8fa28926cbe8fdcf0ec8f96d932e160399a1ac8a (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.c10
-rw-r--r--src/shl_hook.h27
-rw-r--r--src/uterm_input.c2
-rw-r--r--src/uterm_video.c4
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,