elimiate race condition of capture callback
[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_capture->func_capture
53
54 static void
55 _tdm_caputre_cb_done(tdm_capture *capture_backend, tbm_surface_h buffer, void *user_data)
56 {
57     tdm_private_capture *private_capture = user_data;
58     tdm_private_display *private_display = private_capture->private_display;
59     int lock_after_cb_done = 0;
60
61     if (pthread_mutex_trylock(&private_display->lock))
62     {
63         pthread_mutex_unlock(&private_display->lock);
64         lock_after_cb_done = 1;
65     }
66
67     tdm_buffer_unref_backend(tdm_buffer_get(buffer));
68
69     if (lock_after_cb_done)
70         pthread_mutex_lock(&private_display->lock);
71 }
72
73 INTERN tdm_private_capture*
74 tdm_capture_create_output_internal(tdm_private_output *private_output, tdm_error *error)
75 {
76     tdm_private_display *private_display;
77     tdm_func_display *func_display;
78     tdm_func_capture *func_capture;
79     tdm_private_capture *private_capture = NULL;
80     tdm_capture *capture_backend = NULL;
81     tdm_error ret = TDM_ERROR_NONE;
82
83     private_display = private_output->private_display;
84     func_display = &private_display->func_display;
85     func_capture = &private_display->func_capture;
86
87     if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE))
88     {
89         TDM_ERR("no capture capability");
90         if (error)
91             *error = TDM_ERROR_BAD_REQUEST;
92         return NULL;
93     }
94
95     capture_backend = func_display->output_create_capture(private_output->output_backend, &ret);
96     if (ret != TDM_ERROR_NONE)
97     {
98         if (error)
99             *error = ret;
100         return NULL;
101     }
102
103     private_capture = calloc(1, sizeof(tdm_private_capture));
104     if (!private_capture)
105     {
106         TDM_ERR("failed: alloc memory");
107         func_capture->capture_destroy(capture_backend);
108         if (error)
109             *error = TDM_ERROR_OUT_OF_MEMORY;
110         return NULL;
111     }
112
113     ret = func_capture->capture_set_done_handler(capture_backend, _tdm_caputre_cb_done, private_capture);
114     if (ret != TDM_ERROR_NONE)
115     {
116         TDM_ERR("set capture_done_handler failed");
117         func_capture->capture_destroy(capture_backend);
118         if (error)
119             *error = ret;
120         return NULL;
121     }
122
123     LIST_ADD(&private_capture->link, &private_output->capture_list);
124     private_capture->func_capture = func_capture;
125     private_capture->target = TDM_CAPTURE_TARGET_OUTPUT;
126     private_capture->private_display = private_display;
127     private_capture->private_output = private_output;
128     private_capture->private_layer = NULL;
129     private_capture->capture_backend = capture_backend;
130
131     if (error)
132         *error = TDM_ERROR_NONE;
133
134     return private_capture;
135 }
136
137 INTERN tdm_private_capture*
138 tdm_capture_create_layer_internal(tdm_private_layer *private_layer, tdm_error *error)
139 {
140     tdm_private_display *private_display;
141     tdm_private_output *private_output;
142     tdm_func_display *func_display;
143     tdm_func_capture *func_capture;
144     tdm_private_capture *private_capture = NULL;
145     tdm_capture *capture_backend = NULL;
146     tdm_error ret = TDM_ERROR_NONE;
147
148     private_output = private_layer->private_output;
149     private_display = private_output->private_display;
150     func_display = &private_display->func_display;
151     func_capture = &private_display->func_capture;
152
153     if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE))
154     {
155         TDM_ERR("no capture capability");
156         if (error)
157             *error = TDM_ERROR_BAD_REQUEST;
158         return NULL;
159     }
160
161     capture_backend = func_display->layer_create_capture(private_layer->layer_backend, &ret);
162     if (ret != TDM_ERROR_NONE)
163         return NULL;
164
165     private_capture = calloc(1, sizeof(tdm_private_capture));
166     if (!private_capture)
167     {
168         TDM_ERR("failed: alloc memory");
169         func_capture->capture_destroy(capture_backend);
170         if (error)
171             *error = TDM_ERROR_OUT_OF_MEMORY;
172         return NULL;
173     }
174
175     LIST_ADD(&private_capture->link, &private_output->capture_list);
176     private_capture->target = TDM_CAPTURE_TARGET_LAYER;
177     private_capture->func_capture = func_capture;
178     private_capture->private_display = private_display;
179     private_capture->private_output = private_output;
180     private_capture->private_layer = private_layer;
181     private_capture->capture_backend = capture_backend;
182
183     if (error)
184         *error = TDM_ERROR_NONE;
185
186     return private_capture;
187 }
188
189 INTERN void
190 tdm_capture_destroy_internal(tdm_private_capture *private_capture)
191 {
192     tdm_func_capture *func_capture;
193
194     if (!private_capture)
195         return;
196
197     LIST_DEL(&private_capture->link);
198
199     func_capture = private_capture->func_capture;
200     func_capture->capture_destroy(private_capture->capture_backend);
201
202     free(private_capture);
203 }
204
205 EXTERN void
206 tdm_capture_destroy(tdm_capture *capture)
207 {
208     tdm_private_capture *private_capture = capture;
209     tdm_private_display *private_display;
210
211     if (!private_capture)
212         return;
213
214     private_display = private_capture->private_display;
215
216     pthread_mutex_lock(&private_display->lock);
217     tdm_capture_destroy_internal(private_capture);
218     pthread_mutex_unlock(&private_display->lock);
219 }
220
221 EXTERN tdm_error
222 tdm_capture_set_info(tdm_capture *capture, tdm_info_capture *info)
223 {
224     CAPTURE_FUNC_ENTRY();
225
226     TDM_RETURN_VAL_IF_FAIL(info != NULL, TDM_ERROR_INVALID_PARAMETER);
227
228     pthread_mutex_lock(&private_display->lock);
229
230     if (!func_capture->capture_set_info)
231     {
232         pthread_mutex_unlock(&private_display->lock);
233         return TDM_ERROR_NONE;
234     }
235
236     ret = func_capture->capture_set_info(private_capture->capture_backend, info);
237
238     pthread_mutex_unlock(&private_display->lock);
239
240     return ret;
241 }
242
243 EXTERN tdm_error
244 tdm_capture_attach(tdm_capture *capture, tdm_buffer *buffer)
245 {
246     CAPTURE_FUNC_ENTRY();
247
248     TDM_RETURN_VAL_IF_FAIL(buffer != NULL, TDM_ERROR_INVALID_PARAMETER);
249
250     pthread_mutex_lock(&private_display->lock);
251
252     if (!func_capture->capture_attach)
253     {
254         pthread_mutex_unlock(&private_display->lock);
255         return TDM_ERROR_NONE;
256     }
257
258     tdm_buffer_ref_backend(buffer);
259     ret = func_capture->capture_attach(private_capture->capture_backend,
260                                        tdm_buffer_get_surface(buffer));
261
262     pthread_mutex_unlock(&private_display->lock);
263
264     return ret;
265 }
266
267 EXTERN tdm_error
268 tdm_capture_commit(tdm_capture *capture)
269 {
270     CAPTURE_FUNC_ENTRY();
271
272     pthread_mutex_lock(&private_display->lock);
273
274     if (!func_capture->capture_commit)
275     {
276         pthread_mutex_unlock(&private_display->lock);
277         return TDM_ERROR_NONE;
278     }
279
280     ret = func_capture->capture_commit(private_capture->capture_backend);
281
282     pthread_mutex_unlock(&private_display->lock);
283
284     return ret;
285 }