fix deadlock and enhance lock/unlock to protect the backend module's data
[platform/core/uifw/libtdm.git] / src / tdm_server.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 #include "tdm-server-protocol.h"
44
45 /* CAUTION:
46  * - tdm server doesn't care about thread things.
47  * - DO NOT use the TDM internal functions here.
48  */
49
50 struct _tdm_private_server {
51         struct list_head vblank_list;
52 };
53
54 typedef struct _tdm_server_vblank_info {
55         struct list_head link;
56         struct wl_resource *resource;
57         tdm_private_server *private_server;
58 } tdm_server_vblank_info;
59
60 static tdm_private_server *keep_private_server;
61
62 static void
63 _tdm_server_cb_output_vblank(tdm_output *output, unsigned int sequence,
64                              unsigned int tv_sec, unsigned int tv_usec,
65                              void *user_data)
66 {
67         tdm_server_vblank_info *vblank_info = (tdm_server_vblank_info*)user_data;
68         tdm_server_vblank_info *found;
69
70         if (!keep_private_server)
71                 return;
72
73         LIST_FIND_ITEM(vblank_info, &keep_private_server->vblank_list,
74                        tdm_server_vblank_info, link, found);
75         if (!found) {
76                 TDM_DBG("vblank_info(%p) is destroyed", vblank_info);
77                 return;
78         }
79
80         TDM_DBG("wl_tdm_vblank@%d done", wl_resource_get_id(vblank_info->resource));
81
82         wl_tdm_vblank_send_done(vblank_info->resource, sequence, tv_sec, tv_usec);
83         wl_resource_destroy(vblank_info->resource);
84 }
85
86 static void
87 destroy_vblank_callback(struct wl_resource *resource)
88 {
89         tdm_server_vblank_info *vblank_info = wl_resource_get_user_data(resource);
90         LIST_DEL(&vblank_info->link);
91         free(vblank_info);
92 }
93
94 static void
95 _tdm_server_cb_wait_vblank(struct wl_client *client,
96                            struct wl_resource *resource,
97                            uint32_t id, const char *name, int32_t interval)
98 {
99         tdm_private_loop *private_loop = wl_resource_get_user_data(resource);
100         tdm_private_server *private_server = private_loop->private_server;
101         tdm_server_vblank_info *vblank_info;
102         struct wl_resource *vblank_resource;
103         tdm_output *found = NULL;
104         int count = 0, i;
105         tdm_error ret;
106
107         TDM_DBG("The tdm client requests vblank");
108
109         tdm_display_get_output_count(private_loop->dpy, &count);
110
111         for (i = 0; i < count; i++) {
112                 tdm_output *output= tdm_display_get_output(private_loop->dpy, i, NULL);
113                 tdm_output_conn_status status;
114                 const char *model = NULL;
115
116                 ret = tdm_output_get_conn_status(output, &status);
117                 if (ret || status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED)
118                         continue;
119
120                 ret = tdm_output_get_model_info(output, NULL, &model, NULL);
121                 if (ret || !model)
122                         continue;
123
124                 if (strncmp(model, name, TDM_NAME_LEN))
125                         continue;
126
127                 found = output;
128                 break;
129         }
130
131         if (!found) {
132                 wl_resource_post_error(resource, WL_TDM_ERROR_INVALID_NAME,
133                                        "There is no '%s' output", name);
134                 TDM_ERR("There is no '%s' output", name);
135                 return;
136         }
137
138         vblank_resource =
139                 wl_resource_create(client, &wl_tdm_vblank_interface,
140                                    wl_resource_get_version(resource), id);
141         if (!vblank_resource) {
142                 wl_resource_post_no_memory(resource);
143                 TDM_ERR("wl_resource_create failed");
144                 return;
145         }
146
147         vblank_info = calloc(1, sizeof *vblank_info);
148         if (!vblank_info) {
149                 wl_resource_destroy(vblank_resource);
150                 wl_resource_post_no_memory(resource);
151                 TDM_ERR("alloc failed");
152                 return;
153         }
154
155         TDM_DBG("wl_tdm_vblank@%d output(%s) interval(%d)", id, name, interval);
156
157         ret = tdm_output_wait_vblank(found, interval, 0,
158                                      _tdm_server_cb_output_vblank, vblank_info);
159         if (ret != TDM_ERROR_NONE) {
160                 wl_resource_destroy(vblank_resource);
161                 free(vblank_info);
162                 wl_resource_post_error(resource, WL_TDM_ERROR_OPERATION_FAILED,
163                                        "couldn't wait vblank for %s", name);
164                 TDM_ERR("couldn't wait vblank for %s", name);
165                 return;
166         }
167
168         vblank_info->resource = vblank_resource;
169         vblank_info->private_server = private_server;
170
171         wl_resource_set_implementation(vblank_resource, NULL, vblank_info,
172                                        destroy_vblank_callback);
173
174         LIST_ADDTAIL(&vblank_info->link, &private_server->vblank_list);
175 }
176
177 static const struct wl_tdm_interface tdm_implementation = {
178         _tdm_server_cb_wait_vblank,
179 };
180
181 static void
182 _tdm_server_bind(struct wl_client *client, void *data,
183                  uint32_t version, uint32_t id)
184 {
185         struct wl_resource *resource;
186
187         resource = wl_resource_create(client, &wl_tdm_interface, version, id);
188         if (!resource) {
189                 wl_client_post_no_memory(client);
190                 return;
191         }
192
193         TDM_DBG("tdm server binding");
194
195         wl_resource_set_implementation(resource, &tdm_implementation, data, NULL);
196 }
197
198 INTERN tdm_error
199 tdm_server_init(tdm_private_loop *private_loop)
200 {
201         tdm_private_server *private_server;
202
203         if (private_loop->private_server)
204                 return TDM_ERROR_NONE;
205
206         TDM_RETURN_VAL_IF_FAIL(private_loop, TDM_ERROR_OPERATION_FAILED);
207         TDM_RETURN_VAL_IF_FAIL(private_loop->wl_display, TDM_ERROR_OPERATION_FAILED);
208
209         if(wl_display_add_socket(private_loop->wl_display, "tdm-socket")) {
210                 TDM_ERR("createing a tdm-socket failed");
211                 return TDM_ERROR_OPERATION_FAILED;
212         }
213
214         private_server = calloc(1, sizeof *private_server);
215         if (!private_server) {
216                 TDM_ERR("alloc failed");
217                 return TDM_ERROR_OUT_OF_MEMORY;
218         }
219
220         LIST_INITHEAD(&private_server->vblank_list);
221
222         if (!wl_global_create(private_loop->wl_display, &wl_tdm_interface, 1,
223                               private_loop, _tdm_server_bind)) {
224                 TDM_ERR("creating a global resource failed");
225                 free(private_server);
226                 return TDM_ERROR_OUT_OF_MEMORY;
227         }
228
229         private_loop->private_server = private_server;
230         keep_private_server = private_server;
231
232         return TDM_ERROR_NONE;
233 }
234
235 INTERN void
236 tdm_server_deinit(tdm_private_loop *private_loop)
237 {
238         tdm_server_vblank_info *v = NULL, *vv = NULL;
239         tdm_private_server *private_server;
240
241         if (!private_loop->private_server)
242                 return;
243
244         private_server = private_loop->private_server;
245
246         LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_server->vblank_list, link) {
247                 wl_resource_destroy(v->resource);
248         }
249
250         free(private_server);
251         private_loop->private_server = NULL;
252         keep_private_server = NULL;
253 }