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