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 <sys/socket.h>
43 #include "tdm_private.h"
46 struct _tdm_private_thread {
47 pthread_t event_thread;
48 pthread_mutex_t event_mutex;
53 /* 0: read, 1: write */
58 _tdm_thread_main(void *data)
60 tdm_private_display *private_display = (tdm_private_display*)data;
61 tdm_private_thread *private_thread;
66 _pthread_mutex_lock(&private_display->lock);
68 private_thread = private_display->private_thread;
69 private_thread->thread_tid = syscall(SYS_gettid);
71 TDM_INFO("display_tid:%d, thread_tid: %d",
72 private_thread->display_tid, private_thread->thread_tid);
74 fd = tdm_event_loop_get_fd(private_display);
76 TDM_ERR("couldn't get fd");
84 _pthread_mutex_unlock(&private_display->lock);
89 TDM_INFO("fd(%d) polling in", fd);
91 ret = poll(&fds, 1, -1);
94 TDM_INFO("fd(%d) polling out", fd);
97 if (errno == EBUSY) /* normal case */
100 TDM_ERR("poll failed: %m");
105 if (tdm_debug_thread)
106 TDM_INFO("thread got events");
108 _pthread_mutex_lock(&private_display->lock);
110 if (tdm_event_loop_dispatch(private_display) < 0)
111 TDM_ERR("dispatch error");
113 _pthread_mutex_unlock(&private_display->lock);
121 tdm_thread_init(tdm_private_display *private_display)
123 tdm_private_thread *private_thread;
126 if (private_display->private_thread)
127 return TDM_ERROR_NONE;
129 /* enable as default */
130 thread = getenv("TDM_THREAD");
131 if (thread && strstr(thread, "0")) {
132 TDM_INFO("not using a TDM event thread");
133 return TDM_ERROR_NONE;
136 private_thread = calloc(1, sizeof *private_thread);
137 if (!private_thread) {
138 TDM_ERR("alloc failed");
139 return TDM_ERROR_OUT_OF_MEMORY;
142 if (pipe(private_thread->pipe) != 0) {
143 TDM_ERR("socketpair failed: %m");
144 free(private_thread);
145 return TDM_ERROR_OPERATION_FAILED;
148 private_thread->display_tid = syscall(SYS_gettid);
150 pthread_mutex_init(&private_thread->event_mutex, NULL);
151 pthread_create(&private_thread->event_thread, NULL, _tdm_thread_main,
154 private_display->private_thread = private_thread;
156 TDM_INFO("using a TDM event thread. pipe(%d,%d)",
157 private_thread->pipe[0], private_thread->pipe[1]);
159 return TDM_ERROR_NONE;
163 tdm_thread_deinit(tdm_private_display *private_display)
165 if (!private_display->private_thread)
168 pthread_cancel(private_display->private_thread->event_thread);
169 pthread_join(private_display->private_thread->event_thread, NULL);
170 pthread_mutex_destroy(&private_display->private_thread->event_mutex);
172 if (private_display->private_thread->pipe[0] >= 0)
173 close(private_display->private_thread->pipe[0]);
174 if (private_display->private_thread->pipe[1] >= 0)
175 close(private_display->private_thread->pipe[1]);
177 free(private_display->private_thread);
178 private_display->private_thread = NULL;
180 TDM_INFO("Finish a TDM event thread");
184 tdm_thread_get_fd(tdm_private_display *private_display)
186 tdm_private_thread *private_thread;
188 TDM_RETURN_VAL_IF_FAIL(private_display, -1);
189 TDM_RETURN_VAL_IF_FAIL(private_display->private_thread, -1);
191 private_thread = private_display->private_thread;
193 return private_thread->pipe[0];
197 tdm_thread_send_cb(tdm_private_display *private_display, tdm_thread_cb_base *base)
199 tdm_private_thread *private_thread;
202 TDM_RETURN_VAL_IF_FAIL(base, TDM_ERROR_INVALID_PARAMETER);
203 TDM_RETURN_VAL_IF_FAIL(private_display, TDM_ERROR_INVALID_PARAMETER);
204 TDM_RETURN_VAL_IF_FAIL(private_display->private_thread, TDM_ERROR_INVALID_PARAMETER);
206 private_thread = private_display->private_thread;
208 if (tdm_debug_thread)
209 TDM_INFO("fd(%d) type(%d), length(%d)",
210 private_thread->pipe[1], base->type, base->length);
212 len = write(private_thread->pipe[1], base, base->length);
213 if (len != base->length) {
214 TDM_ERR("write failed (%d != %d): %m", len, base->length);
215 return TDM_ERROR_OPERATION_FAILED;
218 return TDM_ERROR_NONE;
222 tdm_thread_handle_cb(tdm_private_display *private_display)
224 tdm_private_thread *private_thread;
225 tdm_thread_cb_base *base;
229 TDM_RETURN_VAL_IF_FAIL(private_display, TDM_ERROR_INVALID_PARAMETER);
230 TDM_RETURN_VAL_IF_FAIL(private_display->private_thread, TDM_ERROR_INVALID_PARAMETER);
232 private_thread = private_display->private_thread;
234 len = read(private_thread->pipe[0], buffer, sizeof buffer);
236 if (tdm_debug_thread)
237 TDM_INFO("fd(%d) read length(%d)", private_thread->pipe[0], len);
240 return TDM_ERROR_NONE;
242 if (len < sizeof *base) {
243 TDM_NEVER_GET_HERE();
244 return TDM_ERROR_OPERATION_FAILED;
249 base = (tdm_thread_cb_base*)&buffer[i];
250 if (tdm_debug_thread)
251 TDM_INFO("type(%d), length(%d)", base->type, base->length);
252 switch (base->type) {
253 case TDM_THREAD_CB_OUTPUT_COMMIT:
255 tdm_thread_cb_output_commit *output_commit = (tdm_thread_cb_output_commit*)base;
256 tdm_output *output_backend =
257 tdm_display_find_output_stamp(private_display, output_commit->output_stamp);
258 if (!output_backend) {
259 TDM_WRN("no output(%ld)", output_commit->output_stamp);
262 tdm_output_cb_commit(output_backend, output_commit->sequence,
263 output_commit->tv_sec, output_commit->tv_usec,
264 output_commit->user_data);
267 case TDM_THREAD_CB_OUTPUT_VBLANK:
269 tdm_thread_cb_output_vblank *output_vblank = (tdm_thread_cb_output_vblank*)base;
270 tdm_output *output_backend =
271 tdm_display_find_output_stamp(private_display, output_vblank->output_stamp);
272 if (!output_backend) {
273 TDM_WRN("no output(%ld)", output_vblank->output_stamp);
276 tdm_output_cb_vblank(output_backend, output_vblank->sequence,
277 output_vblank->tv_sec, output_vblank->tv_usec,
278 output_vblank->user_data);
281 case TDM_THREAD_CB_OUTPUT_STATUS:
283 tdm_thread_cb_output_status *output_status = (tdm_thread_cb_output_status*)base;
284 tdm_output *output_backend =
285 tdm_display_find_output_stamp(private_display, output_status->output_stamp);
286 if (!output_backend) {
287 TDM_WRN("no output(%ld)", output_status->output_stamp);
290 tdm_output_cb_status(output_backend, output_status->status,
291 output_status->user_data);
294 case TDM_THREAD_CB_PP_DONE:
296 tdm_thread_cb_pp_done *pp_done = (tdm_thread_cb_pp_done*)base;
298 tdm_pp_find_stamp(private_display, pp_done->pp_stamp);
300 TDM_WRN("no pp(%ld)", pp_done->pp_stamp);
303 tdm_pp_cb_done(pp_backend, pp_done->src, pp_done->dst, pp_done->user_data);
306 case TDM_THREAD_CB_CAPTURE_DONE:
308 tdm_thread_cb_capture_done *capture_done = (tdm_thread_cb_capture_done*)base;
309 tdm_capture *capture_backend =
310 tdm_capture_find_stamp(private_display, capture_done->capture_stamp);
311 if (!capture_backend) {
312 TDM_WRN("no capture(%ld)", capture_done->capture_stamp);
315 tdm_capture_cb_done(capture_backend, capture_done->buffer, capture_done->user_data);
324 return TDM_ERROR_NONE;
328 tdm_thread_in_display_thread(tdm_private_display *private_display)
330 tdm_private_thread *private_thread;
332 TDM_RETURN_VAL_IF_FAIL(private_display, 1);
334 if (!private_display->private_thread)
337 private_thread = private_display->private_thread;
339 return (private_thread->display_tid == syscall(SYS_gettid)) ? 1 : 0;