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