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 tdm_private_loop *private_loop;
49 pthread_t event_thread;
54 /* 0: read, 1: write */
59 _tdm_thread_main(void *data)
61 tdm_private_thread *private_thread = (tdm_private_thread*)data;
62 tdm_private_loop *private_loop = private_thread->private_loop;
67 /* Not lock/unlock for the private_thread and private_loop structure
68 * because they won't be destroyed as long as tdm thread is running.
69 * When they're destroyed, we have already exit the tdm thread.
71 private_thread->thread_tid = syscall(SYS_gettid);
73 TDM_INFO("display_tid:%d, thread_tid: %d",
74 private_thread->display_tid, private_thread->thread_tid);
76 fd = tdm_event_loop_get_fd(private_loop->dpy);
78 TDM_ERR("couldn't get fd");
88 TDM_INFO("server flush");
89 tdm_event_loop_flush(private_loop->dpy);
92 TDM_INFO("fd(%d) polling in", fd);
94 ret = poll(&fds, 1, -1);
97 TDM_INFO("fd(%d) polling out", fd);
100 if (errno == EBUSY) /* normal case */
103 TDM_ERR("poll failed: %m");
108 if (tdm_debug_thread)
109 TDM_INFO("thread got events");
111 if (tdm_event_loop_dispatch(private_loop->dpy) < 0)
112 TDM_ERR("dispatch error");
119 /* NOTE: tdm thread doesn't care about multi-thread. */
121 tdm_thread_init(tdm_private_loop *private_loop)
123 tdm_private_display *private_display;
124 tdm_private_thread *private_thread;
127 TDM_RETURN_VAL_IF_FAIL(private_loop->dpy, TDM_ERROR_OPERATION_FAILED);
129 private_display = private_loop->dpy;
130 TDM_RETURN_VAL_IF_FAIL(private_display->private_loop, TDM_ERROR_OPERATION_FAILED);
132 if (private_loop->private_thread)
133 return TDM_ERROR_NONE;
135 /* enable as default */
136 thread = getenv("TDM_THREAD");
137 if (thread && strstr(thread, "0")) {
138 TDM_INFO("not using a TDM event thread");
139 return TDM_ERROR_NONE;
142 private_thread = calloc(1, sizeof *private_thread);
143 if (!private_thread) {
144 TDM_ERR("alloc failed");
145 return TDM_ERROR_OUT_OF_MEMORY;
148 if (pipe(private_thread->pipe) != 0) {
149 TDM_ERR("socketpair failed: %m");
150 free(private_thread);
151 return TDM_ERROR_OPERATION_FAILED;
154 private_thread->private_loop = private_loop;
155 private_loop->private_thread = private_thread;
157 private_thread->display_tid = syscall(SYS_gettid);
159 pthread_create(&private_thread->event_thread, NULL, _tdm_thread_main,
162 TDM_INFO("using a TDM event thread. pipe(%d,%d)",
163 private_thread->pipe[0], private_thread->pipe[1]);
165 return TDM_ERROR_NONE;
169 tdm_thread_deinit(tdm_private_loop *private_loop)
171 if (!private_loop->private_thread)
174 pthread_cancel(private_loop->private_thread->event_thread);
175 pthread_join(private_loop->private_thread->event_thread, NULL);
177 if (private_loop->private_thread->pipe[0] >= 0)
178 close(private_loop->private_thread->pipe[0]);
179 if (private_loop->private_thread->pipe[1] >= 0)
180 close(private_loop->private_thread->pipe[1]);
182 free(private_loop->private_thread);
183 private_loop->private_thread = NULL;
185 TDM_INFO("Finish a TDM event thread");
189 tdm_thread_get_fd(tdm_private_loop *private_loop)
191 tdm_private_thread *private_thread;
193 TDM_RETURN_VAL_IF_FAIL(private_loop, -1);
194 TDM_RETURN_VAL_IF_FAIL(private_loop->private_thread, -1);
196 private_thread = private_loop->private_thread;
198 return private_thread->pipe[0];
202 tdm_thread_send_cb(tdm_private_loop *private_loop, tdm_thread_cb_base *base)
204 tdm_private_thread *private_thread;
207 TDM_RETURN_VAL_IF_FAIL(base, TDM_ERROR_INVALID_PARAMETER);
208 TDM_RETURN_VAL_IF_FAIL(private_loop, TDM_ERROR_INVALID_PARAMETER);
209 TDM_RETURN_VAL_IF_FAIL(private_loop->private_thread, TDM_ERROR_INVALID_PARAMETER);
211 private_thread = private_loop->private_thread;
213 if (tdm_debug_thread)
214 TDM_INFO("fd(%d) type(%d), length(%d)",
215 private_thread->pipe[1], base->type, base->length);
217 len = write(private_thread->pipe[1], base, base->length);
218 if (len != base->length) {
219 TDM_ERR("write failed (%d != %d): %m", len, base->length);
220 return TDM_ERROR_OPERATION_FAILED;
223 return TDM_ERROR_NONE;
227 tdm_thread_handle_cb(tdm_private_loop *private_loop)
229 tdm_private_thread *private_thread;
230 tdm_thread_cb_base *base;
234 TDM_RETURN_VAL_IF_FAIL(private_loop, TDM_ERROR_INVALID_PARAMETER);
235 TDM_RETURN_VAL_IF_FAIL(private_loop->private_thread, TDM_ERROR_INVALID_PARAMETER);
237 private_thread = private_loop->private_thread;
239 len = read(private_thread->pipe[0], buffer, sizeof buffer);
241 if (tdm_debug_thread)
242 TDM_INFO("fd(%d) read length(%d)", private_thread->pipe[0], len);
245 return TDM_ERROR_NONE;
247 if (len < sizeof *base) {
248 TDM_NEVER_GET_HERE();
249 return TDM_ERROR_OPERATION_FAILED;
254 base = (tdm_thread_cb_base*)&buffer[i];
255 if (tdm_debug_thread)
256 TDM_INFO("type(%d), length(%d)", base->type, base->length);
257 switch (base->type) {
258 case TDM_THREAD_CB_OUTPUT_COMMIT:
260 tdm_thread_cb_output_commit *output_commit = (tdm_thread_cb_output_commit*)base;
261 tdm_output *output_backend =
262 tdm_display_find_output_stamp(private_loop->dpy, output_commit->output_stamp);
263 if (!output_backend) {
264 TDM_WRN("no output(%ld)", output_commit->output_stamp);
267 tdm_output_cb_commit(output_backend, output_commit->sequence,
268 output_commit->tv_sec, output_commit->tv_usec,
269 output_commit->user_data);
272 case TDM_THREAD_CB_OUTPUT_VBLANK:
274 tdm_thread_cb_output_vblank *output_vblank = (tdm_thread_cb_output_vblank*)base;
275 tdm_output *output_backend =
276 tdm_display_find_output_stamp(private_loop->dpy, output_vblank->output_stamp);
277 if (!output_backend) {
278 TDM_WRN("no output(%ld)", output_vblank->output_stamp);
281 tdm_output_cb_vblank(output_backend, output_vblank->sequence,
282 output_vblank->tv_sec, output_vblank->tv_usec,
283 output_vblank->user_data);
286 case TDM_THREAD_CB_OUTPUT_STATUS:
288 tdm_thread_cb_output_status *output_status = (tdm_thread_cb_output_status*)base;
289 tdm_output *output_backend =
290 tdm_display_find_output_stamp(private_loop->dpy, output_status->output_stamp);
291 if (!output_backend) {
292 TDM_WRN("no output(%ld)", output_status->output_stamp);
295 tdm_output_cb_status(output_backend, output_status->status,
296 output_status->user_data);
299 case TDM_THREAD_CB_PP_DONE:
301 tdm_thread_cb_pp_done *pp_done = (tdm_thread_cb_pp_done*)base;
303 tdm_pp_find_stamp(private_loop->dpy, pp_done->pp_stamp);
305 TDM_WRN("no pp(%ld)", pp_done->pp_stamp);
308 tdm_pp_cb_done(pp_backend, pp_done->src, pp_done->dst, pp_done->user_data);
311 case TDM_THREAD_CB_CAPTURE_DONE:
313 tdm_thread_cb_capture_done *capture_done = (tdm_thread_cb_capture_done*)base;
314 tdm_capture *capture_backend =
315 tdm_capture_find_stamp(private_loop->dpy, capture_done->capture_stamp);
316 if (!capture_backend) {
317 TDM_WRN("no capture(%ld)", capture_done->capture_stamp);
320 tdm_capture_cb_done(capture_backend, capture_done->buffer, capture_done->user_data);
329 tdm_event_loop_flush(private_loop->dpy);
331 return TDM_ERROR_NONE;
335 tdm_thread_in_display_thread(tdm_private_loop *private_loop, pid_t tid)
337 tdm_private_thread *private_thread;
339 TDM_RETURN_VAL_IF_FAIL(private_loop, 1);
341 if (!private_loop->private_thread)
344 private_thread = private_loop->private_thread;
346 return (private_thread->display_tid == tid) ? 1 : 0;