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 wl_list_init(struct wl_list * list)37 wl_list_init(struct wl_list *list) 38 { 39 list->prev = list; 40 list->next = list; 41 } 42 43 WL_EXPORT void wl_list_insert(struct wl_list * list,struct wl_list * elm)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 wl_list_remove(struct wl_list * elm)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 wl_list_length(const struct wl_list * list)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 wl_list_empty(const struct wl_list * list)78 wl_list_empty(const struct wl_list *list) 79 { 80 return list->next == list; 81 } 82 83 WL_EXPORT void wl_list_insert_list(struct wl_list * list,struct wl_list * other)84 wl_list_insert_list(struct wl_list *list, struct wl_list *other) 85 { 86 if (wl_list_empty(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 wl_array_init(struct wl_array * array)96 wl_array_init(struct wl_array *array) 97 { 98 memset(array, 0, sizeof *array); 99 } 100 101 WL_EXPORT void wl_array_release(struct wl_array * array)102 wl_array_release(struct wl_array *array) 103 { 104 free(array->data); 105 array->data = WL_ARRAY_POISON_PTR; 106 } 107 108 WL_EXPORT void * wl_array_add(struct wl_array * array,size_t size)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(array->data, alloc); 125 else 126 data = malloc(alloc); 127 128 if (data == NULL) 129 return NULL; 130 array->data = data; 131 array->alloc = alloc; 132 } 133 134 p = array->data + array->size; 135 array->size += size; 136 137 return p; 138 } 139 140 WL_EXPORT int wl_array_copy(struct wl_array * array,struct wl_array * source)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, source->size - array->size)) 145 return -1; 146 } else { 147 array->size = source->size; 148 } 149 150 memcpy(array->data, source->data, source->size); 151 return 0; 152 } 153 154 /** \cond */ 155 156 struct wl_object global_zombie_object; 157 158 int wl_interface_equal(const struct wl_interface * a,const struct wl_interface * b)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(a->name, 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 WL_EXPORT void wl_map_init(struct wl_map * map,uint32_t side)181 wl_map_init(struct wl_map *map, uint32_t side) 182 { 183 memset(map, 0, sizeof *map); 184 map->side = side; 185 } 186 187 WL_EXPORT void wl_map_release(struct wl_map * map)188 wl_map_release(struct wl_map *map) 189 { 190 wl_array_release(&map->client_entries); 191 wl_array_release(&map->server_entries); 192 } 193 194 WL_EXPORT uint32_t wl_map_insert_new(struct wl_map * map,uint32_t flags,void * data)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(entries, 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 WL_EXPORT int wl_map_insert_at(struct wl_map * map,uint32_t flags,uint32_t i,void * data)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(entries, 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 WL_EXPORT int wl_map_reserve_new(struct wl_map * map,uint32_t i)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(entries, 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 WL_EXPORT void wl_map_remove(struct wl_map * map,uint32_t i)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 WL_EXPORT void * wl_map_lookup(struct wl_map * map,uint32_t i)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 WL_EXPORT uint32_t wl_map_lookup_flags(struct wl_map * map,uint32_t i)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 for_each_helper(struct wl_array * entries,wl_iterator_func_t func,void * data)364 for_each_helper(struct wl_array *entries, wl_iterator_func_t func, void *data) 365 { 366 union map_entry *start, *end, *p; 367 enum wl_iterator_result ret = WL_ITERATOR_CONTINUE; 368 369 start = entries->data; 370 end = (union map_entry *) ((char *) entries->data + entries->size); 371 372 for (p = start; p < end; p++) 373 if (p->data && !map_entry_is_free(*p)) { 374 ret = func(map_entry_get_data(*p), data); 375 if (ret != WL_ITERATOR_CONTINUE) 376 break; 377 } 378 379 return ret; 380 } 381 382 WL_EXPORT void wl_map_for_each(struct wl_map * map,wl_iterator_func_t func,void * data)383 wl_map_for_each(struct wl_map *map, wl_iterator_func_t func, void *data) 384 { 385 enum wl_iterator_result ret; 386 387 ret = for_each_helper(&map->client_entries, func, data); 388 if (ret == WL_ITERATOR_CONTINUE) 389 for_each_helper(&map->server_entries, func, data); 390 } 391 392 static void wl_log_stderr_handler(const char * fmt,va_list arg)393 wl_log_stderr_handler(const char *fmt, va_list arg) 394 { 395 vfprintf(stderr, fmt, arg); 396 } 397 398 wl_log_func_t wl_log_handler = wl_log_stderr_handler; 399 400 void wl_log(const char * fmt,...)401 wl_log(const char *fmt, ...) 402 { 403 va_list argp; 404 405 va_start(argp, fmt); 406 wl_log_handler(fmt, argp); 407 va_end(argp); 408 } 409 410 void wl_abort(const char * fmt,...)411 wl_abort(const char *fmt, ...) 412 { 413 va_list argp; 414 415 va_start(argp, fmt); 416 wl_log_handler(fmt, argp); 417 va_end(argp); 418 419 abort(); 420 } 421 422 /** \endcond */ 423