fix deadlock and enhance lock/unlock to protect the backend module's data
[platform/core/uifw/libtdm.git] / src / tdm_pp.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_backend.h"
42 #include "tdm_private.h"
43
44 #define PP_FUNC_ENTRY() \
45     tdm_func_pp *func_pp; \
46     tdm_private_display *private_display; \
47     tdm_private_pp *private_pp; \
48     tdm_error ret = TDM_ERROR_NONE; \
49     TDM_RETURN_VAL_IF_FAIL(pp != NULL, TDM_ERROR_INVALID_PARAMETER); \
50     private_pp = (tdm_private_pp*)pp; \
51     private_display = private_pp->private_display; \
52     func_pp = &private_display->func_pp
53
54 static tdm_error
55 _tdm_pp_check_if_exist(tdm_private_pp *private_pp,
56                        tbm_surface_h src, tbm_surface_h dst)
57 {
58         tdm_buffer_info *buf_info = NULL;
59
60         LIST_FOR_EACH_ENTRY(buf_info, &private_pp->src_buffer_list, link) {
61                 if (buf_info->buffer == src) {
62                         TDM_ERR("%p attached twice", src);
63                         return TDM_ERROR_BAD_REQUEST;
64                 }
65         }
66
67         LIST_FOR_EACH_ENTRY(buf_info, &private_pp->src_pending_buffer_list, link) {
68                 if (buf_info->buffer == src) {
69                         TDM_ERR("%p attached twice", src);
70                         return TDM_ERROR_BAD_REQUEST;
71                 }
72         }
73
74         LIST_FOR_EACH_ENTRY(buf_info, &private_pp->dst_buffer_list, link) {
75                 if (buf_info->buffer == dst) {
76                         TDM_ERR("%p attached twice", dst);
77                         return TDM_ERROR_BAD_REQUEST;
78                 }
79         }
80
81         LIST_FOR_EACH_ENTRY(buf_info, &private_pp->dst_pending_buffer_list, link) {
82                 if (buf_info->buffer == dst) {
83                         TDM_ERR("%p attached twice", dst);
84                         return TDM_ERROR_BAD_REQUEST;
85                 }
86         }
87
88         return TDM_ERROR_NONE;
89 }
90
91 INTERN void
92 tdm_pp_cb_done(tdm_pp *pp_backend, tbm_surface_h src, tbm_surface_h dst,
93                void *user_data)
94 {
95         tdm_private_pp *private_pp = user_data;
96         tdm_private_display *private_display = private_pp->private_display;
97         tdm_buffer_info *buf_info;
98         tbm_surface_h first_entry;
99
100         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
101
102         if (private_pp->owner_tid != syscall(SYS_gettid)) {
103                 tdm_thread_cb_pp_done pp_done;
104                 tdm_error ret;
105
106                 pp_done.base.type = TDM_THREAD_CB_PP_DONE;
107                 pp_done.base.length = sizeof pp_done;
108                 pp_done.pp_stamp = private_pp->stamp;
109                 pp_done.src = src;
110                 pp_done.dst = dst;
111                 pp_done.user_data = user_data;
112
113                 ret = tdm_thread_send_cb(private_display->private_loop, &pp_done.base);
114                 TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
115
116                 return;
117         }
118
119         if (private_pp->owner_tid != syscall(SYS_gettid))
120                 TDM_NEVER_GET_HERE();
121
122         if (tdm_debug_buffer)
123                 TDM_INFO("pp(%p) done: src(%p) dst(%p)", private_pp, src, dst);
124
125         first_entry = tdm_buffer_list_get_first_entry(&private_pp->src_buffer_list);
126         if (first_entry != src)
127                 TDM_ERR("src(%p) is skipped", first_entry);
128
129         first_entry = tdm_buffer_list_get_first_entry(&private_pp->dst_buffer_list);
130         if (first_entry != dst)
131                 TDM_ERR("dst(%p) is skipped", first_entry);
132
133         if ((buf_info = tdm_buffer_get_info(src)))
134                 LIST_DEL(&buf_info->link);
135
136         if ((buf_info = tdm_buffer_get_info(dst)))
137                 LIST_DEL(&buf_info->link);
138
139         _pthread_mutex_unlock(&private_display->lock);
140         tdm_buffer_unref_backend(src);
141         tdm_buffer_unref_backend(dst);
142         _pthread_mutex_lock(&private_display->lock);
143 }
144
145 INTERN tdm_private_pp *
146 tdm_pp_find_stamp(tdm_private_display *private_display, unsigned long stamp)
147 {
148         tdm_private_pp *private_pp = NULL;
149
150         TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), NULL);
151
152         LIST_FOR_EACH_ENTRY(private_pp, &private_display->pp_list, link) {
153                 if (private_pp->stamp == stamp)
154                         return private_pp;
155         }
156
157         return NULL;
158 }
159
160 INTERN tdm_private_pp *
161 tdm_pp_create_internal(tdm_private_display *private_display, tdm_error *error)
162 {
163         tdm_func_display *func_display;
164         tdm_func_pp *func_pp;
165         tdm_private_pp *private_pp = NULL;
166         tdm_pp *pp_backend = NULL;
167         tdm_error ret = TDM_ERROR_NONE;
168
169         TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), NULL);
170
171         func_display = &private_display->func_display;
172         func_pp = &private_display->func_pp;
173
174         if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP)) {
175                 TDM_ERR("no pp capability");
176                 if (error)
177                         *error = TDM_ERROR_NO_CAPABILITY;
178                 return NULL;
179         }
180
181         pp_backend = func_display->display_create_pp(private_display->bdata, &ret);
182         if (ret != TDM_ERROR_NONE) {
183                 if (error)
184                         *error = ret;
185                 return NULL;
186         }
187
188         private_pp = calloc(1, sizeof(tdm_private_pp));
189         if (!private_pp) {
190                 TDM_ERR("failed: alloc memory");
191                 func_pp->pp_destroy(pp_backend);
192                 if (error)
193                         *error = TDM_ERROR_OUT_OF_MEMORY;
194                 return NULL;
195         }
196
197         ret = func_pp->pp_set_done_handler(pp_backend, tdm_pp_cb_done, private_pp);
198         if (ret != TDM_ERROR_NONE) {
199                 TDM_ERR("spp(%p) et pp_done_handler failed", private_pp);
200                 func_pp->pp_destroy(pp_backend);
201                 if (error)
202                         *error = ret;
203                 return NULL;
204         }
205
206         private_pp->stamp = tdm_helper_get_time_in_millis();
207         while (tdm_pp_find_stamp(private_display, private_pp->stamp))
208                 private_pp->stamp++;
209
210         LIST_ADD(&private_pp->link, &private_display->pp_list);
211         private_pp->private_display = private_display;
212         private_pp->pp_backend = pp_backend;
213         private_pp->owner_tid = syscall(SYS_gettid);
214
215         LIST_INITHEAD(&private_pp->src_pending_buffer_list);
216         LIST_INITHEAD(&private_pp->dst_pending_buffer_list);
217         LIST_INITHEAD(&private_pp->src_buffer_list);
218         LIST_INITHEAD(&private_pp->dst_buffer_list);
219
220         if (error)
221                 *error = TDM_ERROR_NONE;
222
223         return private_pp;
224 }
225
226 INTERN void
227 tdm_pp_destroy_internal(tdm_private_pp *private_pp)
228 {
229         tdm_private_display *private_display;
230         tdm_func_pp *func_pp;
231         tdm_buffer_info *b = NULL, *bb = NULL;
232
233         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
234
235         if (!private_pp)
236                 return;
237
238         private_display = private_pp->private_display;
239         func_pp = &private_display->func_pp;
240
241         LIST_DEL(&private_pp->link);
242
243         func_pp->pp_destroy(private_pp->pp_backend);
244
245         if (!LIST_IS_EMPTY(&private_pp->src_pending_buffer_list)) {
246                 TDM_WRN("pp(%p) not finished:", private_pp);
247                 tdm_buffer_list_dump(&private_pp->src_pending_buffer_list);
248
249                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->src_pending_buffer_list, link) {
250                         LIST_DEL(&b->link);
251                         _pthread_mutex_unlock(&private_display->lock);
252                         tdm_buffer_unref_backend(b->buffer);
253                         _pthread_mutex_lock(&private_display->lock);
254                 }
255         }
256
257         if (!LIST_IS_EMPTY(&private_pp->dst_pending_buffer_list)) {
258                 TDM_WRN("pp(%p) not finished:", private_pp);
259                 tdm_buffer_list_dump(&private_pp->dst_pending_buffer_list);
260
261                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->dst_pending_buffer_list, link) {
262                         LIST_DEL(&b->link);
263                         _pthread_mutex_unlock(&private_display->lock);
264                         tdm_buffer_unref_backend(b->buffer);
265                         _pthread_mutex_lock(&private_display->lock);
266                 }
267         }
268
269         if (!LIST_IS_EMPTY(&private_pp->src_buffer_list)) {
270                 TDM_WRN("pp(%p) not finished:", private_pp);
271                 tdm_buffer_list_dump(&private_pp->src_buffer_list);
272
273                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->src_buffer_list, link) {
274                         LIST_DEL(&b->link);
275                         _pthread_mutex_unlock(&private_display->lock);
276                         tdm_buffer_unref_backend(b->buffer);
277                         _pthread_mutex_lock(&private_display->lock);
278                 }
279         }
280
281         if (!LIST_IS_EMPTY(&private_pp->dst_buffer_list)) {
282                 TDM_WRN("pp(%p) not finished:", private_pp);
283                 tdm_buffer_list_dump(&private_pp->dst_buffer_list);
284
285                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->dst_buffer_list, link) {
286                         LIST_DEL(&b->link);
287                         _pthread_mutex_unlock(&private_display->lock);
288                         tdm_buffer_unref_backend(b->buffer);
289                         _pthread_mutex_lock(&private_display->lock);
290                 }
291         }
292
293         private_pp->stamp = 0;
294         free(private_pp);
295 }
296
297 EXTERN void
298 tdm_pp_destroy(tdm_pp *pp)
299 {
300         tdm_private_pp *private_pp = pp;
301         tdm_private_display *private_display;
302
303         if (!private_pp)
304                 return;
305
306         private_display = private_pp->private_display;
307
308         _pthread_mutex_lock(&private_display->lock);
309         tdm_pp_destroy_internal(private_pp);
310         _pthread_mutex_unlock(&private_display->lock);
311 }
312
313 EXTERN tdm_error
314 tdm_pp_set_info(tdm_pp *pp, tdm_info_pp *info)
315 {
316         PP_FUNC_ENTRY();
317
318         TDM_RETURN_VAL_IF_FAIL(info != NULL, TDM_ERROR_INVALID_PARAMETER);
319
320         _pthread_mutex_lock(&private_display->lock);
321
322         if (!func_pp->pp_set_info) {
323                 _pthread_mutex_unlock(&private_display->lock);
324                 TDM_DBG("failed: not implemented!!");
325                 return TDM_ERROR_NOT_IMPLEMENTED;
326         }
327
328         TDM_INFO("pp(%p) info: src(%dx%d %d,%d %dx%d %c%c%c%c) dst(%dx%d %d,%d %dx%d %c%c%c%c) trans(%d) sync(%d) flags(%x)",
329                  private_pp, info->src_config.size.h, info->src_config.size.v,
330                  info->src_config.pos.x, info->src_config.pos.y,
331                  info->src_config.pos.w, info->src_config.pos.h,
332                  FOURCC_STR(info->src_config.format),
333                  info->dst_config.size.h, info->dst_config.size.v,
334                  info->dst_config.pos.x, info->dst_config.pos.y,
335                  info->dst_config.pos.w, info->dst_config.pos.h,
336                  FOURCC_STR(info->dst_config.format),
337                  info->transform, info->sync, info->flags);
338
339         ret = func_pp->pp_set_info(private_pp->pp_backend, info);
340         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
341
342         _pthread_mutex_unlock(&private_display->lock);
343
344         return ret;
345 }
346
347 EXTERN tdm_error
348 tdm_pp_attach(tdm_pp *pp, tbm_surface_h src, tbm_surface_h dst)
349 {
350         PP_FUNC_ENTRY();
351
352         TDM_RETURN_VAL_IF_FAIL(src != NULL, TDM_ERROR_INVALID_PARAMETER);
353         TDM_RETURN_VAL_IF_FAIL(dst != NULL, TDM_ERROR_INVALID_PARAMETER);
354
355         _pthread_mutex_lock(&private_display->lock);
356
357         if (!func_pp->pp_attach) {
358                 _pthread_mutex_unlock(&private_display->lock);
359                 TDM_DBG("failed: not implemented!!");
360                 return TDM_ERROR_NOT_IMPLEMENTED;
361         }
362
363         ret = _tdm_pp_check_if_exist(private_pp, src, dst);
364         if (ret != TDM_ERROR_NONE) {
365                 _pthread_mutex_unlock(&private_display->lock);
366                 return ret;
367         }
368
369         ret = func_pp->pp_attach(private_pp->pp_backend, src, dst);
370         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
371
372         if (ret == TDM_ERROR_NONE) {
373                 tdm_buffer_info *buf_info;
374
375                 if ((buf_info = tdm_buffer_get_info(src)))
376                         LIST_ADDTAIL(&buf_info->link, &private_pp->src_pending_buffer_list);
377
378                 if ((buf_info = tdm_buffer_get_info(dst)))
379                         LIST_ADDTAIL(&buf_info->link, &private_pp->dst_pending_buffer_list);
380
381                 if (tdm_debug_buffer) {
382                         TDM_INFO("pp(%p) attached:", private_pp);
383                         tdm_buffer_list_dump(&private_pp->src_pending_buffer_list);
384                         tdm_buffer_list_dump(&private_pp->dst_pending_buffer_list);
385                 }
386         }
387
388         _pthread_mutex_unlock(&private_display->lock);
389
390         return ret;
391 }
392
393 EXTERN tdm_error
394 tdm_pp_commit(tdm_pp *pp)
395 {
396         tdm_buffer_info *b = NULL, *bb = NULL;
397
398         PP_FUNC_ENTRY();
399
400         _pthread_mutex_lock(&private_display->lock);
401
402         if (!func_pp->pp_commit) {
403                 _pthread_mutex_unlock(&private_display->lock);
404                 TDM_DBG("failed: not implemented!!");
405                 return TDM_ERROR_NOT_IMPLEMENTED;
406         }
407
408         ret = func_pp->pp_commit(private_pp->pp_backend);
409         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
410
411         if (ret == TDM_ERROR_NONE) {
412                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->src_pending_buffer_list, link) {
413                         LIST_DEL(&b->link);
414                         tdm_buffer_ref_backend(b->buffer);
415                         LIST_ADDTAIL(&b->link, &private_pp->src_buffer_list);
416                 }
417
418                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->dst_pending_buffer_list, link) {
419                         LIST_DEL(&b->link);
420                         tdm_buffer_ref_backend(b->buffer);
421                         LIST_ADDTAIL(&b->link, &private_pp->dst_buffer_list);
422                 }
423         } else {
424                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->src_pending_buffer_list, link)
425                         LIST_DEL(&b->link);
426                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->dst_pending_buffer_list, link)
427                         LIST_DEL(&b->link);
428         }
429
430         _pthread_mutex_unlock(&private_display->lock);
431
432         return ret;
433 }