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