monitor: add trace option to debug server-client protocol
[platform/core/uifw/libtdm.git] / src / tdm_event_loop.c
1 /**************************************************************************
2  *
3  * libtdm
4  *
5  * Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
6  *
7  * Contact: Eunchul Kim <chulspro.kim@samsung.com>,
8  *          JinYoung Jeon <jy0.jeon@samsung.com>,
9  *          Taeheon Kim <th908.kim@samsung.com>,
10  *          YoungJun Cho <yj44.cho@samsung.com>,
11  *          SooChan Lim <sc1.lim@samsung.com>,
12  *          Boram Park <sc1.lim@samsung.com>
13  *
14  * Permission is hereby granted, free of charge, to any person obtaining a
15  * copy of this software and associated documentation files (the
16  * "Software"), to deal in the Software without restriction, including
17  * without limitation the rights to use, copy, modify, merge, publish,
18  * distribute, sub license, and/or sell copies of the Software, and to
19  * permit persons to whom the Software is furnished to do so, subject to
20  * the following conditions:
21  *
22  * The above copyright notice and this permission notice (including the
23  * next paragraph) shall be included in all copies or substantial portions
24  * of the Software.
25  *
26  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
27  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
29  * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
30  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
31  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
32  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33  *
34 **************************************************************************/
35
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39
40 #include "tdm.h"
41 #include "tdm_private.h"
42 #include "tdm_list.h"
43
44 #include <wayland-server-core.h>
45
46 typedef struct _tdm_event_loop_source_base {
47         struct wl_event_source *wl_source;
48 } tdm_event_loop_source_base;
49
50 typedef struct _tdm_event_loop_source_fd {
51         tdm_event_loop_source_base base;
52         tdm_private_display *private_display;
53         tdm_event_loop_fd_handler func;
54         void *user_data;
55 } tdm_event_loop_source_fd;
56
57 typedef struct _tdm_event_loop_source_timer {
58         tdm_event_loop_source_base base;
59         tdm_private_display *private_display;
60         tdm_event_loop_timer_handler func;
61         void *user_data;
62 } tdm_event_loop_source_timer;
63
64 static tdm_error
65 _tdm_event_loop_main_fd_handler(int fd, tdm_event_loop_mask mask, void *user_data)
66 {
67         tdm_private_display *private_display = (tdm_private_display*)user_data;
68         tdm_private_loop *private_loop;
69         tdm_func_display *func_display;
70         tdm_error ret;
71
72         TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED);
73         TDM_RETURN_VAL_IF_FAIL(private_display != NULL, TDM_ERROR_OPERATION_FAILED);
74         TDM_RETURN_VAL_IF_FAIL(private_display->private_loop != NULL, TDM_ERROR_OPERATION_FAILED);
75
76         private_loop = private_display->private_loop;
77
78         if (tdm_debug_module & TDM_DEBUG_THREAD)
79                 TDM_INFO("backend fd(%d) event happens", private_loop->backend_fd);
80
81         func_display = &private_display->func_display;
82         if (!func_display->display_handle_events)
83                 return TDM_ERROR_NONE;
84
85         ret = func_display->display_handle_events(private_display->bdata);
86
87         return ret;
88 }
89
90 INTERN tdm_error
91 tdm_event_loop_init(tdm_private_display *private_display)
92 {
93         tdm_private_loop *private_loop;
94         tdm_error ret;
95
96         TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED);
97
98         if (private_display->private_loop)
99                 return TDM_ERROR_NONE;
100
101         private_loop = calloc(1, sizeof * private_loop);
102         if (!private_loop) {
103                 TDM_ERR("alloc failed");
104                 return TDM_ERROR_OUT_OF_MEMORY;
105         }
106
107         private_loop->backend_fd = -1;
108
109         private_loop->wl_display = wl_display_create();
110         if (!private_loop->wl_display) {
111                 TDM_ERR("creating a wayland display failed");
112                 free(private_loop);
113                 return TDM_ERROR_OUT_OF_MEMORY;
114         }
115         private_loop->wl_loop = wl_display_get_event_loop(private_loop->wl_display);
116
117         ret = tdm_server_init(private_loop);
118         if (ret != TDM_ERROR_NONE) {
119                 TDM_ERR("server init failed");
120                 wl_display_destroy(private_loop->wl_display);
121                 free(private_loop);
122                 return TDM_ERROR_OPERATION_FAILED;
123         }
124
125         private_loop->dpy = private_display;
126         private_display->private_loop = private_loop;
127
128         ret = tdm_thread_init(private_loop);
129         if (ret != TDM_ERROR_NONE) {
130                 TDM_ERR("thread init failed");
131                 tdm_server_deinit(private_loop);
132                 wl_display_destroy(private_loop->wl_display);
133                 free(private_loop);
134                 return TDM_ERROR_OPERATION_FAILED;
135         }
136
137         TDM_INFO("event loop fd(%d)", wl_event_loop_get_fd(private_loop->wl_loop));
138
139         return TDM_ERROR_NONE;
140 }
141
142 INTERN void
143 tdm_event_loop_deinit(tdm_private_display *private_display)
144 {
145         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
146
147         if (!private_display->private_loop)
148                 return;
149
150         /* after tdm_thread_deinit, we don't worry about thread things because it's finalized */
151         tdm_thread_deinit(private_display->private_loop);
152         tdm_server_deinit(private_display->private_loop);
153
154         if (private_display->private_loop->backend_source)
155                 tdm_event_loop_source_remove(private_display->private_loop->backend_source);
156
157         if (private_display->private_loop->wl_display)
158                 wl_display_destroy(private_display->private_loop->wl_display);
159
160         free(private_display->private_loop);
161         private_display->private_loop = NULL;
162 }
163
164 INTERN void
165 tdm_event_loop_create_backend_source(tdm_private_display *private_display)
166 {
167         tdm_private_loop *private_loop = private_display->private_loop;
168         tdm_func_display *func_display;
169         tdm_error ret;
170         int fd = -1;
171
172         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
173         TDM_RETURN_IF_FAIL(private_loop != NULL);
174
175         func_display = &private_display->func_display;
176         if (!func_display->display_get_fd) {
177                 TDM_INFO("TDM backend module won't offer a display fd");
178                 return;
179         }
180
181         ret = func_display->display_get_fd(private_display->bdata, &fd);
182         if (fd < 0) {
183                 TDM_ERR("TDM backend module returns fd(%d)", fd);
184                 return;
185         }
186
187         if (!func_display->display_handle_events) {
188                 TDM_ERR("no display_handle_events function");
189                 return;
190         }
191
192         private_loop->backend_source =
193                 tdm_event_loop_add_fd_handler(private_display, fd,
194                                                                           TDM_EVENT_LOOP_READABLE,
195                                                                           _tdm_event_loop_main_fd_handler,
196                                                                           private_display, &ret);
197         if (!private_loop->backend_source) {
198                 TDM_ERR("no backend fd(%d) source", fd);
199                 return;
200         }
201
202         private_loop->backend_fd = fd;
203
204         TDM_INFO("backend fd(%d) source created", private_loop->backend_fd);
205 }
206
207 INTERN int
208 tdm_event_loop_get_fd(tdm_private_display *private_display)
209 {
210         tdm_private_loop *private_loop = private_display->private_loop;
211
212         /* DON'T check TDM_MUTEX_IS_LOCKED here */
213
214         TDM_RETURN_VAL_IF_FAIL(private_loop->wl_loop != NULL, -1);
215
216         return wl_event_loop_get_fd(private_loop->wl_loop);
217 }
218
219 INTERN tdm_error
220 tdm_event_loop_dispatch(tdm_private_display *private_display)
221 {
222         tdm_private_loop *private_loop = private_display->private_loop;
223
224         /* DON'T check TDM_MUTEX_IS_LOCKED here */
225
226         TDM_RETURN_VAL_IF_FAIL(private_loop->wl_loop != NULL, TDM_ERROR_OPERATION_FAILED);
227
228         if (tdm_debug_module & TDM_DEBUG_THREAD)
229                 TDM_INFO("dispatch");
230
231         if (tdm_thread_is_running() &&
232                 tdm_thread_in_display_thread(syscall(SYS_gettid))) {
233                 TDM_NEVER_GET_HERE();
234                 return TDM_ERROR_OPERATION_FAILED;
235         }
236
237         /* Don't set timeout to -1. It can make deadblock by two mutex locks.
238          * If need to set -1, use poll() and call tdm_event_loop_dispatch() after
239          * escaping polling.
240          */
241         if (wl_event_loop_dispatch(private_loop->wl_loop, 0) < 0)
242                 TDM_ERR("dispatch failed");
243
244         wl_display_flush_clients(private_loop->wl_display);
245
246         return TDM_ERROR_NONE;
247 }
248
249
250 INTERN void
251 tdm_event_loop_flush(tdm_private_display *private_display)
252 {
253         tdm_private_loop *private_loop = private_display->private_loop;
254
255         /* DON'T check TDM_MUTEX_IS_LOCKED here */
256
257         TDM_RETURN_IF_FAIL(private_loop->wl_display != NULL);
258
259         if (tdm_thread_is_running() &&
260                 tdm_thread_in_display_thread(syscall(SYS_gettid))) {
261                 TDM_NEVER_GET_HERE();
262                 return;
263         }
264
265         wl_display_flush_clients(private_loop->wl_display);
266 }
267
268 static int
269 _tdm_event_loop_fd_func(int fd, uint32_t wl_mask, void *data)
270 {
271         tdm_event_loop_source_fd *fd_source = (tdm_event_loop_source_fd*)data;
272         tdm_private_display *private_display;
273         tdm_event_loop_mask mask = 0;
274
275         /* DON'T check TDM_MUTEX_IS_LOCKED here */
276
277         TDM_RETURN_VAL_IF_FAIL(fd_source, 1);
278         TDM_RETURN_VAL_IF_FAIL(fd_source->func, 1);
279
280         private_display = fd_source->private_display;
281
282         if (wl_mask & WL_EVENT_READABLE)
283                 mask |= TDM_EVENT_LOOP_READABLE;
284         if (wl_mask & WL_EVENT_WRITABLE)
285                 mask |= TDM_EVENT_LOOP_WRITABLE;
286         if (wl_mask & WL_EVENT_HANGUP)
287                 mask |= TDM_EVENT_LOOP_HANGUP;
288         if (wl_mask & WL_EVENT_ERROR)
289                 mask |= TDM_EVENT_LOOP_ERROR;
290
291         _pthread_mutex_lock(&private_display->lock);
292         fd_source->func(fd, mask, fd_source->user_data);
293         _pthread_mutex_unlock(&private_display->lock);
294
295         return 1;
296 }
297
298 EXTERN tdm_event_loop_source *
299 tdm_event_loop_add_fd_handler(tdm_display *dpy, int fd, tdm_event_loop_mask mask,
300                                                           tdm_event_loop_fd_handler func, void *user_data,
301                                                           tdm_error *error)
302 {
303         tdm_private_display *private_display;
304         tdm_private_loop *private_loop;
305         tdm_event_loop_source_fd *fd_source;
306         uint32_t wl_mask = 0;
307         tdm_error ret;
308
309         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED, NULL);
310         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(dpy, TDM_ERROR_INVALID_PARAMETER, NULL);
311         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(fd >= 0, TDM_ERROR_INVALID_PARAMETER, NULL);
312         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(func, TDM_ERROR_INVALID_PARAMETER, NULL);
313
314         private_display = (tdm_private_display*)dpy;
315         private_loop = private_display->private_loop;
316         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(private_loop, TDM_ERROR_INVALID_PARAMETER, NULL);
317         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(private_loop->wl_loop, TDM_ERROR_INVALID_PARAMETER, NULL);
318
319         fd_source = calloc(1, sizeof(tdm_event_loop_source_fd));
320         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(fd_source, TDM_ERROR_OUT_OF_MEMORY, NULL);
321
322         if (mask & TDM_EVENT_LOOP_READABLE)
323                 wl_mask |= WL_EVENT_READABLE;
324         if (mask & TDM_EVENT_LOOP_WRITABLE)
325                 wl_mask |= WL_EVENT_WRITABLE;
326
327         fd_source->private_display = private_display;
328         fd_source->func = func;
329         fd_source->user_data = user_data;
330
331         fd_source->base.wl_source =
332                 wl_event_loop_add_fd(private_loop->wl_loop,
333                                                          fd, wl_mask, _tdm_event_loop_fd_func, fd_source);
334         if (!fd_source->base.wl_source) {
335                 if (error)
336                         *error = TDM_ERROR_OUT_OF_MEMORY;
337                 free(fd_source);
338                 return NULL;
339         }
340
341         if (error)
342                 *error = TDM_ERROR_NONE;
343
344         return (tdm_event_loop_source *)fd_source;
345 }
346
347 EXTERN tdm_error
348 tdm_event_loop_source_fd_update(tdm_event_loop_source *source, tdm_event_loop_mask mask)
349 {
350         tdm_event_loop_source_fd *fd_source = source;
351         uint32_t wl_mask = 0;
352
353         TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED);
354         TDM_RETURN_VAL_IF_FAIL(fd_source, TDM_ERROR_INVALID_PARAMETER);
355
356         if (mask & TDM_EVENT_LOOP_READABLE)
357                 wl_mask |= WL_EVENT_READABLE;
358         if (mask & TDM_EVENT_LOOP_WRITABLE)
359                 wl_mask |= WL_EVENT_WRITABLE;
360
361         if (wl_event_source_fd_update(fd_source->base.wl_source, wl_mask) < 0) {
362                 TDM_ERR("source update failed: %m");
363                 return TDM_ERROR_OPERATION_FAILED;
364         }
365
366         return TDM_ERROR_NONE;
367 }
368
369 static int
370 _tdm_event_loop_timer_func(void *data)
371 {
372         tdm_event_loop_source_timer *timer_source = (tdm_event_loop_source_timer*)data;
373         tdm_private_display *private_display;
374
375         /* DON'T check TDM_MUTEX_IS_LOCKED here */
376
377         TDM_RETURN_VAL_IF_FAIL(timer_source, 1);
378         TDM_RETURN_VAL_IF_FAIL(timer_source->func, 1);
379
380         private_display = timer_source->private_display;
381
382         /* TDM event_loop function is actually for TDM backend module. When we call the
383          * backend's functions, we have to lock the mutex. TDM backend shouldn't consider
384          * mutex things.
385          */
386         _pthread_mutex_lock(&private_display->lock);
387         timer_source->func(timer_source->user_data);
388         _pthread_mutex_unlock(&private_display->lock);
389
390         return 1;
391 }
392
393 EXTERN tdm_event_loop_source *
394 tdm_event_loop_add_timer_handler(tdm_display *dpy, tdm_event_loop_timer_handler func,
395                                                                  void *user_data, tdm_error *error)
396 {
397         tdm_private_display *private_display;
398         tdm_private_loop *private_loop;
399         tdm_event_loop_source_timer *timer_source;
400         tdm_error ret;
401
402         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED, NULL);
403         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(dpy, TDM_ERROR_INVALID_PARAMETER, NULL);
404         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(func, TDM_ERROR_INVALID_PARAMETER, NULL);
405
406         private_display = (tdm_private_display*)dpy;
407         private_loop = private_display->private_loop;
408         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(private_loop, TDM_ERROR_INVALID_PARAMETER, NULL);
409         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(private_loop->wl_loop, TDM_ERROR_INVALID_PARAMETER, NULL);
410
411         timer_source = calloc(1, sizeof(tdm_event_loop_source_timer));
412         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(timer_source, TDM_ERROR_OUT_OF_MEMORY, NULL);
413
414         timer_source->private_display = private_display;
415         timer_source->func = func;
416         timer_source->user_data = user_data;
417
418         timer_source->base.wl_source =
419                 wl_event_loop_add_timer(private_loop->wl_loop,
420                                                                 _tdm_event_loop_timer_func, timer_source);
421         if (!timer_source->base.wl_source) {
422                 if (error)
423                         *error = TDM_ERROR_OUT_OF_MEMORY;
424                 free(timer_source);
425                 return NULL;
426         }
427
428         if (error)
429                 *error = TDM_ERROR_NONE;
430
431         return (tdm_event_loop_source *)timer_source;
432 }
433
434 EXTERN tdm_error
435 tdm_event_loop_source_timer_update(tdm_event_loop_source *source, unsigned int ms_delay)
436 {
437         tdm_event_loop_source_timer *timer_source = source;
438
439         TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED);
440         TDM_RETURN_VAL_IF_FAIL(timer_source, TDM_ERROR_INVALID_PARAMETER);
441
442         if (wl_event_source_timer_update(timer_source->base.wl_source, ms_delay) < 0) {
443                 TDM_ERR("source update failed: %m");
444                 return TDM_ERROR_OPERATION_FAILED;
445         }
446
447         return TDM_ERROR_NONE;
448 }
449
450 EXTERN void
451 tdm_event_loop_source_remove(tdm_event_loop_source *source)
452 {
453         tdm_event_loop_source_base *base = (tdm_event_loop_source_base*)source;
454
455         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
456
457         if (!base)
458                 return;
459
460         wl_event_source_remove(base->wl_source);
461
462         free(source);
463 }
464
465 static void
466 _trace_cb_client_destroy(struct wl_listener *listener, void *data)
467 {
468         struct wl_client *client = (struct wl_client *) data;
469         struct timespec tp;
470         unsigned int time;
471         pid_t pid = -1;
472         const char *proc_name;
473         char temp[512] = { 0, }, *p = temp;
474         int len = sizeof(temp), *l = &len;
475
476         wl_client_get_credentials(client, &pid, NULL, NULL);
477         proc_name = tdm_server_get_client_name(pid);
478
479         clock_gettime(CLOCK_MONOTONIC, &tp);
480         time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
481
482         TDM_SNPRINTF(p, l, "[%10.3f] Server           [PID:%d] client destroying", time / 1000.0, pid);
483         TDM_SNPRINTF(p, l, ", cmd: %s", proc_name ? proc_name : "Unknown");
484
485         TDM_INFO("%s", temp);
486
487         wl_list_remove(&listener->link);
488         free(listener);
489 }
490
491 static void
492 _trace_reg_client_destroy_listener(struct wl_client *client)
493 {
494         struct wl_listener *listener;
495
496         listener = wl_client_get_destroy_listener(client, _trace_cb_client_destroy);
497         if (listener)
498                 return;
499
500         listener = calloc(1, sizeof(struct wl_listener));
501         TDM_RETURN_IF_FAIL(listener != NULL);
502
503         listener->notify = _trace_cb_client_destroy;
504         wl_client_add_destroy_listener(client, listener);
505 }
506
507 static const char *
508 _trace_get_next_argument(const char *signature,
509                                                  struct argument_details *details)
510 {
511         details->nullable = 0;
512         for (; *signature; ++signature) {
513                 switch (*signature) {
514                 case 'i':
515                 case 'u':
516                 case 'f':
517                 case 's':
518                 case 'o':
519                 case 'n':
520                 case 'a':
521                 case 'h':
522                         details->type = *signature;
523                         return signature + 1;
524                 case '?':
525                         details->nullable = 1;
526                         break;
527                 default:
528                         return NULL;
529                 }
530         }
531         details->type = '\0';
532         return signature;
533 }
534
535 #if !TDM_WAYLAND_LOGGER
536
537 static void
538 _trace_protocol_cb(struct wl_closure *closure, struct wl_resource *resource, int send)
539 {
540         int i;
541         struct argument_details arg;
542         struct wl_object *object = &resource->object;
543         struct wl_client *client = resource->client;
544         const char *signature = closure->message->signature;
545         struct timespec tp;
546         unsigned int time;
547         pid_t pid = -1;
548         const char *proc_name;
549         char temp[512] = { 0, }, *p = temp;
550         int len = sizeof(temp), *l = &len;
551
552         if (client) {
553                 _trace_reg_client_destroy_listener(client);
554                 wl_client_get_credentials(client, &pid, NULL, NULL);
555         }
556
557         proc_name = tdm_server_get_client_name(pid);
558
559         clock_gettime(CLOCK_MONOTONIC, &tp);
560         time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
561
562         TDM_SNPRINTF(p, l, "[%10.3f] %s%d%s%s@%u.%s(",
563                                  time / 1000.0,
564                                  send ? "Server -> Client [PID:" : "Server <- Client [PID:",
565                                  pid, "] ",
566                                  object->interface->name, object->id, closure->message->name);
567
568         for (i = 0; i < closure->count; i++) {
569                 signature = _trace_get_next_argument(signature, &arg);
570                 TDM_RETURN_IF_FAIL(signature != NULL);
571
572                 if (i > 0)
573                         TDM_SNPRINTF(p, l, ", ");
574
575                 switch (arg.type) {
576                 case 'u':
577                         TDM_SNPRINTF(p, l, "%u", closure->args[i].u);
578                         break;
579                 case 'i':
580                         TDM_SNPRINTF(p, l, "%d", closure->args[i].i);
581                         break;
582                 case 'f':
583                         TDM_SNPRINTF(p, l, "%f", wl_fixed_to_double(closure->args[i].f));
584                         break;
585                 case 's':
586                         TDM_SNPRINTF(p, l, "\"%s\"", closure->args[i].s);
587                         break;
588                 case 'o':
589                         if (closure->args[i].o)
590                                 TDM_SNPRINTF(p, l, "%s@%u", closure->args[i].o->interface->name, closure->args[i].o->id);
591                         else
592                                 TDM_SNPRINTF(p, l, "nil");
593                         break;
594                 case 'n':
595                         TDM_SNPRINTF(p, l, "new id %s@",
596                                                  (closure->message->types[i]) ? closure->message->types[i]->name : "[unknown]");
597                         if (closure->args[i].n != 0)
598                                 TDM_SNPRINTF(p, l, "%u", closure->args[i].n);
599                         else
600                                 TDM_SNPRINTF(p, l, "nil");
601                         break;
602                 case 'a':
603                         TDM_SNPRINTF(p, l, "array");
604                         break;
605                 case 'h':
606                         TDM_SNPRINTF(p, l, "fd %d", closure->args[i].h);
607                         break;
608                 default:
609                         return;
610                 }
611         }
612
613         TDM_SNPRINTF(p, l, "), cmd: %s", proc_name ? proc_name : "Unknown");
614
615         TDM_INFO("%s", temp);
616 }
617
618 #else
619
620 static struct wl_protocol_logger *_trace_protocol_logger;
621
622 static void
623 _trace_protocol_logger_cb(void *user_data,
624                                                   enum wl_protocol_logger_type direction,
625                                                   const struct wl_protocol_logger_message *message)
626 {
627         int i;
628         struct argument_details arg;
629         struct wl_client *client = wl_resource_get_client(message->resource);
630         const char *signature = message->message->signature;
631         struct timespec tp;
632         unsigned int time;
633         pid_t pid = -1;
634         const char *proc_name;
635         char temp[512] = { 0, }, *p = temp;
636         int len = sizeof(temp), *l = &len;
637         int send;
638
639         if (client) {
640                 _trace_reg_client_destroy_listener(client);
641                 wl_client_get_credentials(client, &pid, NULL, NULL);
642         }
643
644         proc_name = tdm_server_get_client_name(pid);
645
646         clock_gettime(CLOCK_MONOTONIC, &tp);
647         time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
648
649         send = (direction == WL_PROTOCOL_LOGGER_EVENT) ? 1 : 0;
650
651         TDM_SNPRINTF(p, l, "[%10.3f] %s%d%s%s@%u.%s(",
652                                  time / 1000.0,
653                                  send ? "Server -> Client [PID:" : "Server <- Client [PID:",
654                                  pid, "] ",
655                                  wl_resource_get_name(message->resource),
656                                  wl_resource_get_id(message->resource),
657                                  message->message->name);
658
659         for (i = 0; i < message->arguments_count; i++) {
660                 signature = _trace_get_next_argument(signature, &arg);
661                 TDM_RETURN_IF_FAIL(signature != NULL);
662
663                 if (i > 0)
664                         TDM_SNPRINTF(p, l, ", ");
665
666                 switch (arg.type) {
667                 case 'u':
668                         TDM_SNPRINTF(p, l, "%u", message->arguments[i].u);
669                         break;
670                 case 'i':
671                         TDM_SNPRINTF(p, l, "%d", message->arguments[i].i);
672                         break;
673                 case 'f':
674                         TDM_SNPRINTF(p, l, "%f",
675                                                  wl_fixed_to_double(message->arguments[i].f));
676                         break;
677                 case 's':
678                         TDM_SNPRINTF(p, l, "\"%s\"", message->arguments[i].s);
679                         break;
680                 case 'o':
681                         if (message->arguments[i].o)
682                                 TDM_SNPRINTF(p, l, "%s@%u",
683                                                          wl_resource_get_name((struct wl_resource *) message->arguments[i].o),
684                                                          wl_resource_get_id((struct wl_resource *) message->arguments[i].o));
685                         else
686                                 TDM_SNPRINTF(p, l, "nil");
687                         break;
688                 case 'n':
689                         TDM_SNPRINTF(p, l, "new id %s@",
690                                                  (message->message->types[i]) ? message->message->types[i]->name : "[unknown]");
691                         if (message->arguments[i].n != 0)
692                                 TDM_SNPRINTF(p, l, "%u", message->arguments[i].n);
693                         else
694                                 TDM_SNPRINTF(p, l, "nil");
695                         break;
696                 case 'a':
697                         TDM_SNPRINTF(p, l, "array");
698                         break;
699                 case 'h':
700                         TDM_SNPRINTF(p, l, "fd %d", message->arguments[i].h);
701                         break;
702                 default:
703                         return;
704                 }
705         }
706
707         TDM_SNPRINTF(p, l, "), cmd: %s", proc_name ? proc_name : "Unknown");
708
709         TDM_INFO("%s", temp);
710 }
711 #endif
712
713 INTERN tdm_error
714 tdm_event_loop_trace_enable(tdm_private_display * private_display,
715                                                         unsigned int enable)
716 {
717         tdm_private_loop *private_loop = private_display->private_loop;
718
719         TDM_RETURN_VAL_IF_FAIL(private_loop->wl_display != NULL, TDM_ERROR_NONE);
720
721         if (!enable) {
722 #if !TDM_WAYLAND_LOGGER
723                 wl_debug_server_debug_func_set(NULL);
724 #else
725                 if (_trace_protocol_logger) {
726                         wl_protocol_logger_destroy(_trace_protocol_logger);
727                         _trace_protocol_logger = NULL;
728                 }
729 #endif
730                 return TDM_ERROR_NONE;
731         }
732
733 #if !TDM_WAYLAND_LOGGER
734         wl_debug_server_debug_func_set((wl_server_debug_func_ptr) _trace_protocol_cb);
735 #else
736         if (_trace_protocol_logger)
737                 wl_protocol_logger_destroy(_trace_protocol_logger);
738
739         _trace_protocol_logger =
740                 wl_display_add_protocol_logger(private_loop->wl_display, _trace_protocol_logger_cb, NULL);
741 #endif
742
743         return TDM_ERROR_NONE;
744 }