enhance log
[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         /* Don't set timeout to -1. It can make deadblock by two mutex locks.
234          * If need to set -1, use poll() and call tdm_event_loop_dispatch() after
235          * escaping polling.
236          */
237         if (wl_event_loop_dispatch(private_loop->wl_loop, 0) < 0)
238                 TDM_ERR("dispatch failed");
239
240         return TDM_ERROR_NONE;
241 }
242
243
244 INTERN void
245 tdm_event_loop_flush(tdm_private_display *private_display)
246 {
247         tdm_private_loop *private_loop = private_display->private_loop;
248
249         /* DON'T check TDM_MUTEX_IS_LOCKED here */
250
251         TDM_RETURN_IF_FAIL(private_loop->wl_display != NULL);
252
253         wl_display_flush_clients(private_loop->wl_display);
254 }
255
256 static int
257 _tdm_event_loop_fd_func(int fd, uint32_t wl_mask, void *data)
258 {
259         tdm_event_loop_source_fd *fd_source = (tdm_event_loop_source_fd*)data;
260         tdm_private_display *private_display;
261         tdm_event_loop_mask mask = 0;
262
263         /* DON'T check TDM_MUTEX_IS_LOCKED here */
264
265         TDM_RETURN_VAL_IF_FAIL(fd_source, 1);
266         TDM_RETURN_VAL_IF_FAIL(fd_source->func, 1);
267
268         private_display = fd_source->private_display;
269
270         if (wl_mask & WL_EVENT_READABLE)
271                 mask |= TDM_EVENT_LOOP_READABLE;
272         if (wl_mask & WL_EVENT_WRITABLE)
273                 mask |= TDM_EVENT_LOOP_WRITABLE;
274         if (wl_mask & WL_EVENT_HANGUP)
275                 mask |= TDM_EVENT_LOOP_HANGUP;
276         if (wl_mask & WL_EVENT_ERROR)
277                 mask |= TDM_EVENT_LOOP_ERROR;
278
279         _pthread_mutex_lock(&private_display->lock);
280         fd_source->func(fd, mask, fd_source->user_data);
281         _pthread_mutex_unlock(&private_display->lock);
282
283         return 1;
284 }
285
286 EXTERN tdm_event_loop_source*
287 tdm_event_loop_add_fd_handler(tdm_display *dpy, int fd, tdm_event_loop_mask mask,
288                               tdm_event_loop_fd_handler func, void *user_data,
289                               tdm_error *error)
290 {
291         tdm_private_display *private_display;
292         tdm_private_loop *private_loop;
293         tdm_event_loop_source_fd *fd_source;
294         uint32_t wl_mask = 0;
295         tdm_error ret;
296
297         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED, NULL);
298         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(dpy, TDM_ERROR_INVALID_PARAMETER, NULL);
299         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(fd >= 0, TDM_ERROR_INVALID_PARAMETER, NULL);
300         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(func, TDM_ERROR_INVALID_PARAMETER, NULL);
301
302         private_display = (tdm_private_display*)dpy;
303         private_loop = private_display->private_loop;
304         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(private_loop, TDM_ERROR_INVALID_PARAMETER, NULL);
305         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(private_loop->wl_loop, TDM_ERROR_INVALID_PARAMETER, NULL);
306
307         fd_source = calloc(1, sizeof(tdm_event_loop_source_fd));
308         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(fd_source, TDM_ERROR_OUT_OF_MEMORY, NULL);
309
310         if (mask & TDM_EVENT_LOOP_READABLE)
311                 wl_mask |= WL_EVENT_READABLE;
312         if (mask & TDM_EVENT_LOOP_WRITABLE)
313                 wl_mask |= WL_EVENT_WRITABLE;
314
315         fd_source->base.wl_source =
316                 wl_event_loop_add_fd(private_loop->wl_loop,
317                                      fd, wl_mask, _tdm_event_loop_fd_func, fd_source);
318         if (!fd_source->base.wl_source) {
319                 if (error)
320                         *error = TDM_ERROR_OUT_OF_MEMORY;
321                 free(fd_source);
322                 return NULL;
323         }
324
325         fd_source->private_display = private_display;
326         fd_source->func = func;
327         fd_source->user_data = user_data;
328
329         if (error)
330                 *error = TDM_ERROR_NONE;
331
332         return (tdm_event_loop_source*)fd_source;
333 }
334
335 EXTERN tdm_error
336 tdm_event_loop_source_fd_update(tdm_event_loop_source *source, tdm_event_loop_mask mask)
337 {
338         tdm_event_loop_source_fd *fd_source = source;
339         uint32_t wl_mask = 0;
340
341         TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED);
342         TDM_RETURN_VAL_IF_FAIL(fd_source, TDM_ERROR_INVALID_PARAMETER);
343
344         if (mask & TDM_EVENT_LOOP_READABLE)
345                 wl_mask |= WL_EVENT_READABLE;
346         if (mask & TDM_EVENT_LOOP_WRITABLE)
347                 wl_mask |= WL_EVENT_WRITABLE;
348
349         if (wl_event_source_fd_update(fd_source->base.wl_source, wl_mask) < 0) {
350                 TDM_ERR("source update failed: %m");
351                 return TDM_ERROR_OPERATION_FAILED;
352         }
353
354         return TDM_ERROR_NONE;
355 }
356
357 static int
358 _tdm_event_loop_timer_func(void *data)
359 {
360         tdm_event_loop_source_timer *timer_source = (tdm_event_loop_source_timer*)data;
361         tdm_private_display *private_display;
362
363         /* DON'T check TDM_MUTEX_IS_LOCKED here */
364
365         TDM_RETURN_VAL_IF_FAIL(timer_source, 1);
366         TDM_RETURN_VAL_IF_FAIL(timer_source->func, 1);
367
368         private_display = timer_source->private_display;
369
370         _pthread_mutex_lock(&private_display->lock);
371         timer_source->func(timer_source->user_data);
372         _pthread_mutex_unlock(&private_display->lock);
373
374         return 1;
375 }
376
377 EXTERN tdm_event_loop_source*
378 tdm_event_loop_add_timer_handler(tdm_display *dpy, tdm_event_loop_timer_handler func,
379                                  void *user_data, tdm_error *error)
380 {
381         tdm_private_display *private_display;
382         tdm_private_loop *private_loop;
383         tdm_event_loop_source_timer *timer_source;
384         tdm_error ret;
385
386         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED, NULL);
387         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(dpy, TDM_ERROR_INVALID_PARAMETER, NULL);
388         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(func, TDM_ERROR_INVALID_PARAMETER, NULL);
389
390         private_display = (tdm_private_display*)dpy;
391         private_loop = private_display->private_loop;
392         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(private_loop, TDM_ERROR_INVALID_PARAMETER, NULL);
393         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(private_loop->wl_loop, TDM_ERROR_INVALID_PARAMETER, NULL);
394
395         timer_source = calloc(1, sizeof(tdm_event_loop_source_timer));
396         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(timer_source, TDM_ERROR_OUT_OF_MEMORY, NULL);
397
398         timer_source->base.wl_source =
399                 wl_event_loop_add_timer(private_loop->wl_loop,
400                                         _tdm_event_loop_timer_func, timer_source);
401         if (!timer_source->base.wl_source) {
402                 if (error)
403                         *error = TDM_ERROR_OUT_OF_MEMORY;
404                 free(timer_source);
405                 return NULL;
406         }
407
408         timer_source->private_display = private_display;
409         timer_source->func = func;
410         timer_source->user_data = user_data;
411
412         if (error)
413                 *error = TDM_ERROR_NONE;
414
415         return (tdm_event_loop_source*)timer_source;
416 }
417
418 EXTERN tdm_error
419 tdm_event_loop_source_timer_update(tdm_event_loop_source *source, int ms_delay)
420 {
421         tdm_event_loop_source_timer *timer_source = source;
422
423         TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED);
424         TDM_RETURN_VAL_IF_FAIL(timer_source, TDM_ERROR_INVALID_PARAMETER);
425
426         if (wl_event_source_timer_update(timer_source->base.wl_source, ms_delay) < 0) {
427                 TDM_ERR("source update failed: %m");
428                 return TDM_ERROR_OPERATION_FAILED;
429         }
430
431         return TDM_ERROR_NONE;
432 }
433
434 EXTERN void
435 tdm_event_loop_source_remove(tdm_event_loop_source *source)
436 {
437         tdm_event_loop_source_base *base = (tdm_event_loop_source_base*)source;
438
439         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
440
441         if (!base)
442                 return;
443
444         wl_event_source_remove(base->wl_source);
445
446         free(source);
447 }