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 <boram1288.park@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 list_head link;
44 tdm_private_display *private_display;
45 struct wl_event_source *wl_source;
46 } tdm_event_loop_source_base;
48 typedef struct _tdm_event_loop_source_fd {
49 tdm_event_loop_source_base base;
50 tdm_event_loop_fd_handler func;
52 } tdm_event_loop_source_fd;
54 typedef struct _tdm_event_loop_source_timer {
55 tdm_event_loop_source_base base;
56 tdm_event_loop_timer_handler func;
58 } tdm_event_loop_source_timer;
60 static tdm_private_loop *keep_private_loop;
63 _tdm_event_loop_main_fd_handler(int fd, tdm_event_loop_mask mask, void *user_data)
65 tdm_private_module *private_module = (tdm_private_module*)user_data;
66 tdm_private_display *private_display;
67 tdm_func_display *func_display;
70 TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED);
71 TDM_RETURN_VAL_IF_FAIL(private_module != NULL, TDM_ERROR_OPERATION_FAILED);
73 if (tdm_debug_module & TDM_DEBUG_EVENT)
74 TDM_INFO("backend fd(%d) event happens", private_module->fd);
76 if (private_module->use_hal_tdm) {
77 tdm_private_module *current_module;
78 private_display = private_module->private_display;
79 current_module = private_display->current_module;
80 private_display->current_module = private_module;
81 ret = (tdm_error)hal_tdm_display_handle_events(private_module->htdm_dpy);
82 if (ret == TDM_ERROR_NONE)
83 private_display->current_module = NULL;
85 private_display->current_module = current_module;
87 func_display = &private_module->func_display;
88 if (!func_display->display_handle_events)
89 return TDM_ERROR_NONE;
91 private_display = private_module->private_display;
92 private_display->current_module = private_module;
93 ret = func_display->display_handle_events(private_module->bdata);
94 private_display->current_module = NULL;
101 tdm_event_loop_init(tdm_private_display *private_display)
103 tdm_private_loop *private_loop;
106 TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED);
108 if (private_display->private_loop)
109 return TDM_ERROR_NONE;
111 private_loop = calloc(1, sizeof * private_loop);
113 TDM_ERR("alloc failed");
114 return TDM_ERROR_OUT_OF_MEMORY;
117 private_loop->wl_display = wl_display_create();
118 if (!private_loop->wl_display) {
119 TDM_ERR("creating a wayland display failed");
121 return TDM_ERROR_OUT_OF_MEMORY;
123 private_loop->wl_loop = wl_display_get_event_loop(private_loop->wl_display);
125 ret = tdm_server_init(private_loop);
126 if (ret != TDM_ERROR_NONE) {
127 TDM_ERR("server init failed");
128 wl_display_destroy(private_loop->wl_display);
130 return TDM_ERROR_OPERATION_FAILED;
133 LIST_INITHEAD(&private_loop->source_list);
135 private_loop->dpy = private_display;
136 private_display->private_loop = private_loop;
138 ret = tdm_thread_init(private_loop);
139 if (ret != TDM_ERROR_NONE) {
140 TDM_ERR("thread init failed");
141 tdm_server_deinit(private_loop);
142 wl_display_destroy(private_loop->wl_display);
144 return TDM_ERROR_OPERATION_FAILED;
147 keep_private_loop = private_loop;
149 TDM_INFO("event loop fd(%d)", wl_event_loop_get_fd(private_loop->wl_loop));
151 return TDM_ERROR_NONE;
155 tdm_event_loop_deinit(tdm_private_display *private_display)
157 tdm_private_module *private_module = NULL;
158 tdm_event_loop_source_base *source = NULL, *ss = NULL;
160 TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
162 if (!private_display->private_loop)
165 if (tdm_thread_is_running())
166 TDM_ERR("thread is still running. tdm_event_loop_stop SHOULD be called");
168 tdm_server_deinit(private_display->private_loop);
170 LIST_FOR_EACH_ENTRY(private_module, &private_display->module_list, link) {
171 if (private_module->event_source)
172 tdm_event_loop_source_remove(private_module->event_source);
173 private_module->event_source = NULL;
174 private_module->fd = -1;
177 LIST_FOR_EACH_ENTRY_SAFE(source, ss, &private_display->private_loop->source_list, link) {
178 tdm_event_loop_source_remove(source);
181 #if WAYLAND_VERSION_MAJOR >= 1 && WAYLAND_VERSION_MINOR >= 15
182 wl_display_destroy_clients(private_display->private_loop->wl_display);
185 wl_display_destroy(private_display->private_loop->wl_display);
187 free(private_display->private_loop);
188 private_display->private_loop = NULL;
189 keep_private_loop = NULL;
191 TDM_INFO("event loop deinit done");
195 tdm_event_loop_stop(tdm_private_display *private_display)
197 TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
199 /* after tdm_thread_deinit, we don't worry about thread things because it's finalized */
200 tdm_thread_deinit(private_display->private_loop);
204 tdm_event_loop_create_backend_source(tdm_private_display *private_display)
206 tdm_private_loop *private_loop = private_display->private_loop;
207 tdm_private_module *private_module = NULL;
211 TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
212 TDM_RETURN_IF_FAIL(private_loop != NULL);
214 LIST_FOR_EACH_ENTRY(private_module, &private_display->module_list, link) {
215 if (private_module->use_hal_tdm) {
216 if (hal_tdm_display_get_fd(private_module->htdm_dpy, &fd) != HAL_TDM_ERROR_NONE) {
217 TDM_INFO("TDM backend module won't offer a display fd");
218 private_module->event_source = NULL;
219 private_module->fd = -1;
222 ret = TDM_ERROR_NONE;
224 tdm_func_display *func_display = &private_module->func_display;
226 if (!func_display->display_get_fd) {
227 TDM_INFO("TDM backend module won't offer a display fd");
228 private_module->event_source = NULL;
229 private_module->fd = -1;
233 ret = func_display->display_get_fd(private_module->bdata, &fd);
234 assert(func_display->display_handle_events);
236 assert(ret == TDM_ERROR_NONE && fd >= 0);
238 private_module->event_source =
239 tdm_event_loop_add_fd_handler(private_display, fd,
240 TDM_EVENT_LOOP_READABLE,
241 _tdm_event_loop_main_fd_handler,
242 private_module, &ret);
243 if (!private_module->event_source) {
244 TDM_ERR("no backend fd(%d) source", fd);
248 private_module->fd = fd;
250 TDM_INFO("backend fd(%d) source created", private_module->fd);
255 tdm_event_loop_get_fd(tdm_private_display *private_display)
257 tdm_private_loop *private_loop = private_display->private_loop;
259 /* DON'T check TDM_MUTEX_IS_LOCKED here */
261 TDM_RETURN_VAL_IF_FAIL(private_loop->wl_loop != NULL, -1);
263 return wl_event_loop_get_fd(private_loop->wl_loop);
267 tdm_event_loop_dispatch(tdm_private_display *private_display)
269 tdm_private_loop *private_loop = private_display->private_loop;
271 /* DON'T check TDM_MUTEX_IS_LOCKED here */
273 TDM_RETURN_VAL_IF_FAIL(private_loop->wl_loop != NULL, TDM_ERROR_OPERATION_FAILED);
275 if (tdm_debug_module & TDM_DEBUG_EVENT)
276 TDM_INFO("dispatch");
278 if (tdm_thread_is_running() &&
279 tdm_thread_in_display_thread(syscall(SYS_gettid))) {
280 TDM_NEVER_GET_HERE();
281 return TDM_ERROR_OPERATION_FAILED;
284 /* Don't set timeout to -1. It can make deadblock by two mutex locks.
285 * If need to set -1, use poll() and call tdm_event_loop_dispatch() after
288 if (wl_event_loop_dispatch(private_loop->wl_loop, 0) < 0)
289 TDM_ERR("dispatch failed");
291 wl_display_flush_clients(private_loop->wl_display);
293 return TDM_ERROR_NONE;
298 tdm_event_loop_flush(tdm_private_display *private_display)
300 tdm_private_loop *private_loop = private_display->private_loop;
302 /* DON'T check TDM_MUTEX_IS_LOCKED here */
304 TDM_RETURN_IF_FAIL(private_loop->wl_display != NULL);
306 if (tdm_thread_is_running() &&
307 tdm_thread_in_display_thread(syscall(SYS_gettid))) {
308 TDM_NEVER_GET_HERE();
312 wl_display_flush_clients(private_loop->wl_display);
316 _tdm_event_loop_fd_func(int fd, uint32_t wl_mask, void *data)
318 tdm_event_loop_source_fd *fd_source = (tdm_event_loop_source_fd*)data;
319 tdm_private_display *private_display;
320 tdm_event_loop_mask mask = 0;
322 /* DON'T check TDM_MUTEX_IS_LOCKED here */
324 TDM_RETURN_VAL_IF_FAIL(fd_source, 1);
325 TDM_RETURN_VAL_IF_FAIL(fd_source->func, 1);
327 private_display = fd_source->base.private_display;
329 if (wl_mask & WL_EVENT_READABLE)
330 mask |= TDM_EVENT_LOOP_READABLE;
331 if (wl_mask & WL_EVENT_WRITABLE)
332 mask |= TDM_EVENT_LOOP_WRITABLE;
333 if (wl_mask & WL_EVENT_HANGUP)
334 mask |= TDM_EVENT_LOOP_HANGUP;
335 if (wl_mask & WL_EVENT_ERROR)
336 mask |= TDM_EVENT_LOOP_ERROR;
338 _pthread_mutex_lock(&private_display->lock);
339 fd_source->func(fd, mask, fd_source->user_data);
340 _pthread_mutex_unlock(&private_display->lock);
345 EXTERN tdm_event_loop_source *
346 tdm_event_loop_add_fd_handler(tdm_display *dpy, int fd, tdm_event_loop_mask mask,
347 tdm_event_loop_fd_handler func, void *user_data,
350 tdm_private_display *private_display;
351 tdm_private_loop *private_loop;
352 tdm_event_loop_source_fd *fd_source;
353 uint32_t wl_mask = 0;
356 TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED, NULL);
357 TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(dpy, TDM_ERROR_INVALID_PARAMETER, NULL);
358 TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(fd >= 0, TDM_ERROR_INVALID_PARAMETER, NULL);
359 TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(func, TDM_ERROR_INVALID_PARAMETER, NULL);
361 private_display = (tdm_private_display*)dpy;
362 private_loop = private_display->private_loop;
363 TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(private_loop, TDM_ERROR_INVALID_PARAMETER, NULL);
364 TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(private_loop->wl_loop, TDM_ERROR_INVALID_PARAMETER, NULL);
366 fd_source = calloc(1, sizeof(tdm_event_loop_source_fd));
367 TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(fd_source, TDM_ERROR_OUT_OF_MEMORY, NULL);
369 if (mask & TDM_EVENT_LOOP_READABLE)
370 wl_mask |= WL_EVENT_READABLE;
371 if (mask & TDM_EVENT_LOOP_WRITABLE)
372 wl_mask |= WL_EVENT_WRITABLE;
374 fd_source->func = func;
375 fd_source->user_data = user_data;
377 fd_source->base.private_display = private_display;
378 fd_source->base.wl_source =
379 wl_event_loop_add_fd(private_loop->wl_loop,
380 fd, wl_mask, _tdm_event_loop_fd_func, fd_source);
381 if (!fd_source->base.wl_source) {
383 *error = TDM_ERROR_OUT_OF_MEMORY;
388 LIST_ADDTAIL(&fd_source->base.link, &private_loop->source_list);
391 *error = TDM_ERROR_NONE;
393 return (tdm_event_loop_source *)fd_source;
397 tdm_event_loop_source_fd_update(tdm_event_loop_source *source, tdm_event_loop_mask mask)
399 tdm_event_loop_source_fd *fd_source = source;
400 uint32_t wl_mask = 0;
402 TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED);
403 TDM_RETURN_VAL_IF_FAIL(fd_source, TDM_ERROR_INVALID_PARAMETER);
405 if (mask & TDM_EVENT_LOOP_READABLE)
406 wl_mask |= WL_EVENT_READABLE;
407 if (mask & TDM_EVENT_LOOP_WRITABLE)
408 wl_mask |= WL_EVENT_WRITABLE;
410 if (wl_event_source_fd_update(fd_source->base.wl_source, wl_mask) < 0) {
411 TDM_ERR("source update failed: %m");
412 return TDM_ERROR_OPERATION_FAILED;
415 return TDM_ERROR_NONE;
419 _tdm_event_loop_timer_func(void *data)
421 tdm_event_loop_source_timer *timer_source = (tdm_event_loop_source_timer*)data;
422 tdm_private_display *private_display;
424 /* DON'T check TDM_MUTEX_IS_LOCKED here */
426 TDM_RETURN_VAL_IF_FAIL(timer_source, 1);
427 TDM_RETURN_VAL_IF_FAIL(timer_source->func, 1);
429 private_display = timer_source->base.private_display;
431 /* TDM event_loop function is actually for TDM backend module. When we call the
432 * backend's functions, we have to lock the mutex. TDM backend shouldn't consider
435 _pthread_mutex_lock(&private_display->lock);
436 timer_source->func(timer_source->user_data);
437 _pthread_mutex_unlock(&private_display->lock);
442 EXTERN tdm_event_loop_source *
443 tdm_event_loop_add_timer_handler(tdm_display *dpy, tdm_event_loop_timer_handler func,
444 void *user_data, tdm_error *error)
446 tdm_private_display *private_display;
447 tdm_private_loop *private_loop;
448 tdm_event_loop_source_timer *timer_source;
451 TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED, NULL);
452 TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(dpy, TDM_ERROR_INVALID_PARAMETER, NULL);
453 TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(func, TDM_ERROR_INVALID_PARAMETER, NULL);
455 private_display = (tdm_private_display*)dpy;
456 private_loop = private_display->private_loop;
457 TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(private_loop, TDM_ERROR_INVALID_PARAMETER, NULL);
458 TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(private_loop->wl_loop, TDM_ERROR_INVALID_PARAMETER, NULL);
460 timer_source = calloc(1, sizeof(tdm_event_loop_source_timer));
461 TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(timer_source, TDM_ERROR_OUT_OF_MEMORY, NULL);
463 timer_source->func = func;
464 timer_source->user_data = user_data;
466 timer_source->base.private_display = private_display;
467 timer_source->base.wl_source =
468 wl_event_loop_add_timer(private_loop->wl_loop,
469 _tdm_event_loop_timer_func, timer_source);
470 if (!timer_source->base.wl_source) {
472 *error = TDM_ERROR_OUT_OF_MEMORY;
477 LIST_ADDTAIL(&timer_source->base.link, &private_loop->source_list);
480 *error = TDM_ERROR_NONE;
482 return (tdm_event_loop_source *)timer_source;
486 tdm_event_loop_source_timer_update(tdm_event_loop_source *source, unsigned int ms_delay)
488 tdm_event_loop_source_timer *timer_source = source;
490 TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED);
491 TDM_RETURN_VAL_IF_FAIL(timer_source, TDM_ERROR_INVALID_PARAMETER);
493 if (wl_event_source_timer_update(timer_source->base.wl_source, ms_delay) < 0) {
494 TDM_ERR("source update failed: %m");
495 return TDM_ERROR_OPERATION_FAILED;
498 return TDM_ERROR_NONE;
502 tdm_event_loop_source_remove(tdm_event_loop_source *source)
504 tdm_event_loop_source_base *base = (tdm_event_loop_source_base*)source;
506 TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
508 if (!base || !keep_private_loop)
511 LIST_DEL(&base->link);
513 wl_event_source_remove(base->wl_source);
518 /* LCOV_EXCL_START */
520 _trace_cb_client_destroy(struct wl_listener *listener, void *data)
522 struct wl_client *client = (struct wl_client *) data;
526 const char *proc_name;
527 char temp[512] = { 0, }, *p = temp;
528 int len = sizeof(temp), *l = &len;
530 wl_client_get_credentials(client, &pid, NULL, NULL);
531 proc_name = tdm_server_get_client_name(pid);
533 clock_gettime(CLOCK_MONOTONIC, &tp);
534 time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
536 TDM_SNPRINTF(p, l, "[%10.3f] Server [PID:%d] client destroying", time / 1000.0, pid);
537 TDM_SNPRINTF(p, l, ", cmd: %s", proc_name ? proc_name : "Unknown");
539 TDM_INFO("%s", temp);
541 wl_list_remove(&listener->link);
546 _trace_reg_client_destroy_listener(struct wl_client *client)
548 struct wl_listener *listener;
550 listener = wl_client_get_destroy_listener(client, _trace_cb_client_destroy);
554 listener = calloc(1, sizeof(struct wl_listener));
555 TDM_RETURN_IF_FAIL(listener != NULL);
557 listener->notify = _trace_cb_client_destroy;
558 wl_client_add_destroy_listener(client, listener);
562 _trace_get_next_argument(const char *signature,
563 struct argument_details *details)
565 details->nullable = 0;
566 for (; *signature; ++signature) {
567 switch (*signature) {
576 details->type = *signature;
577 return signature + 1;
579 details->nullable = 1;
585 details->type = '\0';
589 static struct wl_protocol_logger *_trace_protocol_logger;
592 _trace_protocol_logger_cb(void *user_data,
593 enum wl_protocol_logger_type direction,
594 const struct wl_protocol_logger_message *message)
597 struct argument_details arg;
598 struct wl_client *client = wl_resource_get_client(message->resource);
599 const char *signature = message->message->signature;
603 const char *proc_name;
604 char temp[512] = { 0, }, *p = temp;
605 int len = sizeof(temp), *l = &len;
609 _trace_reg_client_destroy_listener(client);
610 wl_client_get_credentials(client, &pid, NULL, NULL);
613 proc_name = tdm_server_get_client_name(pid);
615 clock_gettime(CLOCK_MONOTONIC, &tp);
616 time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
618 send = (direction == WL_PROTOCOL_LOGGER_EVENT) ? 1 : 0;
620 TDM_SNPRINTF(p, l, "[%10.3f] %s%d%s%s@%u.%s(",
622 send ? "Server -> Client [PID:" : "Server <- Client [PID:",
624 wl_resource_get_class(message->resource),
625 wl_resource_get_id(message->resource),
626 message->message->name);
628 for (i = 0; i < message->arguments_count; i++) {
629 signature = _trace_get_next_argument(signature, &arg);
630 TDM_RETURN_IF_FAIL(signature != NULL);
633 TDM_SNPRINTF(p, l, ", ");
637 TDM_SNPRINTF(p, l, "%u", message->arguments[i].u);
640 TDM_SNPRINTF(p, l, "%d", message->arguments[i].i);
643 TDM_SNPRINTF(p, l, "%f",
644 wl_fixed_to_double(message->arguments[i].f));
647 TDM_SNPRINTF(p, l, "\"%s\"", message->arguments[i].s);
650 if (message->arguments[i].o)
651 TDM_SNPRINTF(p, l, "%s@%u",
652 wl_resource_get_class((struct wl_resource *) message->arguments[i].o),
653 wl_resource_get_id((struct wl_resource *) message->arguments[i].o));
655 TDM_SNPRINTF(p, l, "nil");
658 TDM_SNPRINTF(p, l, "new id %s@",
659 (message->message->types[i]) ? message->message->types[i]->name : "[unknown]");
660 if (message->arguments[i].n != 0)
661 TDM_SNPRINTF(p, l, "%u", message->arguments[i].n);
663 TDM_SNPRINTF(p, l, "nil");
666 TDM_SNPRINTF(p, l, "array");
669 TDM_SNPRINTF(p, l, "fd %d", message->arguments[i].h);
676 TDM_SNPRINTF(p, l, "), cmd: %s", proc_name ? proc_name : "Unknown");
678 TDM_INFO("%s", temp);
682 tdm_event_loop_trace_enable(tdm_private_display * private_display,
685 tdm_private_loop *private_loop = private_display->private_loop;
687 TDM_RETURN_VAL_IF_FAIL(private_loop->wl_display != NULL, TDM_ERROR_NONE);
690 if (_trace_protocol_logger) {
691 wl_protocol_logger_destroy(_trace_protocol_logger);
692 _trace_protocol_logger = NULL;
694 return TDM_ERROR_NONE;
697 if (_trace_protocol_logger)
698 wl_protocol_logger_destroy(_trace_protocol_logger);
700 _trace_protocol_logger =
701 wl_display_add_protocol_logger(private_loop->wl_display, _trace_protocol_logger_cb, NULL);
703 return TDM_ERROR_NONE;