add excluding coverage comments for tdm_event_loop.c for folowing code:
[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         if (tdm_thread_is_running())
151                 TDM_ERR("thread is still running. tdm_event_loop_stop SHOULD be called");
152
153         tdm_server_deinit(private_display->private_loop);
154
155         if (private_display->private_loop->backend_source)
156                 tdm_event_loop_source_remove(private_display->private_loop->backend_source);
157
158         if (private_display->private_loop->wl_display)
159                 wl_display_destroy(private_display->private_loop->wl_display);
160
161         free(private_display->private_loop);
162         private_display->private_loop = NULL;
163 }
164
165 INTERN void
166 tdm_event_loop_stop(tdm_private_display *private_display)
167 {
168         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
169
170         /* after tdm_thread_deinit, we don't worry about thread things because it's finalized */
171         tdm_thread_deinit(private_display->private_loop);
172 }
173
174 INTERN void
175 tdm_event_loop_create_backend_source(tdm_private_display *private_display)
176 {
177         tdm_private_loop *private_loop = private_display->private_loop;
178         tdm_func_display *func_display;
179         tdm_error ret;
180         int fd = -1;
181
182         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
183         TDM_RETURN_IF_FAIL(private_loop != NULL);
184
185         func_display = &private_display->func_display;
186         if (!func_display->display_get_fd) {
187                 TDM_INFO("TDM backend module won't offer a display fd");
188                 return;
189         }
190
191         ret = func_display->display_get_fd(private_display->bdata, &fd);
192         if (fd < 0) {
193                 TDM_ERR("TDM backend module returns fd(%d)", fd);
194                 return;
195         }
196
197         if (!func_display->display_handle_events) {
198                 TDM_ERR("no display_handle_events function");
199                 return;
200         }
201
202         private_loop->backend_source =
203                 tdm_event_loop_add_fd_handler(private_display, fd,
204                                                                           TDM_EVENT_LOOP_READABLE,
205                                                                           _tdm_event_loop_main_fd_handler,
206                                                                           private_display, &ret);
207         if (!private_loop->backend_source) {
208                 TDM_ERR("no backend fd(%d) source", fd);
209                 return;
210         }
211
212         private_loop->backend_fd = fd;
213
214         TDM_INFO("backend fd(%d) source created", private_loop->backend_fd);
215 }
216
217 INTERN int
218 tdm_event_loop_get_fd(tdm_private_display *private_display)
219 {
220         tdm_private_loop *private_loop = private_display->private_loop;
221
222         /* DON'T check TDM_MUTEX_IS_LOCKED here */
223
224         TDM_RETURN_VAL_IF_FAIL(private_loop->wl_loop != NULL, -1);
225
226         return wl_event_loop_get_fd(private_loop->wl_loop);
227 }
228
229 INTERN tdm_error
230 tdm_event_loop_dispatch(tdm_private_display *private_display)
231 {
232         tdm_private_loop *private_loop = private_display->private_loop;
233
234         /* DON'T check TDM_MUTEX_IS_LOCKED here */
235
236         TDM_RETURN_VAL_IF_FAIL(private_loop->wl_loop != NULL, TDM_ERROR_OPERATION_FAILED);
237
238         if (tdm_debug_module & TDM_DEBUG_THREAD)
239                 TDM_INFO("dispatch");
240
241         if (tdm_thread_is_running() &&
242                 tdm_thread_in_display_thread(syscall(SYS_gettid))) {
243                 TDM_NEVER_GET_HERE();
244                 return TDM_ERROR_OPERATION_FAILED;
245         }
246
247         /* Don't set timeout to -1. It can make deadblock by two mutex locks.
248          * If need to set -1, use poll() and call tdm_event_loop_dispatch() after
249          * escaping polling.
250          */
251         if (wl_event_loop_dispatch(private_loop->wl_loop, 0) < 0)
252                 TDM_ERR("dispatch failed");
253
254         wl_display_flush_clients(private_loop->wl_display);
255
256         return TDM_ERROR_NONE;
257 }
258
259
260 INTERN void
261 tdm_event_loop_flush(tdm_private_display *private_display)
262 {
263         tdm_private_loop *private_loop = private_display->private_loop;
264
265         /* DON'T check TDM_MUTEX_IS_LOCKED here */
266
267         TDM_RETURN_IF_FAIL(private_loop->wl_display != NULL);
268
269         if (tdm_thread_is_running() &&
270                 tdm_thread_in_display_thread(syscall(SYS_gettid))) {
271                 TDM_NEVER_GET_HERE();
272                 return;
273         }
274
275         wl_display_flush_clients(private_loop->wl_display);
276 }
277
278 static int
279 _tdm_event_loop_fd_func(int fd, uint32_t wl_mask, void *data)
280 {
281         tdm_event_loop_source_fd *fd_source = (tdm_event_loop_source_fd*)data;
282         tdm_private_display *private_display;
283         tdm_event_loop_mask mask = 0;
284
285         /* DON'T check TDM_MUTEX_IS_LOCKED here */
286
287         TDM_RETURN_VAL_IF_FAIL(fd_source, 1);
288         TDM_RETURN_VAL_IF_FAIL(fd_source->func, 1);
289
290         private_display = fd_source->private_display;
291
292         if (wl_mask & WL_EVENT_READABLE)
293                 mask |= TDM_EVENT_LOOP_READABLE;
294         if (wl_mask & WL_EVENT_WRITABLE)
295                 mask |= TDM_EVENT_LOOP_WRITABLE;
296         if (wl_mask & WL_EVENT_HANGUP)
297                 mask |= TDM_EVENT_LOOP_HANGUP;
298         if (wl_mask & WL_EVENT_ERROR)
299                 mask |= TDM_EVENT_LOOP_ERROR;
300
301         _pthread_mutex_lock(&private_display->lock);
302         fd_source->func(fd, mask, fd_source->user_data);
303         _pthread_mutex_unlock(&private_display->lock);
304
305         return 1;
306 }
307
308 EXTERN tdm_event_loop_source *
309 tdm_event_loop_add_fd_handler(tdm_display *dpy, int fd, tdm_event_loop_mask mask,
310                                                           tdm_event_loop_fd_handler func, void *user_data,
311                                                           tdm_error *error)
312 {
313         tdm_private_display *private_display;
314         tdm_private_loop *private_loop;
315         tdm_event_loop_source_fd *fd_source;
316         uint32_t wl_mask = 0;
317         tdm_error ret;
318
319         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED, NULL);
320         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(dpy, TDM_ERROR_INVALID_PARAMETER, NULL);
321         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(fd >= 0, TDM_ERROR_INVALID_PARAMETER, NULL);
322         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(func, TDM_ERROR_INVALID_PARAMETER, NULL);
323
324         private_display = (tdm_private_display*)dpy;
325         private_loop = private_display->private_loop;
326         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(private_loop, TDM_ERROR_INVALID_PARAMETER, NULL);
327         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(private_loop->wl_loop, TDM_ERROR_INVALID_PARAMETER, NULL);
328
329         fd_source = calloc(1, sizeof(tdm_event_loop_source_fd));
330         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(fd_source, TDM_ERROR_OUT_OF_MEMORY, NULL);
331
332         if (mask & TDM_EVENT_LOOP_READABLE)
333                 wl_mask |= WL_EVENT_READABLE;
334         if (mask & TDM_EVENT_LOOP_WRITABLE)
335                 wl_mask |= WL_EVENT_WRITABLE;
336
337         fd_source->private_display = private_display;
338         fd_source->func = func;
339         fd_source->user_data = user_data;
340
341         fd_source->base.wl_source =
342                 wl_event_loop_add_fd(private_loop->wl_loop,
343                                                          fd, wl_mask, _tdm_event_loop_fd_func, fd_source);
344         if (!fd_source->base.wl_source) {
345                 if (error)
346                         *error = TDM_ERROR_OUT_OF_MEMORY;
347                 free(fd_source);
348                 return NULL;
349         }
350
351         if (error)
352                 *error = TDM_ERROR_NONE;
353
354         return (tdm_event_loop_source *)fd_source;
355 }
356
357 EXTERN tdm_error
358 tdm_event_loop_source_fd_update(tdm_event_loop_source *source, tdm_event_loop_mask mask)
359 {
360         tdm_event_loop_source_fd *fd_source = source;
361         uint32_t wl_mask = 0;
362
363         TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED);
364         TDM_RETURN_VAL_IF_FAIL(fd_source, TDM_ERROR_INVALID_PARAMETER);
365
366         if (mask & TDM_EVENT_LOOP_READABLE)
367                 wl_mask |= WL_EVENT_READABLE;
368         if (mask & TDM_EVENT_LOOP_WRITABLE)
369                 wl_mask |= WL_EVENT_WRITABLE;
370
371         if (wl_event_source_fd_update(fd_source->base.wl_source, wl_mask) < 0) {
372                 TDM_ERR("source update failed: %m");
373                 return TDM_ERROR_OPERATION_FAILED;
374         }
375
376         return TDM_ERROR_NONE;
377 }
378
379 static int
380 _tdm_event_loop_timer_func(void *data)
381 {
382         tdm_event_loop_source_timer *timer_source = (tdm_event_loop_source_timer*)data;
383         tdm_private_display *private_display;
384
385         /* DON'T check TDM_MUTEX_IS_LOCKED here */
386
387         TDM_RETURN_VAL_IF_FAIL(timer_source, 1);
388         TDM_RETURN_VAL_IF_FAIL(timer_source->func, 1);
389
390         private_display = timer_source->private_display;
391
392         /* TDM event_loop function is actually for TDM backend module. When we call the
393          * backend's functions, we have to lock the mutex. TDM backend shouldn't consider
394          * mutex things.
395          */
396         _pthread_mutex_lock(&private_display->lock);
397         timer_source->func(timer_source->user_data);
398         _pthread_mutex_unlock(&private_display->lock);
399
400         return 1;
401 }
402
403 EXTERN tdm_event_loop_source *
404 tdm_event_loop_add_timer_handler(tdm_display *dpy, tdm_event_loop_timer_handler func,
405                                                                  void *user_data, tdm_error *error)
406 {
407         tdm_private_display *private_display;
408         tdm_private_loop *private_loop;
409         tdm_event_loop_source_timer *timer_source;
410         tdm_error ret;
411
412         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED, NULL);
413         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(dpy, TDM_ERROR_INVALID_PARAMETER, NULL);
414         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(func, TDM_ERROR_INVALID_PARAMETER, NULL);
415
416         private_display = (tdm_private_display*)dpy;
417         private_loop = private_display->private_loop;
418         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(private_loop, TDM_ERROR_INVALID_PARAMETER, NULL);
419         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(private_loop->wl_loop, TDM_ERROR_INVALID_PARAMETER, NULL);
420
421         timer_source = calloc(1, sizeof(tdm_event_loop_source_timer));
422         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(timer_source, TDM_ERROR_OUT_OF_MEMORY, NULL);
423
424         timer_source->private_display = private_display;
425         timer_source->func = func;
426         timer_source->user_data = user_data;
427
428         timer_source->base.wl_source =
429                 wl_event_loop_add_timer(private_loop->wl_loop,
430                                                                 _tdm_event_loop_timer_func, timer_source);
431         if (!timer_source->base.wl_source) {
432                 if (error)
433                         *error = TDM_ERROR_OUT_OF_MEMORY;
434                 free(timer_source);
435                 return NULL;
436         }
437
438         if (error)
439                 *error = TDM_ERROR_NONE;
440
441         return (tdm_event_loop_source *)timer_source;
442 }
443
444 EXTERN tdm_error
445 tdm_event_loop_source_timer_update(tdm_event_loop_source *source, unsigned int ms_delay)
446 {
447         tdm_event_loop_source_timer *timer_source = source;
448
449         TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED);
450         TDM_RETURN_VAL_IF_FAIL(timer_source, TDM_ERROR_INVALID_PARAMETER);
451
452         if (wl_event_source_timer_update(timer_source->base.wl_source, ms_delay) < 0) {
453                 TDM_ERR("source update failed: %m");
454                 return TDM_ERROR_OPERATION_FAILED;
455         }
456
457         return TDM_ERROR_NONE;
458 }
459
460 EXTERN void
461 tdm_event_loop_source_remove(tdm_event_loop_source *source)
462 {
463         tdm_event_loop_source_base *base = (tdm_event_loop_source_base*)source;
464
465         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
466
467         if (!base)
468                 return;
469
470         wl_event_source_remove(base->wl_source);
471
472         free(source);
473 }
474
475 /* LCOV_EXCL_START */
476 static void
477 _trace_cb_client_destroy(struct wl_listener *listener, void *data)
478 {
479         struct wl_client *client = (struct wl_client *) data;
480         struct timespec tp;
481         unsigned int time;
482         pid_t pid = -1;
483         const char *proc_name;
484         char temp[512] = { 0, }, *p = temp;
485         int len = sizeof(temp), *l = &len;
486
487         wl_client_get_credentials(client, &pid, NULL, NULL);
488         proc_name = tdm_server_get_client_name(pid);
489
490         clock_gettime(CLOCK_MONOTONIC, &tp);
491         time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
492
493         TDM_SNPRINTF(p, l, "[%10.3f] Server           [PID:%d] client destroying", time / 1000.0, pid);
494         TDM_SNPRINTF(p, l, ", cmd: %s", proc_name ? proc_name : "Unknown");
495
496         TDM_INFO("%s", temp);
497
498         wl_list_remove(&listener->link);
499         free(listener);
500 }
501
502 static void
503 _trace_reg_client_destroy_listener(struct wl_client *client)
504 {
505         struct wl_listener *listener;
506
507         listener = wl_client_get_destroy_listener(client, _trace_cb_client_destroy);
508         if (listener)
509                 return;
510
511         listener = calloc(1, sizeof(struct wl_listener));
512         TDM_RETURN_IF_FAIL(listener != NULL);
513
514         listener->notify = _trace_cb_client_destroy;
515         wl_client_add_destroy_listener(client, listener);
516 }
517
518 static const char *
519 _trace_get_next_argument(const char *signature,
520                                                  struct argument_details *details)
521 {
522         details->nullable = 0;
523         for (; *signature; ++signature) {
524                 switch (*signature) {
525                 case 'i':
526                 case 'u':
527                 case 'f':
528                 case 's':
529                 case 'o':
530                 case 'n':
531                 case 'a':
532                 case 'h':
533                         details->type = *signature;
534                         return signature + 1;
535                 case '?':
536                         details->nullable = 1;
537                         break;
538                 default:
539                         return NULL;
540                 }
541         }
542         details->type = '\0';
543         return signature;
544 }
545
546 static struct wl_protocol_logger *_trace_protocol_logger;
547
548 static void
549 _trace_protocol_logger_cb(void *user_data,
550                                                   enum wl_protocol_logger_type direction,
551                                                   const struct wl_protocol_logger_message *message)
552 {
553         int i;
554         struct argument_details arg;
555         struct wl_client *client = wl_resource_get_client(message->resource);
556         const char *signature = message->message->signature;
557         struct timespec tp;
558         unsigned int time;
559         pid_t pid = -1;
560         const char *proc_name;
561         char temp[512] = { 0, }, *p = temp;
562         int len = sizeof(temp), *l = &len;
563         int send;
564
565         if (client) {
566                 _trace_reg_client_destroy_listener(client);
567                 wl_client_get_credentials(client, &pid, NULL, NULL);
568         }
569
570         proc_name = tdm_server_get_client_name(pid);
571
572         clock_gettime(CLOCK_MONOTONIC, &tp);
573         time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
574
575         send = (direction == WL_PROTOCOL_LOGGER_EVENT) ? 1 : 0;
576
577         TDM_SNPRINTF(p, l, "[%10.3f] %s%d%s%s@%u.%s(",
578                                  time / 1000.0,
579                                  send ? "Server -> Client [PID:" : "Server <- Client [PID:",
580                                  pid, "] ",
581                                  wl_resource_get_class(message->resource),
582                                  wl_resource_get_id(message->resource),
583                                  message->message->name);
584
585         for (i = 0; i < message->arguments_count; i++) {
586                 signature = _trace_get_next_argument(signature, &arg);
587                 TDM_RETURN_IF_FAIL(signature != NULL);
588
589                 if (i > 0)
590                         TDM_SNPRINTF(p, l, ", ");
591
592                 switch (arg.type) {
593                 case 'u':
594                         TDM_SNPRINTF(p, l, "%u", message->arguments[i].u);
595                         break;
596                 case 'i':
597                         TDM_SNPRINTF(p, l, "%d", message->arguments[i].i);
598                         break;
599                 case 'f':
600                         TDM_SNPRINTF(p, l, "%f",
601                                                  wl_fixed_to_double(message->arguments[i].f));
602                         break;
603                 case 's':
604                         TDM_SNPRINTF(p, l, "\"%s\"", message->arguments[i].s);
605                         break;
606                 case 'o':
607                         if (message->arguments[i].o)
608                                 TDM_SNPRINTF(p, l, "%s@%u",
609                                                          wl_resource_get_class((struct wl_resource *) message->arguments[i].o),
610                                                          wl_resource_get_id((struct wl_resource *) message->arguments[i].o));
611                         else
612                                 TDM_SNPRINTF(p, l, "nil");
613                         break;
614                 case 'n':
615                         TDM_SNPRINTF(p, l, "new id %s@",
616                                                  (message->message->types[i]) ? message->message->types[i]->name : "[unknown]");
617                         if (message->arguments[i].n != 0)
618                                 TDM_SNPRINTF(p, l, "%u", message->arguments[i].n);
619                         else
620                                 TDM_SNPRINTF(p, l, "nil");
621                         break;
622                 case 'a':
623                         TDM_SNPRINTF(p, l, "array");
624                         break;
625                 case 'h':
626                         TDM_SNPRINTF(p, l, "fd %d", message->arguments[i].h);
627                         break;
628                 default:
629                         return;
630                 }
631         }
632
633         TDM_SNPRINTF(p, l, "), cmd: %s", proc_name ? proc_name : "Unknown");
634
635         TDM_INFO("%s", temp);
636 }
637
638 INTERN tdm_error
639 tdm_event_loop_trace_enable(tdm_private_display * private_display,
640                                                         unsigned int enable)
641 {
642         tdm_private_loop *private_loop = private_display->private_loop;
643
644         TDM_RETURN_VAL_IF_FAIL(private_loop->wl_display != NULL, TDM_ERROR_NONE);
645
646         if (!enable) {
647                 if (_trace_protocol_logger) {
648                         wl_protocol_logger_destroy(_trace_protocol_logger);
649                         _trace_protocol_logger = NULL;
650                 }
651                 return TDM_ERROR_NONE;
652         }
653
654         if (_trace_protocol_logger)
655                 wl_protocol_logger_destroy(_trace_protocol_logger);
656
657         _trace_protocol_logger =
658                 wl_display_add_protocol_logger(private_loop->wl_display, _trace_protocol_logger_cb, NULL);
659
660         return TDM_ERROR_NONE;
661 }
662 /* LCOV_EXCL_STOP */