4 * Copyright (c) 2011-2013 David Herrmann <dh.herrmann@googlemail.com>
5 * Copyright (c) 2011 University of Tuebingen
7 * Permission is hereby granted, free of charge, to any person obtaining
8 * a copy of this software and associated documentation files
9 * (the "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sublicense, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 * Simply hook-implementation
40 #include "shl_dlist.h"
43 struct shl_hook_entry;
44 typedef void (*shl_hook_cb) (void *parent, void *arg, void *data);
46 #define shl_hook_add_cast(hook, cb, data, oneshot) \
47 shl_hook_add((hook), (shl_hook_cb)(cb), (data), (oneshot))
48 #define shl_hook_add_single_cast(hook, cb, data, oneshot) \
49 shl_hook_add_single((hook), (shl_hook_cb)(cb), (data), (oneshot))
50 #define shl_hook_rm_cast(hook, cb, data) \
51 shl_hook_rm((hook), (shl_hook_cb)(cb), (data))
52 #define shl_hook_rm_all_cast(hook, cb, data) \
53 shl_hook_rm_all((hook), (shl_hook_cb)(cb), (data))
55 struct shl_hook_entry {
56 struct shl_dlist list;
64 struct shl_dlist entries;
65 struct shl_dlist *cur_entry;
69 static inline int shl_hook_new(struct shl_hook **out)
71 struct shl_hook *hook;
76 hook = malloc(sizeof(*hook));
79 memset(hook, 0, sizeof(*hook));
80 shl_dlist_init(&hook->entries);
86 static inline void shl_hook_free(struct shl_hook *hook)
88 struct shl_hook_entry *entry;
93 if (hook->cur_entry) {
98 while (!shl_dlist_empty(&hook->entries)) {
99 entry = shl_dlist_entry(hook->entries.prev,
100 struct shl_hook_entry,
102 shl_dlist_unlink(&entry->list);
109 static inline unsigned int shl_hook_num(struct shl_hook *hook)
117 static inline int shl_hook_add(struct shl_hook *hook, shl_hook_cb cb,
118 void *data, bool oneshot)
120 struct shl_hook_entry *entry;
125 entry = malloc(sizeof(*entry));
128 memset(entry, 0, sizeof(*entry));
131 entry->oneshot = oneshot;
133 shl_dlist_link_tail(&hook->entries, &entry->list);
138 /* This adds an entry only if it is not already in the list. But notice that if
139 * the entry is already registered twice or with a different \oneshot flag, the
140 * list will _not_ be changed! */
141 static inline int shl_hook_add_single(struct shl_hook *hook, shl_hook_cb cb,
142 void *data, bool oneshot)
144 struct shl_hook_entry *entry;
145 struct shl_dlist *iter;
150 shl_dlist_for_each(iter, &hook->entries) {
151 entry = shl_dlist_entry(iter, struct shl_hook_entry, list);
152 if (entry->cb == cb && entry->data == data)
156 return shl_hook_add(hook, cb, data, oneshot);
159 static inline void shl_hook_rm(struct shl_hook *hook, shl_hook_cb cb,
162 struct shl_dlist *iter;
163 struct shl_hook_entry *entry;
168 shl_dlist_for_each_reverse(iter, &hook->entries) {
169 entry = shl_dlist_entry(iter, struct shl_hook_entry, list);
170 if (entry->cb == cb && entry->data == data) {
171 /* if *_call() is running we must not disturb it */
172 if (hook->cur_entry == iter)
173 hook->cur_entry = iter->next;
174 shl_dlist_unlink(&entry->list);
182 static inline void shl_hook_rm_all(struct shl_hook *hook, shl_hook_cb cb,
185 struct shl_dlist *iter, *tmp;
186 struct shl_hook_entry *entry;
191 shl_dlist_for_each_reverse_safe(iter, tmp, &hook->entries) {
192 entry = shl_dlist_entry(iter, struct shl_hook_entry, list);
193 if (entry->cb == cb && entry->data == data) {
194 /* if *_call() is running we must not disturb it */
195 if (hook->cur_entry == iter)
196 hook->cur_entry = iter->next;
197 shl_dlist_unlink(&entry->list);
204 static inline void shl_hook_call(struct shl_hook *hook, void *parent,
207 struct shl_hook_entry *entry;
210 if (!hook || hook->cur_entry)
213 for (hook->cur_entry = hook->entries.next;
214 hook->cur_entry != &hook->entries; ) {
215 entry = shl_dlist_entry(hook->cur_entry,
216 struct shl_hook_entry, list);
217 hook->cur_entry = entry->list.next;
218 oneshot = entry->oneshot;
221 shl_dlist_unlink(&entry->list);
223 entry->cb(parent, arg, entry->data);
231 hook->cur_entry = NULL;
236 #endif /* SHL_HOOK_H */