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 static tdm_private_thread *keep_private_thread;
48 struct _tdm_private_thread {
49 tdm_private_loop *private_loop;
51 pthread_t event_thread;
56 /* 0: read, 1: write */
61 _tdm_thread_main(void *data)
63 tdm_private_thread *private_thread = (tdm_private_thread*)data;
64 tdm_private_loop *private_loop = private_thread->private_loop;
69 /* Not lock/unlock for the private_thread and private_loop structure
70 * because they won't be destroyed as long as tdm thread is running.
71 * When they're destroyed, we have already exit the tdm thread.
73 private_thread->thread_tid = syscall(SYS_gettid);
75 TDM_INFO("display_tid:%d, thread_tid: %d",
76 private_thread->display_tid, private_thread->thread_tid);
78 fd = tdm_event_loop_get_fd(private_loop->dpy);
80 TDM_ERR("couldn't get fd");
90 TDM_INFO("server flush");
91 tdm_event_loop_flush(private_loop->dpy);
94 TDM_INFO("fd(%d) polling in", fd);
96 ret = poll(&fds, 1, -1);
99 TDM_INFO("fd(%d) polling out", fd);
102 if (errno == EBUSY) /* normal case */
105 TDM_ERR("poll failed: %m");
110 if (tdm_debug_thread)
111 TDM_INFO("thread got events");
113 if (tdm_event_loop_dispatch(private_loop->dpy) < 0)
114 TDM_ERR("dispatch error");
121 /* NOTE: tdm thread doesn't care about multi-thread. */
123 tdm_thread_init(tdm_private_loop *private_loop)
125 tdm_private_display *private_display;
126 tdm_private_thread *private_thread;
129 TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED);
130 TDM_RETURN_VAL_IF_FAIL(private_loop->dpy, TDM_ERROR_OPERATION_FAILED);
132 private_display = private_loop->dpy;
133 TDM_RETURN_VAL_IF_FAIL(private_display->private_loop, TDM_ERROR_OPERATION_FAILED);
135 if (private_loop->private_thread)
136 return TDM_ERROR_NONE;
138 /* enable as default */
139 thread = getenv("TDM_THREAD");
140 if (!thread || strncmp(thread, "1", 1)) {
141 TDM_INFO("not using a TDM event thread: %s", (thread)?thread:"none");
142 return TDM_ERROR_NONE;
145 private_thread = calloc(1, sizeof *private_thread);
146 if (!private_thread) {
147 TDM_ERR("alloc failed");
148 return TDM_ERROR_OUT_OF_MEMORY;
151 if (pipe(private_thread->pipe) != 0) {
152 TDM_ERR("socketpair failed: %m");
153 free(private_thread);
154 return TDM_ERROR_OPERATION_FAILED;
157 private_thread->private_loop = private_loop;
158 private_loop->private_thread = private_thread;
160 private_thread->display_tid = syscall(SYS_gettid);
162 pthread_create(&private_thread->event_thread, NULL, _tdm_thread_main,
165 keep_private_thread = private_thread;
167 TDM_INFO("using a TDM event thread. pipe(%d,%d)",
168 private_thread->pipe[0], private_thread->pipe[1]);
170 return TDM_ERROR_NONE;
174 tdm_thread_deinit(tdm_private_loop *private_loop)
176 TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
178 if (!private_loop->private_thread)
181 pthread_cancel(private_loop->private_thread->event_thread);
182 pthread_join(private_loop->private_thread->event_thread, NULL);
184 if (private_loop->private_thread->pipe[0] >= 0)
185 close(private_loop->private_thread->pipe[0]);
186 if (private_loop->private_thread->pipe[1] >= 0)
187 close(private_loop->private_thread->pipe[1]);
189 free(private_loop->private_thread);
190 private_loop->private_thread = NULL;
191 keep_private_thread = NULL;
193 TDM_INFO("Finish a TDM event thread");
197 tdm_thread_get_fd(tdm_private_loop *private_loop)
199 tdm_private_thread *private_thread;
201 TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED);
202 TDM_RETURN_VAL_IF_FAIL(private_loop, -1);
203 TDM_RETURN_VAL_IF_FAIL(private_loop->private_thread, -1);
205 private_thread = private_loop->private_thread;
207 return private_thread->pipe[0];
211 tdm_thread_send_cb(tdm_private_loop *private_loop, tdm_thread_cb_base *base)
213 tdm_private_thread *private_thread;
216 TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED);
217 TDM_RETURN_VAL_IF_FAIL(base, TDM_ERROR_INVALID_PARAMETER);
218 TDM_RETURN_VAL_IF_FAIL(private_loop, TDM_ERROR_INVALID_PARAMETER);
219 TDM_RETURN_VAL_IF_FAIL(private_loop->private_thread, TDM_ERROR_INVALID_PARAMETER);
221 private_thread = private_loop->private_thread;
223 if (tdm_debug_thread)
224 TDM_INFO("fd(%d) type(%d), length(%d)",
225 private_thread->pipe[1], base->type, base->length);
227 len = write(private_thread->pipe[1], base, base->length);
228 if (len != base->length) {
229 TDM_ERR("write failed (%d != %d): %m", (int)len, base->length);
230 return TDM_ERROR_OPERATION_FAILED;
233 return TDM_ERROR_NONE;
237 tdm_thread_handle_cb(tdm_private_loop *private_loop)
239 tdm_private_display *private_display;
240 tdm_private_thread *private_thread;
241 tdm_thread_cb_base *base;
245 /* DON'T check TDM_MUTEX_IS_LOCKED here */
247 TDM_RETURN_VAL_IF_FAIL(private_loop, TDM_ERROR_INVALID_PARAMETER);
248 TDM_RETURN_VAL_IF_FAIL(private_loop->private_thread, TDM_ERROR_INVALID_PARAMETER);
250 private_thread = private_loop->private_thread;
251 private_display = private_loop->dpy;
253 len = read(private_thread->pipe[0], buffer, sizeof buffer);
255 if (tdm_debug_thread)
256 TDM_INFO("fd(%d) read length(%d)", private_thread->pipe[0], len);
259 return TDM_ERROR_NONE;
261 if (len < sizeof *base) {
262 TDM_NEVER_GET_HERE();
263 return TDM_ERROR_OPERATION_FAILED;
266 _pthread_mutex_lock(&private_display->lock);
270 base = (tdm_thread_cb_base*)&buffer[i];
271 if (tdm_debug_thread)
272 TDM_INFO("type(%d), length(%d)", base->type, base->length);
273 switch (base->type) {
274 case TDM_THREAD_CB_OUTPUT_COMMIT:
276 tdm_thread_cb_output_commit *output_commit = (tdm_thread_cb_output_commit*)base;
277 tdm_output *output_backend =
278 tdm_display_find_output_stamp(private_loop->dpy, output_commit->output_stamp);
279 if (!output_backend) {
280 TDM_WRN("no output(%ld)", output_commit->output_stamp);
283 tdm_output_cb_commit(output_backend, output_commit->sequence,
284 output_commit->tv_sec, output_commit->tv_usec,
285 output_commit->user_data);
288 case TDM_THREAD_CB_OUTPUT_VBLANK:
290 tdm_thread_cb_output_vblank *output_vblank = (tdm_thread_cb_output_vblank*)base;
291 tdm_output *output_backend =
292 tdm_display_find_output_stamp(private_loop->dpy, output_vblank->output_stamp);
293 if (!output_backend) {
294 TDM_WRN("no output(%ld)", output_vblank->output_stamp);
297 tdm_output_cb_vblank(output_backend, output_vblank->sequence,
298 output_vblank->tv_sec, output_vblank->tv_usec,
299 output_vblank->user_data);
302 case TDM_THREAD_CB_OUTPUT_STATUS:
304 tdm_thread_cb_output_status *output_status = (tdm_thread_cb_output_status*)base;
305 tdm_output *output_backend =
306 tdm_display_find_output_stamp(private_loop->dpy, output_status->output_stamp);
307 if (!output_backend) {
308 TDM_WRN("no output(%ld)", output_status->output_stamp);
311 tdm_output_cb_status(output_backend, output_status->status,
312 output_status->user_data);
315 case TDM_THREAD_CB_PP_DONE:
317 tdm_thread_cb_pp_done *pp_done = (tdm_thread_cb_pp_done*)base;
319 tdm_pp_find_stamp(private_loop->dpy, pp_done->pp_stamp);
321 TDM_WRN("no pp(%ld)", pp_done->pp_stamp);
324 tdm_pp_cb_done(pp_backend, pp_done->src, pp_done->dst, pp_done->user_data);
327 case TDM_THREAD_CB_CAPTURE_DONE:
329 tdm_thread_cb_capture_done *capture_done = (tdm_thread_cb_capture_done*)base;
330 tdm_capture *capture_backend =
331 tdm_capture_find_stamp(private_loop->dpy, capture_done->capture_stamp);
332 if (!capture_backend) {
333 TDM_WRN("no capture(%ld)", capture_done->capture_stamp);
336 tdm_capture_cb_done(capture_backend, capture_done->buffer, capture_done->user_data);
345 _pthread_mutex_unlock(&private_display->lock);
347 tdm_event_loop_flush(private_loop->dpy);
349 return TDM_ERROR_NONE;
353 tdm_thread_in_display_thread(pid_t tid)
355 if (!keep_private_thread)
358 /* DON'T check TDM_MUTEX_IS_LOCKED here */
360 return (keep_private_thread->display_tid == tid) ? 1 : 0;
364 tdm_thread_is_running(void)
366 /* DON'T check TDM_MUTEX_IS_LOCKED here */
368 return (keep_private_thread) ? 1 : 0;