Use timer to call the output change callback of the sub-thread.
[platform/core/uifw/libtdm.git] / src / tdm_event_loop.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 "tdm.h"
41 #include "tdm_private.h"
42 #include "tdm_list.h"
43
44 #include <wayland-server-core.h>
45
46 typedef struct _tdm_event_loop_source_base {
47         struct wl_event_source *wl_source;
48 } tdm_event_loop_source_base;
49
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;
54         void *user_data;
55 } tdm_event_loop_source_fd;
56
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;
61         void *user_data;
62 } tdm_event_loop_source_timer;
63
64 static tdm_error
65 _tdm_event_loop_main_fd_handler(int fd, tdm_event_loop_mask mask, void *user_data)
66 {
67         tdm_private_display *private_display = (tdm_private_display*)user_data;
68         tdm_private_loop *private_loop;
69         tdm_func_display *func_display;
70         tdm_error ret;
71
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);
75
76         private_loop = private_display->private_loop;
77
78         if (tdm_debug_thread)
79                 TDM_INFO("backend fd(%d) event happens", private_loop->backend_fd);
80
81         func_display = &private_display->func_display;
82         if (!func_display->display_handle_events)
83                 return TDM_ERROR_NONE;
84
85         ret = func_display->display_handle_events(private_display->bdata);
86
87         return ret;
88 }
89
90 INTERN tdm_error
91 tdm_event_loop_init(tdm_private_display *private_display)
92 {
93         tdm_private_loop *private_loop;
94         tdm_error ret;
95
96         TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED);
97
98         if (private_display->private_loop)
99                 return TDM_ERROR_NONE;
100
101         private_loop = calloc(1, sizeof * private_loop);
102         if (!private_loop) {
103                 TDM_ERR("alloc failed");
104                 return TDM_ERROR_OUT_OF_MEMORY;
105         }
106
107         private_loop->backend_fd = -1;
108
109         private_loop->wl_display = wl_display_create();
110         if (!private_loop->wl_display) {
111                 TDM_ERR("creating a wayland display failed");
112                 free(private_loop);
113                 return TDM_ERROR_OUT_OF_MEMORY;
114         }
115         private_loop->wl_loop = wl_display_get_event_loop(private_loop->wl_display);
116
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);
121                 free(private_loop);
122                 return TDM_ERROR_OPERATION_FAILED;
123         }
124
125         private_loop->dpy = private_display;
126         private_display->private_loop = private_loop;
127
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);
133                 free(private_loop);
134                 return TDM_ERROR_OPERATION_FAILED;
135         }
136
137         TDM_INFO("event loop fd(%d)", wl_event_loop_get_fd(private_loop->wl_loop));
138
139         return TDM_ERROR_NONE;
140 }
141
142 INTERN void
143 tdm_event_loop_deinit(tdm_private_display *private_display)
144 {
145         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
146
147         if (!private_display->private_loop)
148                 return;
149
150         /* after tdm_thread_deinit, we don't worry about thread things because it's finalized */
151         tdm_thread_deinit(private_display->private_loop);
152
153
154         _pthread_mutex_unlock(&private_display->lock);
155         tdm_server_deinit(private_display->private_loop);
156
157         if (private_display->private_loop->backend_source)
158                 tdm_event_loop_source_remove(private_display->private_loop->backend_source);
159
160         if (private_display->private_loop->wl_display)
161                 wl_display_destroy(private_display->private_loop->wl_display);
162
163         free(private_display->private_loop);
164         private_display->private_loop = NULL;
165
166         _pthread_mutex_lock(&private_display->lock);
167 }
168
169 INTERN void
170 tdm_event_loop_create_backend_source(tdm_private_display *private_display)
171 {
172         tdm_private_loop *private_loop = private_display->private_loop;
173         tdm_func_display *func_display;
174         tdm_error ret;
175         int fd = -1;
176
177         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
178         TDM_RETURN_IF_FAIL(private_loop != NULL);
179
180         func_display = &private_display->func_display;
181         if (!func_display->display_get_fd) {
182                 TDM_INFO("TDM backend module won't offer a display fd");
183                 return;
184         }
185
186         ret = func_display->display_get_fd(private_display->bdata, &fd);
187         if (fd < 0) {
188                 TDM_ERR("TDM backend module returns fd(%d)", fd);
189                 return;
190         }
191
192         if (!func_display->display_handle_events) {
193                 TDM_ERR("no display_handle_events function");
194                 return;
195         }
196
197         private_loop->backend_source =
198                 tdm_event_loop_add_fd_handler(private_display, fd,
199                                                                           TDM_EVENT_LOOP_READABLE,
200                                                                           _tdm_event_loop_main_fd_handler,
201                                                                           private_display, &ret);
202         if (!private_loop->backend_source) {
203                 TDM_ERR("no backend fd(%d) source", fd);
204                 return;
205         }
206
207         private_loop->backend_fd = fd;
208
209         TDM_INFO("backend fd(%d) source created", private_loop->backend_fd);
210 }
211
212 INTERN int
213 tdm_event_loop_get_fd(tdm_private_display *private_display)
214 {
215         tdm_private_loop *private_loop = private_display->private_loop;
216
217         /* DON'T check TDM_MUTEX_IS_LOCKED here */
218
219         TDM_RETURN_VAL_IF_FAIL(private_loop->wl_loop != NULL, -1);
220
221         return wl_event_loop_get_fd(private_loop->wl_loop);
222 }
223
224 INTERN tdm_error
225 tdm_event_loop_dispatch(tdm_private_display *private_display)
226 {
227         tdm_private_loop *private_loop = private_display->private_loop;
228
229         /* DON'T check TDM_MUTEX_IS_LOCKED here */
230
231         TDM_RETURN_VAL_IF_FAIL(private_loop->wl_loop != NULL, TDM_ERROR_OPERATION_FAILED);
232
233         if (tdm_debug_thread)
234                 TDM_INFO("dispatch");
235
236         if (tdm_thread_is_running() &&
237                 tdm_thread_in_display_thread(syscall(SYS_gettid))) {
238                 TDM_NEVER_GET_HERE();
239                 return TDM_ERROR_OPERATION_FAILED;
240         }
241
242         /* Don't set timeout to -1. It can make deadblock by two mutex locks.
243          * If need to set -1, use poll() and call tdm_event_loop_dispatch() after
244          * escaping polling.
245          */
246         if (wl_event_loop_dispatch(private_loop->wl_loop, 0) < 0)
247                 TDM_ERR("dispatch failed");
248
249         wl_display_flush_clients(private_loop->wl_display);
250
251         return TDM_ERROR_NONE;
252 }
253
254
255 INTERN void
256 tdm_event_loop_flush(tdm_private_display *private_display)
257 {
258         tdm_private_loop *private_loop = private_display->private_loop;
259
260         /* DON'T check TDM_MUTEX_IS_LOCKED here */
261
262         TDM_RETURN_IF_FAIL(private_loop->wl_display != NULL);
263
264         if (tdm_thread_is_running() &&
265                 tdm_thread_in_display_thread(syscall(SYS_gettid))) {
266                 TDM_NEVER_GET_HERE();
267                 return;
268         }
269
270         wl_display_flush_clients(private_loop->wl_display);
271 }
272
273 static int
274 _tdm_event_loop_fd_func(int fd, uint32_t wl_mask, void *data)
275 {
276         tdm_event_loop_source_fd *fd_source = (tdm_event_loop_source_fd*)data;
277         tdm_private_display *private_display;
278         tdm_event_loop_mask mask = 0;
279
280         /* DON'T check TDM_MUTEX_IS_LOCKED here */
281
282         TDM_RETURN_VAL_IF_FAIL(fd_source, 1);
283         TDM_RETURN_VAL_IF_FAIL(fd_source->func, 1);
284
285         private_display = fd_source->private_display;
286
287         if (wl_mask & WL_EVENT_READABLE)
288                 mask |= TDM_EVENT_LOOP_READABLE;
289         if (wl_mask & WL_EVENT_WRITABLE)
290                 mask |= TDM_EVENT_LOOP_WRITABLE;
291         if (wl_mask & WL_EVENT_HANGUP)
292                 mask |= TDM_EVENT_LOOP_HANGUP;
293         if (wl_mask & WL_EVENT_ERROR)
294                 mask |= TDM_EVENT_LOOP_ERROR;
295
296         _pthread_mutex_lock(&private_display->lock);
297         fd_source->func(fd, mask, fd_source->user_data);
298         _pthread_mutex_unlock(&private_display->lock);
299
300         return 1;
301 }
302
303 EXTERN tdm_event_loop_source *
304 tdm_event_loop_add_fd_handler(tdm_display *dpy, int fd, tdm_event_loop_mask mask,
305                                                           tdm_event_loop_fd_handler func, void *user_data,
306                                                           tdm_error *error)
307 {
308         tdm_private_display *private_display;
309         tdm_private_loop *private_loop;
310         tdm_event_loop_source_fd *fd_source;
311         uint32_t wl_mask = 0;
312         tdm_error ret;
313
314         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED, NULL);
315         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(dpy, TDM_ERROR_INVALID_PARAMETER, NULL);
316         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(fd >= 0, TDM_ERROR_INVALID_PARAMETER, NULL);
317         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(func, TDM_ERROR_INVALID_PARAMETER, NULL);
318
319         private_display = (tdm_private_display*)dpy;
320         private_loop = private_display->private_loop;
321         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(private_loop, TDM_ERROR_INVALID_PARAMETER, NULL);
322         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(private_loop->wl_loop, TDM_ERROR_INVALID_PARAMETER, NULL);
323
324         fd_source = calloc(1, sizeof(tdm_event_loop_source_fd));
325         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(fd_source, TDM_ERROR_OUT_OF_MEMORY, NULL);
326
327         if (mask & TDM_EVENT_LOOP_READABLE)
328                 wl_mask |= WL_EVENT_READABLE;
329         if (mask & TDM_EVENT_LOOP_WRITABLE)
330                 wl_mask |= WL_EVENT_WRITABLE;
331
332         fd_source->base.wl_source =
333                 wl_event_loop_add_fd(private_loop->wl_loop,
334                                                          fd, wl_mask, _tdm_event_loop_fd_func, fd_source);
335         if (!fd_source->base.wl_source) {
336                 if (error)
337                         *error = TDM_ERROR_OUT_OF_MEMORY;
338                 free(fd_source);
339                 return NULL;
340         }
341
342         fd_source->private_display = private_display;
343         fd_source->func = func;
344         fd_source->user_data = user_data;
345
346         if (error)
347                 *error = TDM_ERROR_NONE;
348
349         return (tdm_event_loop_source *)fd_source;
350 }
351
352 EXTERN tdm_error
353 tdm_event_loop_source_fd_update(tdm_event_loop_source *source, tdm_event_loop_mask mask)
354 {
355         tdm_event_loop_source_fd *fd_source = source;
356         uint32_t wl_mask = 0;
357
358         TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED);
359         TDM_RETURN_VAL_IF_FAIL(fd_source, TDM_ERROR_INVALID_PARAMETER);
360
361         if (mask & TDM_EVENT_LOOP_READABLE)
362                 wl_mask |= WL_EVENT_READABLE;
363         if (mask & TDM_EVENT_LOOP_WRITABLE)
364                 wl_mask |= WL_EVENT_WRITABLE;
365
366         if (wl_event_source_fd_update(fd_source->base.wl_source, wl_mask) < 0) {
367                 TDM_ERR("source update failed: %m");
368                 return TDM_ERROR_OPERATION_FAILED;
369         }
370
371         return TDM_ERROR_NONE;
372 }
373
374 static int
375 _tdm_event_loop_timer_func(void *data)
376 {
377         tdm_event_loop_source_timer *timer_source = (tdm_event_loop_source_timer*)data;
378         tdm_private_display *private_display;
379
380         /* DON'T check TDM_MUTEX_IS_LOCKED here */
381
382         TDM_RETURN_VAL_IF_FAIL(timer_source, 1);
383         TDM_RETURN_VAL_IF_FAIL(timer_source->func, 1);
384
385         private_display = timer_source->private_display;
386
387         _pthread_mutex_lock(&private_display->lock);
388         timer_source->func(timer_source->user_data);
389         _pthread_mutex_unlock(&private_display->lock);
390
391         return 1;
392 }
393
394 EXTERN tdm_event_loop_source *
395 tdm_event_loop_add_timer_handler(tdm_display *dpy, tdm_event_loop_timer_handler func,
396                                                                  void *user_data, tdm_error *error)
397 {
398         tdm_private_display *private_display;
399         tdm_private_loop *private_loop;
400         tdm_event_loop_source_timer *timer_source;
401         tdm_error ret;
402
403         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED, NULL);
404         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(dpy, TDM_ERROR_INVALID_PARAMETER, NULL);
405         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(func, TDM_ERROR_INVALID_PARAMETER, NULL);
406
407         private_display = (tdm_private_display*)dpy;
408         private_loop = private_display->private_loop;
409         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(private_loop, TDM_ERROR_INVALID_PARAMETER, NULL);
410         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(private_loop->wl_loop, TDM_ERROR_INVALID_PARAMETER, NULL);
411
412         timer_source = calloc(1, sizeof(tdm_event_loop_source_timer));
413         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(timer_source, TDM_ERROR_OUT_OF_MEMORY, NULL);
414
415         timer_source->base.wl_source =
416                 wl_event_loop_add_timer(private_loop->wl_loop,
417                                                                 _tdm_event_loop_timer_func, timer_source);
418         if (!timer_source->base.wl_source) {
419                 if (error)
420                         *error = TDM_ERROR_OUT_OF_MEMORY;
421                 free(timer_source);
422                 return NULL;
423         }
424
425         timer_source->private_display = private_display;
426         timer_source->func = func;
427         timer_source->user_data = user_data;
428
429         if (error)
430                 *error = TDM_ERROR_NONE;
431
432         return (tdm_event_loop_source *)timer_source;
433 }
434
435 EXTERN tdm_error
436 tdm_event_loop_source_timer_update(tdm_event_loop_source *source, unsigned int ms_delay)
437 {
438         tdm_event_loop_source_timer *timer_source = source;
439
440         TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED);
441         TDM_RETURN_VAL_IF_FAIL(timer_source, TDM_ERROR_INVALID_PARAMETER);
442
443         if (wl_event_source_timer_update(timer_source->base.wl_source, ms_delay) < 0) {
444                 TDM_ERR("source update failed: %m");
445                 return TDM_ERROR_OPERATION_FAILED;
446         }
447
448         return TDM_ERROR_NONE;
449 }
450
451 EXTERN void
452 tdm_event_loop_source_remove(tdm_event_loop_source *source)
453 {
454         tdm_event_loop_source_base *base = (tdm_event_loop_source_base*)source;
455
456         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
457
458         if (!base)
459                 return;
460
461         wl_event_source_remove(base->wl_source);
462
463         free(source);
464 }