rename test tools and enhance logs
[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 static int tdm_debug_server;
62
63 static void
64 _tdm_server_cb_output_vblank(tdm_output *output, unsigned int sequence,
65                              unsigned int tv_sec, unsigned int tv_usec,
66                              void *user_data)
67 {
68         tdm_server_vblank_info *vblank_info = (tdm_server_vblank_info*)user_data;
69         tdm_server_vblank_info *found;
70
71         if (!keep_private_server)
72                 return;
73
74         LIST_FIND_ITEM(vblank_info, &keep_private_server->vblank_list,
75                        tdm_server_vblank_info, link, found);
76         if (!found) {
77                 TDM_DBG("vblank_info(%p) is destroyed", vblank_info);
78                 return;
79         }
80
81         if (tdm_debug_server) {
82                 unsigned long curr = tdm_helper_get_time_in_micros();
83                 unsigned long vtime = (tv_sec * 1000000) + tv_usec;
84                 if (curr - vtime > 1000) /* 1ms */
85                         TDM_WRN("delay: %d us", (int)(curr - vtime));
86         }
87
88         TDM_DBG("wl_tdm_vblank@%d done", wl_resource_get_id(vblank_info->resource));
89
90         wl_tdm_vblank_send_done(vblank_info->resource, sequence, tv_sec, tv_usec);
91         wl_resource_destroy(vblank_info->resource);
92 }
93
94 static void
95 destroy_vblank_callback(struct wl_resource *resource)
96 {
97         tdm_server_vblank_info *vblank_info = wl_resource_get_user_data(resource);
98         LIST_DEL(&vblank_info->link);
99         free(vblank_info);
100 }
101
102 static void
103 _tdm_server_cb_wait_vblank(struct wl_client *client,
104                            struct wl_resource *resource,
105                            uint32_t id, const char *name, int32_t interval,
106                            uint32_t req_sec, uint32_t req_usec)
107 {
108         tdm_private_loop *private_loop = wl_resource_get_user_data(resource);
109         tdm_private_server *private_server = private_loop->private_server;
110         tdm_server_vblank_info *vblank_info;
111         struct wl_resource *vblank_resource;
112         tdm_output *found = NULL;
113         int count = 0, i;
114         tdm_error ret;
115
116         TDM_DBG("The tdm client requests vblank");
117
118         tdm_display_get_output_count(private_loop->dpy, &count);
119
120         for (i = 0; i < count; i++) {
121                 tdm_output *output= tdm_display_get_output(private_loop->dpy, i, NULL);
122                 tdm_output_conn_status status;
123                 const char *model = NULL;
124
125                 ret = tdm_output_get_conn_status(output, &status);
126                 if (ret || status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED)
127                         continue;
128
129                 ret = tdm_output_get_model_info(output, NULL, &model, NULL);
130                 if (ret || !model)
131                         continue;
132
133                 if (strncmp(model, name, TDM_NAME_LEN))
134                         continue;
135
136                 found = output;
137                 break;
138         }
139
140         if (!found) {
141                 wl_resource_post_error(resource, WL_TDM_ERROR_INVALID_NAME,
142                                        "There is no '%s' output", name);
143                 TDM_ERR("There is no '%s' output", name);
144                 return;
145         }
146
147         vblank_resource =
148                 wl_resource_create(client, &wl_tdm_vblank_interface,
149                                    wl_resource_get_version(resource), id);
150         if (!vblank_resource) {
151                 wl_resource_post_no_memory(resource);
152                 TDM_ERR("wl_resource_create failed");
153                 return;
154         }
155
156         vblank_info = calloc(1, sizeof *vblank_info);
157         if (!vblank_info) {
158                 wl_resource_destroy(vblank_resource);
159                 wl_resource_post_no_memory(resource);
160                 TDM_ERR("alloc failed");
161                 return;
162         }
163
164         TDM_DBG("wl_tdm_vblank@%d output(%s) interval(%d)", id, name, interval);
165
166         ret = tdm_output_wait_vblank(found, interval, 0,
167                                      _tdm_server_cb_output_vblank, vblank_info);
168         if (ret != TDM_ERROR_NONE) {
169                 wl_resource_destroy(vblank_resource);
170                 free(vblank_info);
171                 wl_resource_post_error(resource, WL_TDM_ERROR_OPERATION_FAILED,
172                                        "couldn't wait vblank for %s", name);
173                 TDM_ERR("couldn't wait vblank for %s", name);
174                 return;
175         }
176
177         if (tdm_debug_server) {
178                 unsigned long curr = tdm_helper_get_time_in_micros();
179                 unsigned long reqtime = (req_sec * 1000000) + req_usec;
180                 if (curr - reqtime > 1000) /* 1ms */
181                         TDM_WRN("delay(req): %d us", (int)(curr - reqtime));
182         }
183
184         vblank_info->resource = vblank_resource;
185         vblank_info->private_server = private_server;
186
187         wl_resource_set_implementation(vblank_resource, NULL, vblank_info,
188                                        destroy_vblank_callback);
189
190         LIST_ADDTAIL(&vblank_info->link, &private_server->vblank_list);
191 }
192
193 static const struct wl_tdm_interface tdm_implementation = {
194         _tdm_server_cb_wait_vblank,
195 };
196
197 static void
198 _tdm_server_bind(struct wl_client *client, void *data,
199                  uint32_t version, uint32_t id)
200 {
201         struct wl_resource *resource;
202
203         resource = wl_resource_create(client, &wl_tdm_interface, version, id);
204         if (!resource) {
205                 wl_client_post_no_memory(client);
206                 return;
207         }
208
209         TDM_DBG("tdm server binding");
210
211         wl_resource_set_implementation(resource, &tdm_implementation, data, NULL);
212 }
213
214 INTERN tdm_error
215 tdm_server_init(tdm_private_loop *private_loop)
216 {
217         tdm_private_server *private_server;
218         const char *debug;
219
220         debug = getenv("TDM_DEBUG_SERVER");
221         if (debug && (strstr(debug, "1")))
222                 tdm_debug_server = 1;
223
224         if (private_loop->private_server)
225                 return TDM_ERROR_NONE;
226
227         TDM_RETURN_VAL_IF_FAIL(private_loop, TDM_ERROR_OPERATION_FAILED);
228         TDM_RETURN_VAL_IF_FAIL(private_loop->wl_display, TDM_ERROR_OPERATION_FAILED);
229
230         if(wl_display_add_socket(private_loop->wl_display, "tdm-socket")) {
231                 TDM_ERR("createing a tdm-socket failed");
232                 return TDM_ERROR_OPERATION_FAILED;
233         }
234
235         private_server = calloc(1, sizeof *private_server);
236         if (!private_server) {
237                 TDM_ERR("alloc failed");
238                 return TDM_ERROR_OUT_OF_MEMORY;
239         }
240
241         LIST_INITHEAD(&private_server->vblank_list);
242
243         if (!wl_global_create(private_loop->wl_display, &wl_tdm_interface, 1,
244                               private_loop, _tdm_server_bind)) {
245                 TDM_ERR("creating a global resource failed");
246                 free(private_server);
247                 return TDM_ERROR_OUT_OF_MEMORY;
248         }
249
250         private_loop->private_server = private_server;
251         keep_private_server = private_server;
252
253         return TDM_ERROR_NONE;
254 }
255
256 INTERN void
257 tdm_server_deinit(tdm_private_loop *private_loop)
258 {
259         tdm_server_vblank_info *v = NULL, *vv = NULL;
260         tdm_private_server *private_server;
261
262         if (!private_loop->private_server)
263                 return;
264
265         private_server = private_loop->private_server;
266
267         LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_server->vblank_list, link) {
268                 wl_resource_destroy(v->resource);
269         }
270
271         free(private_server);
272         private_loop->private_server = NULL;
273         keep_private_server = NULL;
274 }