fix syntax error
[platform/core/uifw/libtdm.git] / src / tdm_thread.c
1 /**************************************************************************
2
3 libtdm
4
5 Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
6
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>
13
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:
21
22 The above copyright notice and this permission notice (including the
23 next paragraph) shall be included in all copies or substantial portions
24 of the Software.
25
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.
33
34 **************************************************************************/
35
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39
40 #include <sys/socket.h>
41
42 #include "tdm.h"
43 #include "tdm_private.h"
44 #include "tdm_list.h"
45
46 struct _tdm_private_thread {
47         tdm_private_loop *private_loop;
48
49         pthread_t event_thread;
50
51         pid_t display_tid;
52         pid_t thread_tid;
53
54         /* 0: read, 1: write */
55         int pipe[2];
56 };
57
58 static void*
59 _tdm_thread_main(void *data)
60 {
61         tdm_private_thread *private_thread = (tdm_private_thread*)data;
62         tdm_private_loop *private_loop = private_thread->private_loop;
63         int fd;
64         struct pollfd fds;
65         int ret;
66
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.
70          */
71         private_thread->thread_tid = syscall(SYS_gettid);
72
73         TDM_INFO("display_tid:%d, thread_tid: %d",
74                  private_thread->display_tid, private_thread->thread_tid);
75
76         fd = tdm_event_loop_get_fd(private_loop->dpy);
77         if (fd < 0) {
78                 TDM_ERR("couldn't get fd");
79                 goto exit_thread;
80         }
81
82         fds.events = POLLIN;
83         fds.fd = fd;
84         fds.revents = 0;
85
86         while (1) {
87                 if (tdm_debug_thread)
88                         TDM_INFO("server flush");
89                 tdm_event_loop_flush(private_loop->dpy);
90
91                 if (tdm_debug_thread)
92                         TDM_INFO("fd(%d) polling in", fd);
93
94                 ret = poll(&fds, 1, -1);
95
96                 if (tdm_debug_thread)
97                         TDM_INFO("fd(%d) polling out", fd);
98
99                 if (ret < 0) {
100                         if (errno == EBUSY)  /* normal case */
101                                 continue;
102                         else {
103                                 TDM_ERR("poll failed: %m");
104                                 goto exit_thread;
105                         }
106                 }
107
108                 if (tdm_debug_thread)
109                         TDM_INFO("thread got events");
110
111                 if (tdm_event_loop_dispatch(private_loop->dpy) < 0)
112                         TDM_ERR("dispatch error");
113         }
114
115 exit_thread:
116         pthread_exit(NULL);
117 }
118
119 /* NOTE: tdm thread doesn't care about multi-thread. */
120 INTERN tdm_error
121 tdm_thread_init(tdm_private_loop *private_loop)
122 {
123         tdm_private_display *private_display;
124         tdm_private_thread *private_thread;
125         const char *thread;
126
127         TDM_RETURN_VAL_IF_FAIL(private_loop->dpy, TDM_ERROR_OPERATION_FAILED);
128
129         private_display = private_loop->dpy;
130         TDM_RETURN_VAL_IF_FAIL(private_display->private_loop, TDM_ERROR_OPERATION_FAILED);
131
132         if (private_loop->private_thread)
133                 return TDM_ERROR_NONE;
134
135         /* enable as default */
136         thread = getenv("TDM_THREAD");
137         if (!thread || strncmp(thread, "1", 1)) {
138                 TDM_INFO("not using a TDM event thread: %s", (thread)?thread:"none");
139                 return TDM_ERROR_NONE;
140         }
141
142         private_thread = calloc(1, sizeof *private_thread);
143         if (!private_thread) {
144                 TDM_ERR("alloc failed");
145                 return TDM_ERROR_OUT_OF_MEMORY;
146         }
147
148         if (pipe(private_thread->pipe) != 0) {
149                 TDM_ERR("socketpair failed: %m");
150                 free(private_thread);
151                 return TDM_ERROR_OPERATION_FAILED;
152         }
153
154         private_thread->private_loop = private_loop;
155         private_loop->private_thread = private_thread;
156
157         private_thread->display_tid = syscall(SYS_gettid);
158
159         pthread_create(&private_thread->event_thread, NULL, _tdm_thread_main,
160                        private_thread);
161
162         TDM_INFO("using a TDM event thread. pipe(%d,%d)",
163                  private_thread->pipe[0], private_thread->pipe[1]);
164
165         return TDM_ERROR_NONE;
166 }
167
168 INTERN void
169 tdm_thread_deinit(tdm_private_loop *private_loop)
170 {
171         if (!private_loop->private_thread)
172                 return;
173
174         pthread_cancel(private_loop->private_thread->event_thread);
175         pthread_join(private_loop->private_thread->event_thread, NULL);
176
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]);
181
182         free(private_loop->private_thread);
183         private_loop->private_thread = NULL;
184
185         TDM_INFO("Finish a TDM event thread");
186 }
187
188 INTERN int
189 tdm_thread_get_fd(tdm_private_loop *private_loop)
190 {
191         tdm_private_thread *private_thread;
192
193         TDM_RETURN_VAL_IF_FAIL(private_loop, -1);
194         TDM_RETURN_VAL_IF_FAIL(private_loop->private_thread, -1);
195
196         private_thread = private_loop->private_thread;
197
198         return private_thread->pipe[0];
199 }
200
201 INTERN tdm_error
202 tdm_thread_send_cb(tdm_private_loop *private_loop, tdm_thread_cb_base *base)
203 {
204         tdm_private_thread *private_thread;
205         ssize_t len;
206
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);
210
211         private_thread = private_loop->private_thread;
212
213         if (tdm_debug_thread)
214                 TDM_INFO("fd(%d) type(%d), length(%d)",
215                          private_thread->pipe[1], base->type, base->length);
216
217         len = write(private_thread->pipe[1], base, base->length);
218         if (len != base->length) {
219                 TDM_ERR("write failed (%d != %d): %m", (int)len, base->length);
220                 return TDM_ERROR_OPERATION_FAILED;
221         }
222
223         return TDM_ERROR_NONE;
224 }
225
226 INTERN tdm_error
227 tdm_thread_handle_cb(tdm_private_loop *private_loop)
228 {
229         tdm_private_thread *private_thread;
230         tdm_thread_cb_base *base;
231         char buffer[1024];
232         int len, i;
233
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);
236
237         private_thread = private_loop->private_thread;
238
239         len = read(private_thread->pipe[0], buffer, sizeof buffer);
240
241         if (tdm_debug_thread)
242                 TDM_INFO("fd(%d) read length(%d)", private_thread->pipe[0], len);
243
244         if (len == 0)
245                 return TDM_ERROR_NONE;
246
247         if (len < sizeof *base) {
248                 TDM_NEVER_GET_HERE();
249                 return TDM_ERROR_OPERATION_FAILED;
250         }
251
252         i = 0;
253         while (i < len) {
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:
259                 {
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);
265                                 break;
266                         }
267                         tdm_output_cb_commit(output_backend, output_commit->sequence,
268                                              output_commit->tv_sec, output_commit->tv_usec,
269                                              output_commit->user_data);
270                         break;
271                 }
272                 case TDM_THREAD_CB_OUTPUT_VBLANK:
273                 {
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);
279                                 break;
280                         }
281                         tdm_output_cb_vblank(output_backend, output_vblank->sequence,
282                                              output_vblank->tv_sec, output_vblank->tv_usec,
283                                              output_vblank->user_data);
284                         break;
285                 }
286                 case TDM_THREAD_CB_OUTPUT_STATUS:
287                 {
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);
293                                 break;
294                         }
295                         tdm_output_cb_status(output_backend, output_status->status,
296                                              output_status->user_data);
297                         break;
298                 }
299                 case TDM_THREAD_CB_PP_DONE:
300                 {
301                         tdm_thread_cb_pp_done *pp_done = (tdm_thread_cb_pp_done*)base;
302                         tdm_pp *pp_backend =
303                                 tdm_pp_find_stamp(private_loop->dpy, pp_done->pp_stamp);
304                         if (!pp_backend) {
305                                 TDM_WRN("no pp(%ld)", pp_done->pp_stamp);
306                                 break;
307                         }
308                         tdm_pp_cb_done(pp_backend, pp_done->src, pp_done->dst, pp_done->user_data);
309                         break;
310                 }
311                 case TDM_THREAD_CB_CAPTURE_DONE:
312                 {
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);
318                                 break;
319                         }
320                         tdm_capture_cb_done(capture_backend, capture_done->buffer, capture_done->user_data);
321                         break;
322                 }
323                 default:
324                         break;
325                 }
326                 i += base->length;
327         }
328
329         tdm_event_loop_flush(private_loop->dpy);
330
331         return TDM_ERROR_NONE;
332 }
333
334 INTERN int
335 tdm_thread_in_display_thread(tdm_private_loop *private_loop, pid_t tid)
336 {
337         tdm_private_thread *private_thread;
338
339         TDM_RETURN_VAL_IF_FAIL(private_loop, 1);
340
341         if (!private_loop->private_thread)
342                 return 1;
343
344         private_thread = private_loop->private_thread;
345
346         return (private_thread->display_tid == tid) ? 1 : 0;
347 }