monitor: add trace option to debug server-client protocol 38/128638/2
authorBoram Park <boram1288.park@samsung.com>
Tue, 2 May 2017 04:47:32 +0000 (13:47 +0900)
committerBoram Park <boram1288.park@samsung.com>
Wed, 10 May 2017 23:12:25 +0000 (08:12 +0900)
Change-Id: Id27af997282b51db1541e2d7e59e521d95097d66

src/tdm_event_loop.c
src/tdm_monitor_server.c
src/tdm_private.h

index a2cac7e..7445ad5 100644 (file)
@@ -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;
+}
index d12a9eb..2df4dd3 100644 (file)
@@ -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",
+               "<enable>",
+               "0 or 1"
+       },
+       {
                "dpms", _tdm_monitor_server_dpms,
                "set output dpms", "<output_idx>:<dpms>", "0:3 or 0:0"
        },
index 4552a5e..59cb1ad 100644 (file)
@@ -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