1 | /* |
2 | * Copyright © 2008-2011 Kristian Høgsberg |
3 | * Copyright © 2011 Intel Corporation |
4 | * |
5 | * Permission is hereby granted, free of charge, to any person obtaining |
6 | * a copy of this software and associated documentation files (the |
7 | * "Software"), to deal in the Software without restriction, including |
8 | * without limitation the rights to use, copy, modify, merge, publish, |
9 | * distribute, sublicense, and/or sell copies of the Software, and to |
10 | * permit persons to whom the Software is furnished to do so, subject to |
11 | * the following conditions: |
12 | * |
13 | * The above copyright notice and this permission notice (including the |
14 | * next paragraph) shall be included in all copies or substantial |
15 | * portions of the Software. |
16 | * |
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
20 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
21 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
22 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
23 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
24 | * SOFTWARE. |
25 | */ |
26 | |
27 | #include <stdlib.h> |
28 | #include <stdint.h> |
29 | #include <stdio.h> |
30 | #include <string.h> |
31 | #include <stdarg.h> |
32 | |
33 | #include "wayland-util.h" |
34 | #include "wayland-private.h" |
35 | |
36 | WL_EXPORT void |
37 | wl_list_init(struct wl_list *list) |
38 | { |
39 | list->prev = list; |
40 | list->next = list; |
41 | } |
42 | |
43 | WL_EXPORT void |
44 | wl_list_insert(struct wl_list *list, struct wl_list *elm) |
45 | { |
46 | elm->prev = list; |
47 | elm->next = list->next; |
48 | list->next = elm; |
49 | elm->next->prev = elm; |
50 | } |
51 | |
52 | WL_EXPORT void |
53 | wl_list_remove(struct wl_list *elm) |
54 | { |
55 | elm->prev->next = elm->next; |
56 | elm->next->prev = elm->prev; |
57 | elm->next = NULL; |
58 | elm->prev = NULL; |
59 | } |
60 | |
61 | WL_EXPORT int |
62 | wl_list_length(const struct wl_list *list) |
63 | { |
64 | struct wl_list *e; |
65 | int count; |
66 | |
67 | count = 0; |
68 | e = list->next; |
69 | while (e != list) { |
70 | e = e->next; |
71 | count++; |
72 | } |
73 | |
74 | return count; |
75 | } |
76 | |
77 | WL_EXPORT int |
78 | wl_list_empty(const struct wl_list *list) |
79 | { |
80 | return list->next == list; |
81 | } |
82 | |
83 | WL_EXPORT void |
84 | wl_list_insert_list(struct wl_list *list, struct wl_list *other) |
85 | { |
86 | if (wl_list_empty(list: other)) |
87 | return; |
88 | |
89 | other->next->prev = list; |
90 | other->prev->next = list->next; |
91 | list->next->prev = other->prev; |
92 | list->next = other->next; |
93 | } |
94 | |
95 | WL_EXPORT void |
96 | wl_array_init(struct wl_array *array) |
97 | { |
98 | memset(s: array, c: 0, n: sizeof *array); |
99 | } |
100 | |
101 | WL_EXPORT void |
102 | wl_array_release(struct wl_array *array) |
103 | { |
104 | free(ptr: array->data); |
105 | array->data = WL_ARRAY_POISON_PTR; |
106 | } |
107 | |
108 | WL_EXPORT void * |
109 | wl_array_add(struct wl_array *array, size_t size) |
110 | { |
111 | size_t alloc; |
112 | void *data, *p; |
113 | |
114 | if (array->alloc > 0) |
115 | alloc = array->alloc; |
116 | else |
117 | alloc = 16; |
118 | |
119 | while (alloc < array->size + size) |
120 | alloc *= 2; |
121 | |
122 | if (array->alloc < alloc) { |
123 | if (array->alloc > 0) |
124 | data = realloc(ptr: array->data, size: alloc); |
125 | else |
126 | data = malloc(size: alloc); |
127 | |
128 | if (data == NULL) |
129 | return NULL; |
130 | array->data = data; |
131 | array->alloc = alloc; |
132 | } |
133 | |
134 | p = (char *)array->data + array->size; |
135 | array->size += size; |
136 | |
137 | return p; |
138 | } |
139 | |
140 | WL_EXPORT int |
141 | wl_array_copy(struct wl_array *array, struct wl_array *source) |
142 | { |
143 | if (array->size < source->size) { |
144 | if (!wl_array_add(array, size: source->size - array->size)) |
145 | return -1; |
146 | } else { |
147 | array->size = source->size; |
148 | } |
149 | |
150 | if (source->size > 0) |
151 | memcpy(dest: array->data, src: source->data, n: source->size); |
152 | |
153 | return 0; |
154 | } |
155 | |
156 | /** \cond */ |
157 | |
158 | int |
159 | wl_interface_equal(const struct wl_interface *a, const struct wl_interface *b) |
160 | { |
161 | /* In most cases the pointer equality test is sufficient. |
162 | * However, in some cases, depending on how things are split |
163 | * across shared objects, we can end up with multiple |
164 | * instances of the interface metadata constants. So if the |
165 | * pointers match, the interfaces are equal, if they don't |
166 | * match we have to compare the interface names. |
167 | */ |
168 | return a == b || strcmp(s1: a->name, s2: b->name) == 0; |
169 | } |
170 | |
171 | union map_entry { |
172 | uintptr_t next; |
173 | void *data; |
174 | }; |
175 | |
176 | #define map_entry_is_free(entry) ((entry).next & 0x1) |
177 | #define map_entry_get_data(entry) ((void *)((entry).next & ~(uintptr_t)0x3)) |
178 | #define map_entry_get_flags(entry) (((entry).next >> 1) & 0x1) |
179 | |
180 | void |
181 | wl_map_init(struct wl_map *map, uint32_t side) |
182 | { |
183 | memset(s: map, c: 0, n: sizeof *map); |
184 | map->side = side; |
185 | } |
186 | |
187 | void |
188 | wl_map_release(struct wl_map *map) |
189 | { |
190 | wl_array_release(array: &map->client_entries); |
191 | wl_array_release(array: &map->server_entries); |
192 | } |
193 | |
194 | uint32_t |
195 | wl_map_insert_new(struct wl_map *map, uint32_t flags, void *data) |
196 | { |
197 | union map_entry *start, *entry; |
198 | struct wl_array *entries; |
199 | uint32_t base; |
200 | |
201 | if (map->side == WL_MAP_CLIENT_SIDE) { |
202 | entries = &map->client_entries; |
203 | base = 0; |
204 | } else { |
205 | entries = &map->server_entries; |
206 | base = WL_SERVER_ID_START; |
207 | } |
208 | |
209 | if (map->free_list) { |
210 | start = entries->data; |
211 | entry = &start[map->free_list >> 1]; |
212 | map->free_list = entry->next; |
213 | } else { |
214 | entry = wl_array_add(array: entries, size: sizeof *entry); |
215 | if (!entry) |
216 | return 0; |
217 | start = entries->data; |
218 | } |
219 | |
220 | entry->data = data; |
221 | entry->next |= (flags & 0x1) << 1; |
222 | |
223 | return (entry - start) + base; |
224 | } |
225 | |
226 | int |
227 | wl_map_insert_at(struct wl_map *map, uint32_t flags, uint32_t i, void *data) |
228 | { |
229 | union map_entry *start; |
230 | uint32_t count; |
231 | struct wl_array *entries; |
232 | |
233 | if (i < WL_SERVER_ID_START) { |
234 | entries = &map->client_entries; |
235 | } else { |
236 | entries = &map->server_entries; |
237 | i -= WL_SERVER_ID_START; |
238 | } |
239 | |
240 | count = entries->size / sizeof *start; |
241 | if (count < i) |
242 | return -1; |
243 | |
244 | if (count == i) |
245 | wl_array_add(array: entries, size: sizeof *start); |
246 | |
247 | start = entries->data; |
248 | start[i].data = data; |
249 | start[i].next |= (flags & 0x1) << 1; |
250 | |
251 | return 0; |
252 | } |
253 | |
254 | int |
255 | wl_map_reserve_new(struct wl_map *map, uint32_t i) |
256 | { |
257 | union map_entry *start; |
258 | uint32_t count; |
259 | struct wl_array *entries; |
260 | |
261 | if (i < WL_SERVER_ID_START) { |
262 | if (map->side == WL_MAP_CLIENT_SIDE) |
263 | return -1; |
264 | |
265 | entries = &map->client_entries; |
266 | } else { |
267 | if (map->side == WL_MAP_SERVER_SIDE) |
268 | return -1; |
269 | |
270 | entries = &map->server_entries; |
271 | i -= WL_SERVER_ID_START; |
272 | } |
273 | |
274 | count = entries->size / sizeof *start; |
275 | |
276 | if (count < i) |
277 | return -1; |
278 | |
279 | if (count == i) { |
280 | wl_array_add(array: entries, size: sizeof *start); |
281 | start = entries->data; |
282 | start[i].data = NULL; |
283 | } else { |
284 | start = entries->data; |
285 | if (start[i].data != NULL) { |
286 | return -1; |
287 | } |
288 | } |
289 | |
290 | return 0; |
291 | } |
292 | |
293 | void |
294 | wl_map_remove(struct wl_map *map, uint32_t i) |
295 | { |
296 | union map_entry *start; |
297 | struct wl_array *entries; |
298 | |
299 | if (i < WL_SERVER_ID_START) { |
300 | if (map->side == WL_MAP_SERVER_SIDE) |
301 | return; |
302 | |
303 | entries = &map->client_entries; |
304 | } else { |
305 | if (map->side == WL_MAP_CLIENT_SIDE) |
306 | return; |
307 | |
308 | entries = &map->server_entries; |
309 | i -= WL_SERVER_ID_START; |
310 | } |
311 | |
312 | start = entries->data; |
313 | start[i].next = map->free_list; |
314 | map->free_list = (i << 1) | 1; |
315 | } |
316 | |
317 | void * |
318 | wl_map_lookup(struct wl_map *map, uint32_t i) |
319 | { |
320 | union map_entry *start; |
321 | uint32_t count; |
322 | struct wl_array *entries; |
323 | |
324 | if (i < WL_SERVER_ID_START) { |
325 | entries = &map->client_entries; |
326 | } else { |
327 | entries = &map->server_entries; |
328 | i -= WL_SERVER_ID_START; |
329 | } |
330 | |
331 | start = entries->data; |
332 | count = entries->size / sizeof *start; |
333 | |
334 | if (i < count && !map_entry_is_free(start[i])) |
335 | return map_entry_get_data(start[i]); |
336 | |
337 | return NULL; |
338 | } |
339 | |
340 | uint32_t |
341 | wl_map_lookup_flags(struct wl_map *map, uint32_t i) |
342 | { |
343 | union map_entry *start; |
344 | uint32_t count; |
345 | struct wl_array *entries; |
346 | |
347 | if (i < WL_SERVER_ID_START) { |
348 | entries = &map->client_entries; |
349 | } else { |
350 | entries = &map->server_entries; |
351 | i -= WL_SERVER_ID_START; |
352 | } |
353 | |
354 | start = entries->data; |
355 | count = entries->size / sizeof *start; |
356 | |
357 | if (i < count && !map_entry_is_free(start[i])) |
358 | return map_entry_get_flags(start[i]); |
359 | |
360 | return 0; |
361 | } |
362 | |
363 | static enum wl_iterator_result |
364 | for_each_helper(struct wl_array *entries, wl_iterator_func_t func, void *data) |
365 | { |
366 | enum wl_iterator_result ret = WL_ITERATOR_CONTINUE; |
367 | union map_entry entry, *start; |
368 | size_t count; |
369 | |
370 | start = (union map_entry *) entries->data; |
371 | count = entries->size / sizeof(union map_entry); |
372 | |
373 | for (size_t idx = 0; idx < count; idx++) { |
374 | entry = start[idx]; |
375 | if (entry.data && !map_entry_is_free(entry)) { |
376 | ret = func(map_entry_get_data(entry), data, map_entry_get_flags(entry)); |
377 | if (ret != WL_ITERATOR_CONTINUE) |
378 | break; |
379 | } |
380 | } |
381 | |
382 | return ret; |
383 | } |
384 | |
385 | void |
386 | wl_map_for_each(struct wl_map *map, wl_iterator_func_t func, void *data) |
387 | { |
388 | enum wl_iterator_result ret; |
389 | |
390 | ret = for_each_helper(entries: &map->client_entries, func, data); |
391 | if (ret == WL_ITERATOR_CONTINUE) |
392 | for_each_helper(entries: &map->server_entries, func, data); |
393 | } |
394 | |
395 | static void |
396 | wl_log_stderr_handler(const char *fmt, va_list arg) |
397 | { |
398 | vfprintf(stderr, format: fmt, arg: arg); |
399 | } |
400 | |
401 | wl_log_func_t wl_log_handler = wl_log_stderr_handler; |
402 | |
403 | void |
404 | wl_log(const char *fmt, ...) |
405 | { |
406 | va_list argp; |
407 | |
408 | va_start(argp, fmt); |
409 | wl_log_handler(fmt, argp); |
410 | va_end(argp); |
411 | } |
412 | |
413 | void |
414 | wl_abort(const char *fmt, ...) |
415 | { |
416 | va_list argp; |
417 | |
418 | va_start(argp, fmt); |
419 | wl_log_handler(fmt, argp); |
420 | va_end(argp); |
421 | |
422 | abort(); |
423 | } |
424 | |
425 | /** \endcond */ |
426 | |