From: Boram Park Date: Tue, 2 May 2017 04:47:32 +0000 (+0900) Subject: monitor: add trace option to debug server-client protocol X-Git-Tag: accepted/tizen/3.0/common/20170515.150157~3 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F38%2F128638%2F2;p=platform%2Fcore%2Fuifw%2Flibtdm.git monitor: add trace option to debug server-client protocol Change-Id: Id27af997282b51db1541e2d7e59e521d95097d66 --- diff --git a/src/tdm_event_loop.c b/src/tdm_event_loop.c index a2cac7e..7445ad5 100644 --- a/src/tdm_event_loop.c +++ b/src/tdm_event_loop.c @@ -461,3 +461,284 @@ tdm_event_loop_source_remove(tdm_event_loop_source *source) free(source); } + +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; +} + +#if !TDM_WAYLAND_LOGGER + +static void +_trace_protocol_cb(struct wl_closure *closure, struct wl_resource *resource, int send) +{ + int i; + struct argument_details arg; + struct wl_object *object = &resource->object; + struct wl_client *client = resource->client; + const char *signature = closure->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; + + 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); + + TDM_SNPRINTF(p, l, "[%10.3f] %s%d%s%s@%u.%s(", + time / 1000.0, + send ? "Server -> Client [PID:" : "Server <- Client [PID:", + pid, "] ", + object->interface->name, object->id, closure->message->name); + + for (i = 0; i < closure->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", closure->args[i].u); + break; + case 'i': + TDM_SNPRINTF(p, l, "%d", closure->args[i].i); + break; + case 'f': + TDM_SNPRINTF(p, l, "%f", wl_fixed_to_double(closure->args[i].f)); + break; + case 's': + TDM_SNPRINTF(p, l, "\"%s\"", closure->args[i].s); + break; + case 'o': + if (closure->args[i].o) + TDM_SNPRINTF(p, l, "%s@%u", closure->args[i].o->interface->name, closure->args[i].o->id); + else + TDM_SNPRINTF(p, l, "nil"); + break; + case 'n': + TDM_SNPRINTF(p, l, "new id %s@", + (closure->message->types[i]) ? closure->message->types[i]->name : "[unknown]"); + if (closure->args[i].n != 0) + TDM_SNPRINTF(p, l, "%u", closure->args[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", closure->args[i].h); + break; + default: + return; + } + } + + TDM_SNPRINTF(p, l, "), cmd: %s", proc_name ? proc_name : "Unknown"); + + TDM_INFO("%s", temp); +} + +#else + +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_name(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_name((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); +} +#endif + +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 !TDM_WAYLAND_LOGGER + wl_debug_server_debug_func_set(NULL); +#else + if (_trace_protocol_logger) { + wl_protocol_logger_destroy(_trace_protocol_logger); + _trace_protocol_logger = NULL; + } +#endif + return TDM_ERROR_NONE; + } + +#if !TDM_WAYLAND_LOGGER + wl_debug_server_debug_func_set((wl_server_debug_func_ptr) _trace_protocol_cb); +#else + 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); +#endif + + return TDM_ERROR_NONE; +} diff --git a/src/tdm_monitor_server.c b/src/tdm_monitor_server.c index d12a9eb..2df4dd3 100644 --- a/src/tdm_monitor_server.c +++ b/src/tdm_monitor_server.c @@ -54,6 +54,23 @@ _tdm_monitor_server_query(unsigned int pid, char *cwd, int argc, char *argv[], c } static void +_tdm_monitor_server_protocol_trace(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy) +{ + int enable; + + if (argc < 3) { + _tdm_monitor_server_usage(argv[0], reply, len); + return; + } + + enable = atoi(argv[2]); + + tdm_event_loop_trace_enable(dpy, enable); + + TDM_SNPRINTF(reply, len, "protocol trace: '%s'\n", (enable) ? "enabled" : "disabled"); +} + +static void _tdm_monitor_server_dpms(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy) { tdm_output *output; @@ -463,6 +480,12 @@ static struct { "show tdm output, layer information", NULL, NULL }, { + "trace", _tdm_monitor_server_protocol_trace, + "enable/disable the wl protocol", + "", + "0 or 1" + }, + { "dpms", _tdm_monitor_server_dpms, "set output dpms", ":", "0:3 or 0:0" }, diff --git a/src/tdm_private.h b/src/tdm_private.h index 4552a5e..59cb1ad 100644 --- a/src/tdm_private.h +++ b/src/tdm_private.h @@ -499,6 +499,8 @@ tdm_error tdm_event_loop_dispatch(tdm_private_display *private_display); void tdm_event_loop_flush(tdm_private_display *private_display); +tdm_error +tdm_event_loop_trace_enable(tdm_private_display *private_display, unsigned int enable); typedef enum { TDM_THREAD_CB_NONE, @@ -692,6 +694,33 @@ tdm_display_enable_fps(tdm_private_display *private_display, int enable); void tdm_monitor_server_command(tdm_display *dpy, const char *options, char *reply, int *len); + + +#define TDM_WAYLAND_LOGGER ((WAYLAND_VERSION_MAJOR == 1) && (WAYLAND_VERSION_MINOR > 11)) + +#if !TDM_WAYLAND_LOGGER +#ifndef WL_CLOSURE_MAX_ARGS +#define WL_CLOSURE_MAX_ARGS 20 +#endif + +struct wl_closure { + int count; + const struct wl_message *message; + uint32_t opcode; + uint32_t sender_id; + union wl_argument args[WL_CLOSURE_MAX_ARGS]; + struct wl_list link; + struct wl_proxy *proxy; + struct wl_array extra[0]; +}; +#endif /* TDM_WAYLAND_LOGGER */ + +struct argument_details { + char type; + int nullable; +}; + + #ifdef __cplusplus } #endif