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