1 /**************************************************************************
5 * Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
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>
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:
22 * The above copyright notice and this permission notice (including the
23 * next paragraph) shall be included in all copies or substantial portions
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.
34 **************************************************************************/
40 #include "tdm_private.h"
42 typedef struct _tdm_event_loop_source_base {
43 struct wl_event_source *wl_source;
44 } tdm_event_loop_source_base;
46 typedef struct _tdm_event_loop_source_fd {
47 tdm_event_loop_source_base base;
48 tdm_private_display *private_display;
49 tdm_event_loop_fd_handler func;
51 } tdm_event_loop_source_fd;
53 typedef struct _tdm_event_loop_source_timer {
54 tdm_event_loop_source_base base;
55 tdm_private_display *private_display;
56 tdm_event_loop_timer_handler func;
58 } tdm_event_loop_source_timer;
61 _tdm_event_loop_main_fd_handler(int fd, tdm_event_loop_mask mask, void *user_data)
63 tdm_private_module *private_module = (tdm_private_module*)user_data;
64 tdm_func_display *func_display;
67 TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED);
68 TDM_RETURN_VAL_IF_FAIL(private_module != NULL, TDM_ERROR_OPERATION_FAILED);
70 if (tdm_debug_module & TDM_DEBUG_EVENT)
71 TDM_INFO("backend fd(%d) event happens", private_module->fd);
73 func_display = &private_module->func_display;
74 if (!func_display->display_handle_events)
75 return TDM_ERROR_NONE;
77 ret = func_display->display_handle_events(private_module->bdata);
83 tdm_event_loop_init(tdm_private_display *private_display)
85 tdm_private_loop *private_loop;
88 TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED);
90 if (private_display->private_loop)
91 return TDM_ERROR_NONE;
93 private_loop = calloc(1, sizeof * private_loop);
95 TDM_ERR("alloc failed");
96 return TDM_ERROR_OUT_OF_MEMORY;
99 private_loop->wl_display = wl_display_create();
100 if (!private_loop->wl_display) {
101 TDM_ERR("creating a wayland display failed");
103 return TDM_ERROR_OUT_OF_MEMORY;
105 private_loop->wl_loop = wl_display_get_event_loop(private_loop->wl_display);
107 ret = tdm_server_init(private_loop);
108 if (ret != TDM_ERROR_NONE) {
109 TDM_ERR("server init failed");
110 wl_display_destroy(private_loop->wl_display);
112 return TDM_ERROR_OPERATION_FAILED;
115 private_loop->dpy = private_display;
116 private_display->private_loop = private_loop;
118 ret = tdm_thread_init(private_loop);
119 if (ret != TDM_ERROR_NONE) {
120 TDM_ERR("thread init failed");
121 tdm_server_deinit(private_loop);
122 wl_display_destroy(private_loop->wl_display);
124 return TDM_ERROR_OPERATION_FAILED;
127 TDM_INFO("event loop fd(%d)", wl_event_loop_get_fd(private_loop->wl_loop));
129 return TDM_ERROR_NONE;
133 tdm_event_loop_deinit(tdm_private_display *private_display)
135 tdm_private_module *private_module = NULL;
137 TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
139 if (!private_display->private_loop)
142 if (tdm_thread_is_running())
143 TDM_ERR("thread is still running. tdm_event_loop_stop SHOULD be called");
145 tdm_server_deinit(private_display->private_loop);
147 LIST_FOR_EACH_ENTRY(private_module, &private_display->module_list, link) {
148 if (private_module->event_source)
149 tdm_event_loop_source_remove(private_module->event_source);
150 private_module->event_source = NULL;
151 private_module->fd = -1;
154 if (private_display->private_loop->wl_display)
155 wl_display_destroy(private_display->private_loop->wl_display);
157 free(private_display->private_loop);
158 private_display->private_loop = NULL;
162 tdm_event_loop_stop(tdm_private_display *private_display)
164 TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
166 /* after tdm_thread_deinit, we don't worry about thread things because it's finalized */
167 tdm_thread_deinit(private_display->private_loop);
171 tdm_event_loop_create_backend_source(tdm_private_display *private_display)
173 tdm_private_loop *private_loop = private_display->private_loop;
174 tdm_private_module *private_module = NULL;
178 TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
179 TDM_RETURN_IF_FAIL(private_loop != NULL);
181 LIST_FOR_EACH_ENTRY(private_module, &private_display->module_list, link) {
182 tdm_func_display *func_display = &private_module->func_display;
184 if (!func_display->display_get_fd) {
185 TDM_INFO("TDM backend module won't offer a display fd");
186 private_module->event_source = NULL;
187 private_module->fd = -1;
191 ret = func_display->display_get_fd(private_module->bdata, &fd);
193 assert(ret == TDM_ERROR_NONE && fd >= 0);
194 assert(func_display->display_handle_events);
196 private_module->event_source =
197 tdm_event_loop_add_fd_handler(private_display, fd,
198 TDM_EVENT_LOOP_READABLE,
199 _tdm_event_loop_main_fd_handler,
200 private_module, &ret);
201 if (!private_module->event_source) {
202 TDM_ERR("no backend fd(%d) source", fd);
206 private_module->fd = fd;
208 TDM_INFO("backend fd(%d) source created", private_module->fd);
213 tdm_event_loop_get_fd(tdm_private_display *private_display)
215 tdm_private_loop *private_loop = private_display->private_loop;
217 /* DON'T check TDM_MUTEX_IS_LOCKED here */
219 TDM_RETURN_VAL_IF_FAIL(private_loop->wl_loop != NULL, -1);
221 return wl_event_loop_get_fd(private_loop->wl_loop);
225 tdm_event_loop_dispatch(tdm_private_display *private_display)
227 tdm_private_loop *private_loop = private_display->private_loop;
229 /* DON'T check TDM_MUTEX_IS_LOCKED here */
231 TDM_RETURN_VAL_IF_FAIL(private_loop->wl_loop != NULL, TDM_ERROR_OPERATION_FAILED);
233 if (tdm_debug_module & TDM_DEBUG_EVENT)
234 TDM_INFO("dispatch");
236 if (tdm_thread_is_running() &&
237 tdm_thread_in_display_thread(syscall(SYS_gettid))) {
238 TDM_NEVER_GET_HERE();
239 return TDM_ERROR_OPERATION_FAILED;
242 /* Don't set timeout to -1. It can make deadblock by two mutex locks.
243 * If need to set -1, use poll() and call tdm_event_loop_dispatch() after
246 if (wl_event_loop_dispatch(private_loop->wl_loop, 0) < 0)
247 TDM_ERR("dispatch failed");
249 wl_display_flush_clients(private_loop->wl_display);
251 return TDM_ERROR_NONE;
256 tdm_event_loop_flush(tdm_private_display *private_display)
258 tdm_private_loop *private_loop = private_display->private_loop;
260 /* DON'T check TDM_MUTEX_IS_LOCKED here */
262 TDM_RETURN_IF_FAIL(private_loop->wl_display != NULL);
264 if (tdm_thread_is_running() &&
265 tdm_thread_in_display_thread(syscall(SYS_gettid))) {
266 TDM_NEVER_GET_HERE();
270 wl_display_flush_clients(private_loop->wl_display);
274 _tdm_event_loop_fd_func(int fd, uint32_t wl_mask, void *data)
276 tdm_event_loop_source_fd *fd_source = (tdm_event_loop_source_fd*)data;
277 tdm_private_display *private_display;
278 tdm_event_loop_mask mask = 0;
280 /* DON'T check TDM_MUTEX_IS_LOCKED here */
282 TDM_RETURN_VAL_IF_FAIL(fd_source, 1);
283 TDM_RETURN_VAL_IF_FAIL(fd_source->func, 1);
285 private_display = fd_source->private_display;
287 if (wl_mask & WL_EVENT_READABLE)
288 mask |= TDM_EVENT_LOOP_READABLE;
289 if (wl_mask & WL_EVENT_WRITABLE)
290 mask |= TDM_EVENT_LOOP_WRITABLE;
291 if (wl_mask & WL_EVENT_HANGUP)
292 mask |= TDM_EVENT_LOOP_HANGUP;
293 if (wl_mask & WL_EVENT_ERROR)
294 mask |= TDM_EVENT_LOOP_ERROR;
296 _pthread_mutex_lock(&private_display->lock);
297 fd_source->func(fd, mask, fd_source->user_data);
298 _pthread_mutex_unlock(&private_display->lock);
303 EXTERN tdm_event_loop_source *
304 tdm_event_loop_add_fd_handler(tdm_display *dpy, int fd, tdm_event_loop_mask mask,
305 tdm_event_loop_fd_handler func, void *user_data,
308 tdm_private_display *private_display;
309 tdm_private_loop *private_loop;
310 tdm_event_loop_source_fd *fd_source;
311 uint32_t wl_mask = 0;
314 TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED, NULL);
315 TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(dpy, TDM_ERROR_INVALID_PARAMETER, NULL);
316 TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(fd >= 0, TDM_ERROR_INVALID_PARAMETER, NULL);
317 TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(func, TDM_ERROR_INVALID_PARAMETER, NULL);
319 private_display = (tdm_private_display*)dpy;
320 private_loop = private_display->private_loop;
321 TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(private_loop, TDM_ERROR_INVALID_PARAMETER, NULL);
322 TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(private_loop->wl_loop, TDM_ERROR_INVALID_PARAMETER, NULL);
324 fd_source = calloc(1, sizeof(tdm_event_loop_source_fd));
325 TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(fd_source, TDM_ERROR_OUT_OF_MEMORY, NULL);
327 if (mask & TDM_EVENT_LOOP_READABLE)
328 wl_mask |= WL_EVENT_READABLE;
329 if (mask & TDM_EVENT_LOOP_WRITABLE)
330 wl_mask |= WL_EVENT_WRITABLE;
332 fd_source->private_display = private_display;
333 fd_source->func = func;
334 fd_source->user_data = user_data;
336 fd_source->base.wl_source =
337 wl_event_loop_add_fd(private_loop->wl_loop,
338 fd, wl_mask, _tdm_event_loop_fd_func, fd_source);
339 if (!fd_source->base.wl_source) {
341 *error = TDM_ERROR_OUT_OF_MEMORY;
347 *error = TDM_ERROR_NONE;
349 return (tdm_event_loop_source *)fd_source;
353 tdm_event_loop_source_fd_update(tdm_event_loop_source *source, tdm_event_loop_mask mask)
355 tdm_event_loop_source_fd *fd_source = source;
356 uint32_t wl_mask = 0;
358 TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED);
359 TDM_RETURN_VAL_IF_FAIL(fd_source, TDM_ERROR_INVALID_PARAMETER);
361 if (mask & TDM_EVENT_LOOP_READABLE)
362 wl_mask |= WL_EVENT_READABLE;
363 if (mask & TDM_EVENT_LOOP_WRITABLE)
364 wl_mask |= WL_EVENT_WRITABLE;
366 if (wl_event_source_fd_update(fd_source->base.wl_source, wl_mask) < 0) {
367 TDM_ERR("source update failed: %m");
368 return TDM_ERROR_OPERATION_FAILED;
371 return TDM_ERROR_NONE;
375 _tdm_event_loop_timer_func(void *data)
377 tdm_event_loop_source_timer *timer_source = (tdm_event_loop_source_timer*)data;
378 tdm_private_display *private_display;
380 /* DON'T check TDM_MUTEX_IS_LOCKED here */
382 TDM_RETURN_VAL_IF_FAIL(timer_source, 1);
383 TDM_RETURN_VAL_IF_FAIL(timer_source->func, 1);
385 private_display = timer_source->private_display;
387 /* TDM event_loop function is actually for TDM backend module. When we call the
388 * backend's functions, we have to lock the mutex. TDM backend shouldn't consider
391 _pthread_mutex_lock(&private_display->lock);
392 timer_source->func(timer_source->user_data);
393 _pthread_mutex_unlock(&private_display->lock);
398 EXTERN tdm_event_loop_source *
399 tdm_event_loop_add_timer_handler(tdm_display *dpy, tdm_event_loop_timer_handler func,
400 void *user_data, tdm_error *error)
402 tdm_private_display *private_display;
403 tdm_private_loop *private_loop;
404 tdm_event_loop_source_timer *timer_source;
407 TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED, NULL);
408 TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(dpy, TDM_ERROR_INVALID_PARAMETER, NULL);
409 TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(func, TDM_ERROR_INVALID_PARAMETER, NULL);
411 private_display = (tdm_private_display*)dpy;
412 private_loop = private_display->private_loop;
413 TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(private_loop, TDM_ERROR_INVALID_PARAMETER, NULL);
414 TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(private_loop->wl_loop, TDM_ERROR_INVALID_PARAMETER, NULL);
416 timer_source = calloc(1, sizeof(tdm_event_loop_source_timer));
417 TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(timer_source, TDM_ERROR_OUT_OF_MEMORY, NULL);
419 timer_source->private_display = private_display;
420 timer_source->func = func;
421 timer_source->user_data = user_data;
423 timer_source->base.wl_source =
424 wl_event_loop_add_timer(private_loop->wl_loop,
425 _tdm_event_loop_timer_func, timer_source);
426 if (!timer_source->base.wl_source) {
428 *error = TDM_ERROR_OUT_OF_MEMORY;
434 *error = TDM_ERROR_NONE;
436 return (tdm_event_loop_source *)timer_source;
440 tdm_event_loop_source_timer_update(tdm_event_loop_source *source, unsigned int ms_delay)
442 tdm_event_loop_source_timer *timer_source = source;
444 TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED);
445 TDM_RETURN_VAL_IF_FAIL(timer_source, TDM_ERROR_INVALID_PARAMETER);
447 if (wl_event_source_timer_update(timer_source->base.wl_source, ms_delay) < 0) {
448 TDM_ERR("source update failed: %m");
449 return TDM_ERROR_OPERATION_FAILED;
452 return TDM_ERROR_NONE;
456 tdm_event_loop_source_remove(tdm_event_loop_source *source)
458 tdm_event_loop_source_base *base = (tdm_event_loop_source_base*)source;
460 TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
465 wl_event_source_remove(base->wl_source);
470 /* LCOV_EXCL_START */
472 _trace_cb_client_destroy(struct wl_listener *listener, void *data)
474 struct wl_client *client = (struct wl_client *) data;
478 const char *proc_name;
479 char temp[512] = { 0, }, *p = temp;
480 int len = sizeof(temp), *l = &len;
482 wl_client_get_credentials(client, &pid, NULL, NULL);
483 proc_name = tdm_server_get_client_name(pid);
485 clock_gettime(CLOCK_MONOTONIC, &tp);
486 time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
488 TDM_SNPRINTF(p, l, "[%10.3f] Server [PID:%d] client destroying", time / 1000.0, pid);
489 TDM_SNPRINTF(p, l, ", cmd: %s", proc_name ? proc_name : "Unknown");
491 TDM_INFO("%s", temp);
493 wl_list_remove(&listener->link);
498 _trace_reg_client_destroy_listener(struct wl_client *client)
500 struct wl_listener *listener;
502 listener = wl_client_get_destroy_listener(client, _trace_cb_client_destroy);
506 listener = calloc(1, sizeof(struct wl_listener));
507 TDM_RETURN_IF_FAIL(listener != NULL);
509 listener->notify = _trace_cb_client_destroy;
510 wl_client_add_destroy_listener(client, listener);
514 _trace_get_next_argument(const char *signature,
515 struct argument_details *details)
517 details->nullable = 0;
518 for (; *signature; ++signature) {
519 switch (*signature) {
528 details->type = *signature;
529 return signature + 1;
531 details->nullable = 1;
537 details->type = '\0';
541 static struct wl_protocol_logger *_trace_protocol_logger;
544 _trace_protocol_logger_cb(void *user_data,
545 enum wl_protocol_logger_type direction,
546 const struct wl_protocol_logger_message *message)
549 struct argument_details arg;
550 struct wl_client *client = wl_resource_get_client(message->resource);
551 const char *signature = message->message->signature;
555 const char *proc_name;
556 char temp[512] = { 0, }, *p = temp;
557 int len = sizeof(temp), *l = &len;
561 _trace_reg_client_destroy_listener(client);
562 wl_client_get_credentials(client, &pid, NULL, NULL);
565 proc_name = tdm_server_get_client_name(pid);
567 clock_gettime(CLOCK_MONOTONIC, &tp);
568 time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
570 send = (direction == WL_PROTOCOL_LOGGER_EVENT) ? 1 : 0;
572 TDM_SNPRINTF(p, l, "[%10.3f] %s%d%s%s@%u.%s(",
574 send ? "Server -> Client [PID:" : "Server <- Client [PID:",
576 wl_resource_get_class(message->resource),
577 wl_resource_get_id(message->resource),
578 message->message->name);
580 for (i = 0; i < message->arguments_count; i++) {
581 signature = _trace_get_next_argument(signature, &arg);
582 TDM_RETURN_IF_FAIL(signature != NULL);
585 TDM_SNPRINTF(p, l, ", ");
589 TDM_SNPRINTF(p, l, "%u", message->arguments[i].u);
592 TDM_SNPRINTF(p, l, "%d", message->arguments[i].i);
595 TDM_SNPRINTF(p, l, "%f",
596 wl_fixed_to_double(message->arguments[i].f));
599 TDM_SNPRINTF(p, l, "\"%s\"", message->arguments[i].s);
602 if (message->arguments[i].o)
603 TDM_SNPRINTF(p, l, "%s@%u",
604 wl_resource_get_class((struct wl_resource *) message->arguments[i].o),
605 wl_resource_get_id((struct wl_resource *) message->arguments[i].o));
607 TDM_SNPRINTF(p, l, "nil");
610 TDM_SNPRINTF(p, l, "new id %s@",
611 (message->message->types[i]) ? message->message->types[i]->name : "[unknown]");
612 if (message->arguments[i].n != 0)
613 TDM_SNPRINTF(p, l, "%u", message->arguments[i].n);
615 TDM_SNPRINTF(p, l, "nil");
618 TDM_SNPRINTF(p, l, "array");
621 TDM_SNPRINTF(p, l, "fd %d", message->arguments[i].h);
628 TDM_SNPRINTF(p, l, "), cmd: %s", proc_name ? proc_name : "Unknown");
630 TDM_INFO("%s", temp);
634 tdm_event_loop_trace_enable(tdm_private_display * private_display,
637 tdm_private_loop *private_loop = private_display->private_loop;
639 TDM_RETURN_VAL_IF_FAIL(private_loop->wl_display != NULL, TDM_ERROR_NONE);
642 if (_trace_protocol_logger) {
643 wl_protocol_logger_destroy(_trace_protocol_logger);
644 _trace_protocol_logger = NULL;
646 return TDM_ERROR_NONE;
649 if (_trace_protocol_logger)
650 wl_protocol_logger_destroy(_trace_protocol_logger);
652 _trace_protocol_logger =
653 wl_display_add_protocol_logger(private_loop->wl_display, _trace_protocol_logger_cb, NULL);
655 return TDM_ERROR_NONE;