Modify it to adjust Tizen IVI enviroment
[platform/upstream/kmscon.git] / src / shl_hook.h
1 /*
2  * shl - Hook Handling
3  *
4  * Copyright (c) 2011-2013 David Herrmann <dh.herrmann@googlemail.com>
5  * Copyright (c) 2011 University of Tuebingen
6  *
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:
14  *
15  * The above copyright notice and this permission notice shall be included
16  * in all copies or substantial portions of the Software.
17  *
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.
25  */
26
27 /*
28  * Simply hook-implementation
29  */
30
31 #ifndef SHL_HOOK_H
32 #define SHL_HOOK_H
33
34 #include <errno.h>
35 #include <stdbool.h>
36 #include <stddef.h>
37 #include <stdint.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include "shl_dlist.h"
41
42 struct shl_hook;
43 struct shl_hook_entry;
44 typedef void (*shl_hook_cb) (void *parent, void *arg, void *data);
45
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))
54
55 struct shl_hook_entry {
56         struct shl_dlist list;
57         shl_hook_cb cb;
58         void *data;
59         bool oneshot;
60 };
61
62 struct shl_hook {
63         unsigned int num;
64         struct shl_dlist entries;
65         struct shl_dlist *cur_entry;
66         bool dead;
67 };
68
69 static inline int shl_hook_new(struct shl_hook **out)
70 {
71         struct shl_hook *hook;
72
73         if (!out)
74                 return -EINVAL;
75
76         hook = malloc(sizeof(*hook));
77         if (!hook)
78                 return -ENOMEM;
79         memset(hook, 0, sizeof(*hook));
80         shl_dlist_init(&hook->entries);
81
82         *out = hook;
83         return 0;
84 }
85
86 static inline void shl_hook_free(struct shl_hook *hook)
87 {
88         struct shl_hook_entry *entry;
89
90         if (!hook)
91                 return;
92
93         if (hook->cur_entry) {
94                 hook->dead = true;
95                 return;
96         }
97
98         while (!shl_dlist_empty(&hook->entries)) {
99                 entry = shl_dlist_entry(hook->entries.prev,
100                                         struct shl_hook_entry,
101                                         list);
102                 shl_dlist_unlink(&entry->list);
103                 free(entry);
104         }
105
106         free(hook);
107 }
108
109 static inline unsigned int shl_hook_num(struct shl_hook *hook)
110 {
111         if (!hook)
112                 return 0;
113
114         return hook->num;
115 }
116
117 static inline int shl_hook_add(struct shl_hook *hook, shl_hook_cb cb,
118                                void *data, bool oneshot)
119 {
120         struct shl_hook_entry *entry;
121
122         if (!hook || !cb)
123                 return -EINVAL;
124
125         entry = malloc(sizeof(*entry));
126         if (!entry)
127                 return -ENOMEM;
128         memset(entry, 0, sizeof(*entry));
129         entry->cb = cb;
130         entry->data = data;
131         entry->oneshot = oneshot;
132
133         shl_dlist_link_tail(&hook->entries, &entry->list);
134         hook->num++;
135         return 0;
136 }
137
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)
143 {
144         struct shl_hook_entry *entry;
145         struct shl_dlist *iter;
146
147         if (!hook || !cb)
148                 return -EINVAL;
149
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)
153                         return 0;
154         }
155
156         return shl_hook_add(hook, cb, data, oneshot);
157 }
158
159 static inline void shl_hook_rm(struct shl_hook *hook, shl_hook_cb cb,
160                                void *data)
161 {
162         struct shl_dlist *iter;
163         struct shl_hook_entry *entry;
164
165         if (!hook || !cb)
166                 return;
167
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);
175                         free(entry);
176                         hook->num--;
177                         return;
178                 }
179         }
180 }
181
182 static inline void shl_hook_rm_all(struct shl_hook *hook, shl_hook_cb cb,
183                                    void *data)
184 {
185         struct shl_dlist *iter, *tmp;
186         struct shl_hook_entry *entry;
187
188         if (!hook || !cb)
189                 return;
190
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);
198                         free(entry);
199                         hook->num--;
200                 }
201         }
202 }
203
204 static inline void shl_hook_call(struct shl_hook *hook, void *parent,
205                                  void *arg)
206 {
207         struct shl_hook_entry *entry;
208         bool oneshot;
209
210         if (!hook || hook->cur_entry)
211                 return;
212
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;
219
220                 if (oneshot)
221                         shl_dlist_unlink(&entry->list);
222
223                 entry->cb(parent, arg, entry->data);
224
225                 if (oneshot) {
226                         free(entry);
227                         --hook->num;
228                 }
229         }
230
231         hook->cur_entry = NULL;
232         if (hook->dead)
233                 shl_hook_free(hook);
234 }
235
236 #endif /* SHL_HOOK_H */