X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Ftdm_event_loop.c;h=b7de4ab12c0f14283cde9c1fdf71fdceab89b9f5;hb=b587c76b5319d00f0c1305ce91053c1fe97c42ca;hp=f653dbed739c7e5b21827a3d26b19b51c042ec94;hpb=9a9d836fb0d090ad6ce39ed002ead2f0c86187ab;p=platform%2Fcore%2Fuifw%2Flibtdm.git diff --git a/src/tdm_event_loop.c b/src/tdm_event_loop.c index f653dbe..b7de4ab 100644 --- a/src/tdm_event_loop.c +++ b/src/tdm_event_loop.c @@ -1,90 +1,82 @@ /************************************************************************** - -libtdm - -Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved. - -Contact: Eunchul Kim , - JinYoung Jeon , - Taeheon Kim , - YoungJun Cho , - SooChan Lim , - Boram Park - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sub license, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice (including the -next paragraph) shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. -IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR -ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - + * + * libtdm + * + * Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved. + * + * Contact: Eunchul Kim , + * JinYoung Jeon , + * Taeheon Kim , + * YoungJun Cho , + * SooChan Lim , + * Boram Park + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * **************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif -#include "tdm.h" #include "tdm_private.h" -#include "tdm_list.h" -#include - -typedef struct _tdm_event_loop_source_base -{ +typedef struct _tdm_event_loop_source_base { + struct list_head link; + tdm_private_display *private_display; struct wl_event_source *wl_source; } tdm_event_loop_source_base; -typedef struct _tdm_event_loop_source_fd -{ +typedef struct _tdm_event_loop_source_fd { tdm_event_loop_source_base base; - tdm_private_display *private_display; tdm_event_loop_fd_handler func; void *user_data; } tdm_event_loop_source_fd; -typedef struct _tdm_event_loop_source_timer -{ +typedef struct _tdm_event_loop_source_timer { tdm_event_loop_source_base base; - tdm_private_display *private_display; tdm_event_loop_timer_handler func; void *user_data; } tdm_event_loop_source_timer; +static tdm_private_loop *keep_private_loop; + static tdm_error _tdm_event_loop_main_fd_handler(int fd, tdm_event_loop_mask mask, void *user_data) { - tdm_private_display *private_display = (tdm_private_display*)user_data; - tdm_private_loop *private_loop; + tdm_private_module *private_module = (tdm_private_module*)user_data; tdm_func_display *func_display; tdm_error ret; - TDM_RETURN_VAL_IF_FAIL(private_display != NULL, TDM_ERROR_OPERATION_FAILED); - TDM_RETURN_VAL_IF_FAIL(private_display->private_loop != NULL, TDM_ERROR_OPERATION_FAILED); + TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED); + TDM_RETURN_VAL_IF_FAIL(private_module != NULL, TDM_ERROR_OPERATION_FAILED); - private_loop = private_display->private_loop; + if (tdm_debug_module & TDM_DEBUG_EVENT) + TDM_INFO("backend fd(%d) event happens", private_module->fd); - if (tdm_debug_thread) - TDM_INFO("backend fd(%d) event happens", private_loop->backend_fd); - - func_display = &private_display->func_display; + func_display = &private_module->func_display; if (!func_display->display_handle_events) return TDM_ERROR_NONE; - ret = func_display->display_handle_events(private_display->bdata); + ret = func_display->display_handle_events(private_module->bdata); return ret; } @@ -95,31 +87,24 @@ tdm_event_loop_init(tdm_private_display *private_display) tdm_private_loop *private_loop; tdm_error ret; + TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED); + if (private_display->private_loop) return TDM_ERROR_NONE; - private_loop = calloc(1, sizeof *private_loop); + private_loop = calloc(1, sizeof * private_loop); if (!private_loop) { TDM_ERR("alloc failed"); return TDM_ERROR_OUT_OF_MEMORY; } - private_loop->backend_fd = -1; - private_loop->wl_display = wl_display_create(); if (!private_loop->wl_display) { TDM_ERR("creating a wayland display failed"); free(private_loop); return TDM_ERROR_OUT_OF_MEMORY; } - private_loop->wl_loop = wl_display_get_event_loop(private_loop->wl_display); - if (!private_loop->wl_loop) { - TDM_ERR("no event loop"); - wl_display_destroy(private_loop->wl_display); - free(private_loop); - return TDM_ERROR_OPERATION_FAILED; - } ret = tdm_server_init(private_loop); if (ret != TDM_ERROR_NONE) { @@ -129,6 +114,8 @@ tdm_event_loop_init(tdm_private_display *private_display) return TDM_ERROR_OPERATION_FAILED; } + LIST_INITHEAD(&private_loop->source_list); + private_loop->dpy = private_display; private_display->private_loop = private_loop; @@ -141,6 +128,8 @@ tdm_event_loop_init(tdm_private_display *private_display) return TDM_ERROR_OPERATION_FAILED; } + keep_private_loop = private_loop; + TDM_INFO("event loop fd(%d)", wl_event_loop_get_fd(private_loop->wl_loop)); return TDM_ERROR_NONE; @@ -149,62 +138,92 @@ tdm_event_loop_init(tdm_private_display *private_display) INTERN void tdm_event_loop_deinit(tdm_private_display *private_display) { + tdm_private_module *private_module = NULL; + tdm_event_loop_source_base *source = NULL, *ss = NULL; + + TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED()); + if (!private_display->private_loop) return; - tdm_thread_deinit(private_display->private_loop); + if (tdm_thread_is_running()) + TDM_ERR("thread is still running. tdm_event_loop_stop SHOULD be called"); + tdm_server_deinit(private_display->private_loop); - if (private_display->private_loop->backend_source) - tdm_event_loop_source_remove(private_display->private_loop->backend_source); + LIST_FOR_EACH_ENTRY(private_module, &private_display->module_list, link) { + if (private_module->event_source) + tdm_event_loop_source_remove(private_module->event_source); + private_module->event_source = NULL; + private_module->fd = -1; + } + + LIST_FOR_EACH_ENTRY_SAFE(source, ss, &private_display->private_loop->source_list, link) { + tdm_event_loop_source_remove(source); + } + +#if WAYLAND_VERSION_MAJOR >= 1 && WAYLAND_VERSION_MINOR >= 15 + wl_display_destroy_clients(private_display->private_loop->wl_display); +#endif - if (private_display->private_loop->wl_display) - wl_display_destroy(private_display->private_loop->wl_display); + wl_display_destroy(private_display->private_loop->wl_display); free(private_display->private_loop); private_display->private_loop = NULL; + keep_private_loop = NULL; + + TDM_INFO("event loop deinit done"); +} + +INTERN void +tdm_event_loop_stop(tdm_private_display *private_display) +{ + TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED()); + + /* after tdm_thread_deinit, we don't worry about thread things because it's finalized */ + tdm_thread_deinit(private_display->private_loop); } INTERN void tdm_event_loop_create_backend_source(tdm_private_display *private_display) { tdm_private_loop *private_loop = private_display->private_loop; - tdm_func_display *func_display; + tdm_private_module *private_module = NULL; tdm_error ret; int fd = -1; + TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED()); TDM_RETURN_IF_FAIL(private_loop != NULL); - func_display = &private_display->func_display; - if (!func_display->display_get_fd) { - TDM_INFO("TDM backend module won't offer a display fd"); - return; - } + LIST_FOR_EACH_ENTRY(private_module, &private_display->module_list, link) { + tdm_func_display *func_display = &private_module->func_display; - ret = func_display->display_get_fd(private_display->bdata, &fd); - if (fd < 0) { - TDM_WRN("TDM backend module returns fd(%d)", fd); - return; - } + if (!func_display->display_get_fd) { + TDM_INFO("TDM backend module won't offer a display fd"); + private_module->event_source = NULL; + private_module->fd = -1; + continue; + } - if (!func_display->display_handle_events) { - TDM_ERR("no display_handle_events function"); - return; - } + ret = func_display->display_get_fd(private_module->bdata, &fd); - private_loop->backend_source = - tdm_event_loop_add_fd_handler(private_display, fd, - TDM_EVENT_LOOP_READABLE, - _tdm_event_loop_main_fd_handler, - private_display, &ret); - if (!private_loop->backend_source) { - TDM_ERR("no backend fd(%d) source", fd); - return; - } + assert(ret == TDM_ERROR_NONE && fd >= 0); + assert(func_display->display_handle_events); - private_loop->backend_fd = fd; + private_module->event_source = + tdm_event_loop_add_fd_handler(private_display, fd, + TDM_EVENT_LOOP_READABLE, + _tdm_event_loop_main_fd_handler, + private_module, &ret); + if (!private_module->event_source) { + TDM_ERR("no backend fd(%d) source", fd); + return; + } - TDM_INFO("backend fd(%d) source created", private_loop->backend_fd); + private_module->fd = fd; + + TDM_INFO("backend fd(%d) source created", private_module->fd); + } } INTERN int @@ -212,6 +231,8 @@ tdm_event_loop_get_fd(tdm_private_display *private_display) { tdm_private_loop *private_loop = private_display->private_loop; + /* DON'T check TDM_MUTEX_IS_LOCKED here */ + TDM_RETURN_VAL_IF_FAIL(private_loop->wl_loop != NULL, -1); return wl_event_loop_get_fd(private_loop->wl_loop); @@ -222,11 +243,19 @@ tdm_event_loop_dispatch(tdm_private_display *private_display) { tdm_private_loop *private_loop = private_display->private_loop; + /* DON'T check TDM_MUTEX_IS_LOCKED here */ + TDM_RETURN_VAL_IF_FAIL(private_loop->wl_loop != NULL, TDM_ERROR_OPERATION_FAILED); - if (tdm_debug_thread) + if (tdm_debug_module & TDM_DEBUG_EVENT) TDM_INFO("dispatch"); + if (tdm_thread_is_running() && + tdm_thread_in_display_thread(syscall(SYS_gettid))) { + TDM_NEVER_GET_HERE(); + return TDM_ERROR_OPERATION_FAILED; + } + /* Don't set timeout to -1. It can make deadblock by two mutex locks. * If need to set -1, use poll() and call tdm_event_loop_dispatch() after * escaping polling. @@ -234,6 +263,8 @@ tdm_event_loop_dispatch(tdm_private_display *private_display) if (wl_event_loop_dispatch(private_loop->wl_loop, 0) < 0) TDM_ERR("dispatch failed"); + wl_display_flush_clients(private_loop->wl_display); + return TDM_ERROR_NONE; } @@ -243,8 +274,16 @@ tdm_event_loop_flush(tdm_private_display *private_display) { tdm_private_loop *private_loop = private_display->private_loop; + /* DON'T check TDM_MUTEX_IS_LOCKED here */ + TDM_RETURN_IF_FAIL(private_loop->wl_display != NULL); + if (tdm_thread_is_running() && + tdm_thread_in_display_thread(syscall(SYS_gettid))) { + TDM_NEVER_GET_HERE(); + return; + } + wl_display_flush_clients(private_loop->wl_display); } @@ -252,11 +291,16 @@ static int _tdm_event_loop_fd_func(int fd, uint32_t wl_mask, void *data) { tdm_event_loop_source_fd *fd_source = (tdm_event_loop_source_fd*)data; + tdm_private_display *private_display; tdm_event_loop_mask mask = 0; + /* DON'T check TDM_MUTEX_IS_LOCKED here */ + TDM_RETURN_VAL_IF_FAIL(fd_source, 1); TDM_RETURN_VAL_IF_FAIL(fd_source->func, 1); + private_display = fd_source->base.private_display; + if (wl_mask & WL_EVENT_READABLE) mask |= TDM_EVENT_LOOP_READABLE; if (wl_mask & WL_EVENT_WRITABLE) @@ -266,15 +310,17 @@ _tdm_event_loop_fd_func(int fd, uint32_t wl_mask, void *data) if (wl_mask & WL_EVENT_ERROR) mask |= TDM_EVENT_LOOP_ERROR; + _pthread_mutex_lock(&private_display->lock); fd_source->func(fd, mask, fd_source->user_data); + _pthread_mutex_unlock(&private_display->lock); return 1; } -EXTERN tdm_event_loop_source* +EXTERN tdm_event_loop_source * tdm_event_loop_add_fd_handler(tdm_display *dpy, int fd, tdm_event_loop_mask mask, - tdm_event_loop_fd_handler func, void *user_data, - tdm_error *error) + tdm_event_loop_fd_handler func, void *user_data, + tdm_error *error) { tdm_private_display *private_display; tdm_private_loop *private_loop; @@ -282,6 +328,7 @@ tdm_event_loop_add_fd_handler(tdm_display *dpy, int fd, tdm_event_loop_mask mask uint32_t wl_mask = 0; tdm_error ret; + TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED, NULL); TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(dpy, TDM_ERROR_INVALID_PARAMETER, NULL); TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(fd >= 0, TDM_ERROR_INVALID_PARAMETER, NULL); TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(func, TDM_ERROR_INVALID_PARAMETER, NULL); @@ -299,9 +346,13 @@ tdm_event_loop_add_fd_handler(tdm_display *dpy, int fd, tdm_event_loop_mask mask if (mask & TDM_EVENT_LOOP_WRITABLE) wl_mask |= WL_EVENT_WRITABLE; + fd_source->func = func; + fd_source->user_data = user_data; + + fd_source->base.private_display = private_display; fd_source->base.wl_source = wl_event_loop_add_fd(private_loop->wl_loop, - fd, wl_mask, _tdm_event_loop_fd_func, fd_source); + fd, wl_mask, _tdm_event_loop_fd_func, fd_source); if (!fd_source->base.wl_source) { if (error) *error = TDM_ERROR_OUT_OF_MEMORY; @@ -309,14 +360,12 @@ tdm_event_loop_add_fd_handler(tdm_display *dpy, int fd, tdm_event_loop_mask mask return NULL; } - fd_source->private_display = private_display; - fd_source->func = func; - fd_source->user_data = user_data; + LIST_ADDTAIL(&fd_source->base.link, &private_loop->source_list); if (error) *error = TDM_ERROR_NONE; - return (tdm_event_loop_source*)fd_source; + return (tdm_event_loop_source *)fd_source; } EXTERN tdm_error @@ -325,6 +374,7 @@ tdm_event_loop_source_fd_update(tdm_event_loop_source *source, tdm_event_loop_ma tdm_event_loop_source_fd *fd_source = source; uint32_t wl_mask = 0; + TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED); TDM_RETURN_VAL_IF_FAIL(fd_source, TDM_ERROR_INVALID_PARAMETER); if (mask & TDM_EVENT_LOOP_READABLE) @@ -344,24 +394,36 @@ static int _tdm_event_loop_timer_func(void *data) { tdm_event_loop_source_timer *timer_source = (tdm_event_loop_source_timer*)data; + tdm_private_display *private_display; + + /* DON'T check TDM_MUTEX_IS_LOCKED here */ TDM_RETURN_VAL_IF_FAIL(timer_source, 1); TDM_RETURN_VAL_IF_FAIL(timer_source->func, 1); + private_display = timer_source->base.private_display; + + /* TDM event_loop function is actually for TDM backend module. When we call the + * backend's functions, we have to lock the mutex. TDM backend shouldn't consider + * mutex things. + */ + _pthread_mutex_lock(&private_display->lock); timer_source->func(timer_source->user_data); + _pthread_mutex_unlock(&private_display->lock); return 1; } -EXTERN tdm_event_loop_source* +EXTERN tdm_event_loop_source * tdm_event_loop_add_timer_handler(tdm_display *dpy, tdm_event_loop_timer_handler func, - void *user_data, tdm_error *error) + void *user_data, tdm_error *error) { tdm_private_display *private_display; tdm_private_loop *private_loop; tdm_event_loop_source_timer *timer_source; tdm_error ret; + TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED, NULL); TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(dpy, TDM_ERROR_INVALID_PARAMETER, NULL); TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(func, TDM_ERROR_INVALID_PARAMETER, NULL); @@ -373,9 +435,13 @@ tdm_event_loop_add_timer_handler(tdm_display *dpy, tdm_event_loop_timer_handler timer_source = calloc(1, sizeof(tdm_event_loop_source_timer)); TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(timer_source, TDM_ERROR_OUT_OF_MEMORY, NULL); + timer_source->func = func; + timer_source->user_data = user_data; + + timer_source->base.private_display = private_display; timer_source->base.wl_source = wl_event_loop_add_timer(private_loop->wl_loop, - _tdm_event_loop_timer_func, timer_source); + _tdm_event_loop_timer_func, timer_source); if (!timer_source->base.wl_source) { if (error) *error = TDM_ERROR_OUT_OF_MEMORY; @@ -383,21 +449,20 @@ tdm_event_loop_add_timer_handler(tdm_display *dpy, tdm_event_loop_timer_handler return NULL; } - timer_source->private_display = private_display; - timer_source->func = func; - timer_source->user_data = user_data; + LIST_ADDTAIL(&timer_source->base.link, &private_loop->source_list); if (error) *error = TDM_ERROR_NONE; - return (tdm_event_loop_source*)timer_source; + return (tdm_event_loop_source *)timer_source; } EXTERN tdm_error -tdm_event_loop_source_timer_update(tdm_event_loop_source *source, int ms_delay) +tdm_event_loop_source_timer_update(tdm_event_loop_source *source, unsigned int ms_delay) { tdm_event_loop_source_timer *timer_source = source; + TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED); TDM_RETURN_VAL_IF_FAIL(timer_source, TDM_ERROR_INVALID_PARAMETER); if (wl_event_source_timer_update(timer_source->base.wl_source, ms_delay) < 0) { @@ -413,10 +478,203 @@ tdm_event_loop_source_remove(tdm_event_loop_source *source) { tdm_event_loop_source_base *base = (tdm_event_loop_source_base*)source; - if (!base) + TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED()); + + if (!base || !keep_private_loop) return; + LIST_DEL(&base->link); + wl_event_source_remove(base->wl_source); free(source); } + +/* LCOV_EXCL_START */ +static void +_trace_cb_client_destroy(struct wl_listener *listener, void *data) +{ + struct wl_client *client = (struct wl_client *) data; + struct timespec tp; + unsigned int time; + pid_t pid = -1; + const char *proc_name; + char temp[512] = { 0, }, *p = temp; + int len = sizeof(temp), *l = &len; + + wl_client_get_credentials(client, &pid, NULL, NULL); + proc_name = tdm_server_get_client_name(pid); + + clock_gettime(CLOCK_MONOTONIC, &tp); + time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000); + + TDM_SNPRINTF(p, l, "[%10.3f] Server [PID:%d] client destroying", time / 1000.0, pid); + TDM_SNPRINTF(p, l, ", cmd: %s", proc_name ? proc_name : "Unknown"); + + TDM_INFO("%s", temp); + + wl_list_remove(&listener->link); + free(listener); +} + +static void +_trace_reg_client_destroy_listener(struct wl_client *client) +{ + struct wl_listener *listener; + + listener = wl_client_get_destroy_listener(client, _trace_cb_client_destroy); + if (listener) + return; + + listener = calloc(1, sizeof(struct wl_listener)); + TDM_RETURN_IF_FAIL(listener != NULL); + + listener->notify = _trace_cb_client_destroy; + wl_client_add_destroy_listener(client, listener); +} + +static const char * +_trace_get_next_argument(const char *signature, + struct argument_details *details) +{ + details->nullable = 0; + for (; *signature; ++signature) { + switch (*signature) { + case 'i': + case 'u': + case 'f': + case 's': + case 'o': + case 'n': + case 'a': + case 'h': + details->type = *signature; + return signature + 1; + case '?': + details->nullable = 1; + break; + default: + return NULL; + } + } + details->type = '\0'; + return signature; +} + +static struct wl_protocol_logger *_trace_protocol_logger; + +static void +_trace_protocol_logger_cb(void *user_data, + enum wl_protocol_logger_type direction, + const struct wl_protocol_logger_message *message) +{ + int i; + struct argument_details arg; + struct wl_client *client = wl_resource_get_client(message->resource); + const char *signature = message->message->signature; + struct timespec tp; + unsigned int time; + pid_t pid = -1; + const char *proc_name; + char temp[512] = { 0, }, *p = temp; + int len = sizeof(temp), *l = &len; + int send; + + if (client) { + _trace_reg_client_destroy_listener(client); + wl_client_get_credentials(client, &pid, NULL, NULL); + } + + proc_name = tdm_server_get_client_name(pid); + + clock_gettime(CLOCK_MONOTONIC, &tp); + time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000); + + send = (direction == WL_PROTOCOL_LOGGER_EVENT) ? 1 : 0; + + TDM_SNPRINTF(p, l, "[%10.3f] %s%d%s%s@%u.%s(", + time / 1000.0, + send ? "Server -> Client [PID:" : "Server <- Client [PID:", + pid, "] ", + wl_resource_get_class(message->resource), + wl_resource_get_id(message->resource), + message->message->name); + + for (i = 0; i < message->arguments_count; i++) { + signature = _trace_get_next_argument(signature, &arg); + TDM_RETURN_IF_FAIL(signature != NULL); + + if (i > 0) + TDM_SNPRINTF(p, l, ", "); + + switch (arg.type) { + case 'u': + TDM_SNPRINTF(p, l, "%u", message->arguments[i].u); + break; + case 'i': + TDM_SNPRINTF(p, l, "%d", message->arguments[i].i); + break; + case 'f': + TDM_SNPRINTF(p, l, "%f", + wl_fixed_to_double(message->arguments[i].f)); + break; + case 's': + TDM_SNPRINTF(p, l, "\"%s\"", message->arguments[i].s); + break; + case 'o': + if (message->arguments[i].o) + TDM_SNPRINTF(p, l, "%s@%u", + wl_resource_get_class((struct wl_resource *) message->arguments[i].o), + wl_resource_get_id((struct wl_resource *) message->arguments[i].o)); + else + TDM_SNPRINTF(p, l, "nil"); + break; + case 'n': + TDM_SNPRINTF(p, l, "new id %s@", + (message->message->types[i]) ? message->message->types[i]->name : "[unknown]"); + if (message->arguments[i].n != 0) + TDM_SNPRINTF(p, l, "%u", message->arguments[i].n); + else + TDM_SNPRINTF(p, l, "nil"); + break; + case 'a': + TDM_SNPRINTF(p, l, "array"); + break; + case 'h': + TDM_SNPRINTF(p, l, "fd %d", message->arguments[i].h); + break; + default: + return; + } + } + + TDM_SNPRINTF(p, l, "), cmd: %s", proc_name ? proc_name : "Unknown"); + + TDM_INFO("%s", temp); +} + +INTERN tdm_error +tdm_event_loop_trace_enable(tdm_private_display * private_display, + unsigned int enable) +{ + tdm_private_loop *private_loop = private_display->private_loop; + + TDM_RETURN_VAL_IF_FAIL(private_loop->wl_display != NULL, TDM_ERROR_NONE); + + if (!enable) { + if (_trace_protocol_logger) { + wl_protocol_logger_destroy(_trace_protocol_logger); + _trace_protocol_logger = NULL; + } + return TDM_ERROR_NONE; + } + + if (_trace_protocol_logger) + wl_protocol_logger_destroy(_trace_protocol_logger); + + _trace_protocol_logger = + wl_display_add_protocol_logger(private_loop->wl_display, _trace_protocol_logger_cb, NULL); + + return TDM_ERROR_NONE; +} +/* LCOV_EXCL_STOP */