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 **************************************************************************/
41 #include "tdm_private.h"
44 #include <wayland-server-core.h>
46 typedef struct _tdm_event_loop_source_base {
47 struct wl_event_source *wl_source;
48 } tdm_event_loop_source_base;
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;
55 } tdm_event_loop_source_fd;
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;
62 } tdm_event_loop_source_timer;
65 _tdm_event_loop_main_fd_handler(int fd, tdm_event_loop_mask mask, void *user_data)
67 tdm_private_display *private_display = (tdm_private_display*)user_data;
68 tdm_private_loop *private_loop;
69 tdm_func_display *func_display;
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);
76 private_loop = private_display->private_loop;
78 if (tdm_debug_module & TDM_DEBUG_THREAD)
79 TDM_INFO("backend fd(%d) event happens", private_loop->backend_fd);
81 func_display = &private_display->func_display;
82 if (!func_display->display_handle_events)
83 return TDM_ERROR_NONE;
85 ret = func_display->display_handle_events(private_display->bdata);
91 tdm_event_loop_init(tdm_private_display *private_display)
93 tdm_private_loop *private_loop;
96 TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED);
98 if (private_display->private_loop)
99 return TDM_ERROR_NONE;
101 private_loop = calloc(1, sizeof * private_loop);
103 TDM_ERR("alloc failed");
104 return TDM_ERROR_OUT_OF_MEMORY;
107 private_loop->backend_fd = -1;
109 private_loop->wl_display = wl_display_create();
110 if (!private_loop->wl_display) {
111 TDM_ERR("creating a wayland display failed");
113 return TDM_ERROR_OUT_OF_MEMORY;
115 private_loop->wl_loop = wl_display_get_event_loop(private_loop->wl_display);
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);
122 return TDM_ERROR_OPERATION_FAILED;
125 private_loop->dpy = private_display;
126 private_display->private_loop = private_loop;
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);
134 return TDM_ERROR_OPERATION_FAILED;
137 TDM_INFO("event loop fd(%d)", wl_event_loop_get_fd(private_loop->wl_loop));
139 return TDM_ERROR_NONE;
143 tdm_event_loop_deinit(tdm_private_display *private_display)
145 TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
147 if (!private_display->private_loop)
150 if (tdm_thread_is_running())
151 TDM_ERR("thread is still running. tdm_event_loop_stop SHOULD be called");
153 tdm_server_deinit(private_display->private_loop);
155 if (private_display->private_loop->backend_source)
156 tdm_event_loop_source_remove(private_display->private_loop->backend_source);
158 if (private_display->private_loop->wl_display)
159 wl_display_destroy(private_display->private_loop->wl_display);
161 free(private_display->private_loop);
162 private_display->private_loop = NULL;
166 tdm_event_loop_stop(tdm_private_display *private_display)
168 TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
170 /* after tdm_thread_deinit, we don't worry about thread things because it's finalized */
171 tdm_thread_deinit(private_display->private_loop);
175 tdm_event_loop_create_backend_source(tdm_private_display *private_display)
177 tdm_private_loop *private_loop = private_display->private_loop;
178 tdm_func_display *func_display;
182 TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
183 TDM_RETURN_IF_FAIL(private_loop != NULL);
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");
191 ret = func_display->display_get_fd(private_display->bdata, &fd);
193 TDM_ERR("TDM backend module returns fd(%d)", fd);
197 if (!func_display->display_handle_events) {
198 TDM_ERR("no display_handle_events function");
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);
212 private_loop->backend_fd = fd;
214 TDM_INFO("backend fd(%d) source created", private_loop->backend_fd);
218 tdm_event_loop_get_fd(tdm_private_display *private_display)
220 tdm_private_loop *private_loop = private_display->private_loop;
222 /* DON'T check TDM_MUTEX_IS_LOCKED here */
224 TDM_RETURN_VAL_IF_FAIL(private_loop->wl_loop != NULL, -1);
226 return wl_event_loop_get_fd(private_loop->wl_loop);
230 tdm_event_loop_dispatch(tdm_private_display *private_display)
232 tdm_private_loop *private_loop = private_display->private_loop;
234 /* DON'T check TDM_MUTEX_IS_LOCKED here */
236 TDM_RETURN_VAL_IF_FAIL(private_loop->wl_loop != NULL, TDM_ERROR_OPERATION_FAILED);
238 if (tdm_debug_module & TDM_DEBUG_THREAD)
239 TDM_INFO("dispatch");
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;
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
251 if (wl_event_loop_dispatch(private_loop->wl_loop, 0) < 0)
252 TDM_ERR("dispatch failed");
254 wl_display_flush_clients(private_loop->wl_display);
256 return TDM_ERROR_NONE;
261 tdm_event_loop_flush(tdm_private_display *private_display)
263 tdm_private_loop *private_loop = private_display->private_loop;
265 /* DON'T check TDM_MUTEX_IS_LOCKED here */
267 TDM_RETURN_IF_FAIL(private_loop->wl_display != NULL);
269 if (tdm_thread_is_running() &&
270 tdm_thread_in_display_thread(syscall(SYS_gettid))) {
271 TDM_NEVER_GET_HERE();
275 wl_display_flush_clients(private_loop->wl_display);
279 _tdm_event_loop_fd_func(int fd, uint32_t wl_mask, void *data)
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;
285 /* DON'T check TDM_MUTEX_IS_LOCKED here */
287 TDM_RETURN_VAL_IF_FAIL(fd_source, 1);
288 TDM_RETURN_VAL_IF_FAIL(fd_source->func, 1);
290 private_display = fd_source->private_display;
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;
301 _pthread_mutex_lock(&private_display->lock);
302 fd_source->func(fd, mask, fd_source->user_data);
303 _pthread_mutex_unlock(&private_display->lock);
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,
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;
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);
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);
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);
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;
337 fd_source->private_display = private_display;
338 fd_source->func = func;
339 fd_source->user_data = user_data;
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) {
346 *error = TDM_ERROR_OUT_OF_MEMORY;
352 *error = TDM_ERROR_NONE;
354 return (tdm_event_loop_source *)fd_source;
358 tdm_event_loop_source_fd_update(tdm_event_loop_source *source, tdm_event_loop_mask mask)
360 tdm_event_loop_source_fd *fd_source = source;
361 uint32_t wl_mask = 0;
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);
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;
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;
376 return TDM_ERROR_NONE;
380 _tdm_event_loop_timer_func(void *data)
382 tdm_event_loop_source_timer *timer_source = (tdm_event_loop_source_timer*)data;
383 tdm_private_display *private_display;
385 /* DON'T check TDM_MUTEX_IS_LOCKED here */
387 TDM_RETURN_VAL_IF_FAIL(timer_source, 1);
388 TDM_RETURN_VAL_IF_FAIL(timer_source->func, 1);
390 private_display = timer_source->private_display;
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
396 _pthread_mutex_lock(&private_display->lock);
397 timer_source->func(timer_source->user_data);
398 _pthread_mutex_unlock(&private_display->lock);
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)
407 tdm_private_display *private_display;
408 tdm_private_loop *private_loop;
409 tdm_event_loop_source_timer *timer_source;
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);
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);
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);
424 timer_source->private_display = private_display;
425 timer_source->func = func;
426 timer_source->user_data = user_data;
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) {
433 *error = TDM_ERROR_OUT_OF_MEMORY;
439 *error = TDM_ERROR_NONE;
441 return (tdm_event_loop_source *)timer_source;
445 tdm_event_loop_source_timer_update(tdm_event_loop_source *source, unsigned int ms_delay)
447 tdm_event_loop_source_timer *timer_source = source;
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);
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;
457 return TDM_ERROR_NONE;
461 tdm_event_loop_source_remove(tdm_event_loop_source *source)
463 tdm_event_loop_source_base *base = (tdm_event_loop_source_base*)source;
465 TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
470 wl_event_source_remove(base->wl_source);
476 _trace_cb_client_destroy(struct wl_listener *listener, void *data)
478 struct wl_client *client = (struct wl_client *) data;
482 const char *proc_name;
483 char temp[512] = { 0, }, *p = temp;
484 int len = sizeof(temp), *l = &len;
486 wl_client_get_credentials(client, &pid, NULL, NULL);
487 proc_name = tdm_server_get_client_name(pid);
489 clock_gettime(CLOCK_MONOTONIC, &tp);
490 time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
492 TDM_SNPRINTF(p, l, "[%10.3f] Server [PID:%d] client destroying", time / 1000.0, pid);
493 TDM_SNPRINTF(p, l, ", cmd: %s", proc_name ? proc_name : "Unknown");
495 TDM_INFO("%s", temp);
497 wl_list_remove(&listener->link);
502 _trace_reg_client_destroy_listener(struct wl_client *client)
504 struct wl_listener *listener;
506 listener = wl_client_get_destroy_listener(client, _trace_cb_client_destroy);
510 listener = calloc(1, sizeof(struct wl_listener));
511 TDM_RETURN_IF_FAIL(listener != NULL);
513 listener->notify = _trace_cb_client_destroy;
514 wl_client_add_destroy_listener(client, listener);
518 _trace_get_next_argument(const char *signature,
519 struct argument_details *details)
521 details->nullable = 0;
522 for (; *signature; ++signature) {
523 switch (*signature) {
532 details->type = *signature;
533 return signature + 1;
535 details->nullable = 1;
541 details->type = '\0';
545 static struct wl_protocol_logger *_trace_protocol_logger;
548 _trace_protocol_logger_cb(void *user_data,
549 enum wl_protocol_logger_type direction,
550 const struct wl_protocol_logger_message *message)
553 struct argument_details arg;
554 struct wl_client *client = wl_resource_get_client(message->resource);
555 const char *signature = message->message->signature;
559 const char *proc_name;
560 char temp[512] = { 0, }, *p = temp;
561 int len = sizeof(temp), *l = &len;
565 _trace_reg_client_destroy_listener(client);
566 wl_client_get_credentials(client, &pid, NULL, NULL);
569 proc_name = tdm_server_get_client_name(pid);
571 clock_gettime(CLOCK_MONOTONIC, &tp);
572 time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
574 send = (direction == WL_PROTOCOL_LOGGER_EVENT) ? 1 : 0;
576 TDM_SNPRINTF(p, l, "[%10.3f] %s%d%s%s@%u.%s(",
578 send ? "Server -> Client [PID:" : "Server <- Client [PID:",
580 wl_resource_get_class(message->resource),
581 wl_resource_get_id(message->resource),
582 message->message->name);
584 for (i = 0; i < message->arguments_count; i++) {
585 signature = _trace_get_next_argument(signature, &arg);
586 TDM_RETURN_IF_FAIL(signature != NULL);
589 TDM_SNPRINTF(p, l, ", ");
593 TDM_SNPRINTF(p, l, "%u", message->arguments[i].u);
596 TDM_SNPRINTF(p, l, "%d", message->arguments[i].i);
599 TDM_SNPRINTF(p, l, "%f",
600 wl_fixed_to_double(message->arguments[i].f));
603 TDM_SNPRINTF(p, l, "\"%s\"", message->arguments[i].s);
606 if (message->arguments[i].o)
607 TDM_SNPRINTF(p, l, "%s@%u",
608 wl_resource_get_class((struct wl_resource *) message->arguments[i].o),
609 wl_resource_get_id((struct wl_resource *) message->arguments[i].o));
611 TDM_SNPRINTF(p, l, "nil");
614 TDM_SNPRINTF(p, l, "new id %s@",
615 (message->message->types[i]) ? message->message->types[i]->name : "[unknown]");
616 if (message->arguments[i].n != 0)
617 TDM_SNPRINTF(p, l, "%u", message->arguments[i].n);
619 TDM_SNPRINTF(p, l, "nil");
622 TDM_SNPRINTF(p, l, "array");
625 TDM_SNPRINTF(p, l, "fd %d", message->arguments[i].h);
632 TDM_SNPRINTF(p, l, "), cmd: %s", proc_name ? proc_name : "Unknown");
634 TDM_INFO("%s", temp);
638 tdm_event_loop_trace_enable(tdm_private_display * private_display,
641 tdm_private_loop *private_loop = private_display->private_loop;
643 TDM_RETURN_VAL_IF_FAIL(private_loop->wl_display != NULL, TDM_ERROR_NONE);
646 if (_trace_protocol_logger) {
647 wl_protocol_logger_destroy(_trace_protocol_logger);
648 _trace_protocol_logger = NULL;
650 return TDM_ERROR_NONE;
653 if (_trace_protocol_logger)
654 wl_protocol_logger_destroy(_trace_protocol_logger);
656 _trace_protocol_logger =
657 wl_display_add_protocol_logger(private_loop->wl_display, _trace_protocol_logger_cb, NULL);
659 return TDM_ERROR_NONE;