69d318db38985e20e5c0c45a2b86868cb3922d49
[platform/core/uifw/libtbm.git] / src / tbm_bo.c
1 /**************************************************************************
2
3 libtbm
4
5 Copyright 2012 Samsung Electronics co., Ltd. All Rights Reserved.
6
7 Contact: SooChan Lim <sc1.lim@samsung.com>, Sangjin Lee <lsj119@samsung.com>
8 Boram Park <boram1288.park@samsung.com>, Changyeon Lee <cyeon.lee@samsung.com>
9
10 Permission is hereby granted, free of charge, to any person obtaining a
11 copy of this software and associated documentation files (the
12 "Software"), to deal in the Software without restriction, including
13 without limitation the rights to use, copy, modify, merge, publish,
14 distribute, sub license, and/or sell copies of the Software, and to
15 permit persons to whom the Software is furnished to do so, subject to
16 the following conditions:
17
18 The above copyright notice and this permission notice (including the
19 next paragraph) shall be included in all copies or substantial portions
20 of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
25 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
26 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
27 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
28 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
30 **************************************************************************/
31
32 #include "config.h"
33 #include "tbm_bufmgr.h"
34 #include "tbm_bufmgr_int.h"
35 #include "list.h"
36
37 static pthread_mutex_t tbm_bo_lock = PTHREAD_MUTEX_INITIALIZER;
38 static __thread tbm_error_e tbm_last_error = TBM_ERROR_NONE;
39 static void _tbm_bo_mutex_unlock(void);
40
41 /* check condition */
42 #define TBM_BO_RETURN_IF_FAIL(cond) {\
43         if (!(cond)) {\
44                 TBM_ERR("'%s' failed.\n", #cond);\
45                 _tbm_bo_mutex_unlock();\
46                 return;\
47         } \
48 }
49
50 #define TBM_BO_RETURN_VAL_IF_FAIL(cond, val) {\
51         if (!(cond)) {\
52                 TBM_ERR("'%s' failed.\n", #cond);\
53                 _tbm_bo_mutex_unlock();\
54                 return val;\
55         } \
56 }
57
58 static void
59 _tbm_set_last_result(tbm_error_e err)
60 {
61         tbm_last_error = err;
62 }
63
64 /* LCOV_EXCL_START */
65 static bool
66 _tbm_bo_mutex_init(void)
67 {
68         static bool tbm_bo_mutex_init = false;
69
70         if (tbm_bo_mutex_init)
71                 return true;
72
73         if (pthread_mutex_init(&tbm_bo_lock, NULL)) {
74                 TBM_ERR("fail: Cannot pthread_mutex_init for tbm_bo_lock.\n");
75                 return false;
76         }
77
78         tbm_bo_mutex_init = true;
79
80         return true;
81 }
82
83 static void
84 _tbm_bo_mutex_lock(void)
85 {
86         if (!_tbm_bo_mutex_init()) {
87                 TBM_ERR("fail: _tbm_bo_mutex_init()\n");
88                 return;
89         }
90
91         pthread_mutex_lock(&tbm_bo_lock);
92 }
93
94 static void
95 _tbm_bo_mutex_unlock(void)
96 {
97         pthread_mutex_unlock(&tbm_bo_lock);
98 }
99
100 static char *
101 _tbm_flag_to_str(int f)
102 {
103         static char str[255];
104
105         if (f == TBM_BO_DEFAULT)
106                  snprintf(str, 255, "DEFAULT");
107         else {
108                 int c = 0;
109
110                 if (f & TBM_BO_SCANOUT)
111                         c += snprintf(&str[c], 255-c, "SCANOUT");
112
113                 if (f & TBM_BO_NONCACHABLE) {
114                         if (c >= 0 && c < 255)
115                                 c += snprintf(&str[c], 255-c, ", ");
116
117                         if (c >= 0 && c < 255)
118                                 c += snprintf(&str[c], 255-c, "NONCACHABLE,");
119                 }
120
121                 if (f & TBM_BO_WC) {
122                         if (c >= 0 && c < 255)
123                                 c += snprintf(&str[c], 255-c, ", ");
124
125                         if (c >= 0 && c < 255)
126                                 c += snprintf(&str[c], 255-c, "WC");
127                 }
128         }
129
130         return str;
131 }
132
133 static void
134 _tbm_util_check_bo_cnt(tbm_bufmgr bufmgr)
135 {
136         static int last_chk_bo_cnt = 0;
137
138         if ((bufmgr->bo_cnt >= 500) && ((bufmgr->bo_cnt % 20) == 0) &&
139                 (bufmgr->bo_cnt > last_chk_bo_cnt)) {
140                 TBM_DBG("============TBM BO CNT DEBUG: bo_cnt=%d\n", bufmgr->bo_cnt);
141                 tbm_bufmgr_debug_show(bufmgr);
142                 last_chk_bo_cnt = bufmgr->bo_cnt;
143         }
144 }
145 /* LCOV_EXCL_STOP */
146
147 tbm_user_data
148 *user_data_lookup(struct list_head *user_data_list, unsigned long key)
149 {
150         tbm_user_data *old_data = NULL;
151
152         if (LIST_IS_EMPTY(user_data_list))
153                 return NULL;
154
155         LIST_FOR_EACH_ENTRY(old_data, user_data_list, item_link) {
156                 if (old_data->key == key)
157                         return old_data;
158         }
159
160         return NULL;
161 }
162
163 tbm_user_data
164 *user_data_create(unsigned long key, tbm_data_free data_free_func)
165 {
166         tbm_user_data *user_data;
167
168         user_data = calloc(1, sizeof(tbm_user_data));
169         if (!user_data) {
170                 /* LCOV_EXCL_START */
171                 TBM_ERR("fail to allocate an user_date\n");
172                 return NULL;
173                 /* LCOV_EXCL_STOP */
174         }
175
176         user_data->key = key;
177         user_data->free_func = data_free_func;
178
179         return user_data;
180 }
181
182 void
183 user_data_delete(tbm_user_data *user_data)
184 {
185         if (user_data->data && user_data->free_func)
186                 user_data->free_func(user_data->data);
187
188         LIST_DEL(&user_data->item_link);
189
190         free(user_data);
191 }
192
193 static int
194 _bo_lock(tbm_bo bo, int device, int opt)
195 {
196         int ret = 1;
197         tbm_error_e error;
198
199         if (bo->bufmgr->backend_module_data) {
200                 if (bo->bufmgr->bo_func->bo_lock) {
201                         error = bo->bufmgr->bo_func->bo_lock(bo->bo_data, device, opt);
202                         if (error != TBM_ERROR_NONE) {
203                                 TBM_WRN("fail to lock");
204                                 ret = 0;
205                         }
206                 }
207         } else {
208                 if (bo->bufmgr->backend->bo_lock)
209                         ret = bo->bufmgr->backend->bo_lock(bo, device, opt);
210         }
211
212         return ret;
213 }
214
215 static void
216 _bo_unlock(tbm_bo bo)
217 {
218         tbm_error_e error;
219
220         if (bo->bufmgr->backend_module_data) {
221                 if (bo->bufmgr->bo_func->bo_unlock) {
222                         error = bo->bufmgr->bo_func->bo_unlock(bo->bo_data);
223                         if (error != TBM_ERROR_NONE)
224                                 TBM_WRN("fail to unlock");
225                 }
226         } else {
227                 if (bo->bufmgr->backend->bo_unlock)
228                         bo->bufmgr->backend->bo_unlock(bo);
229         }
230 }
231
232 static int
233 _tbm_bo_lock(tbm_bo bo, int device, int opt)
234 {
235         int old, ret;
236
237         if (!bo)
238                 return 0;
239
240         /* do not try to lock the bo */
241         if (bo->bufmgr->bo_lock_type == TBM_BUFMGR_BO_LOCK_TYPE_NEVER)
242                 return 1;
243
244         if (bo->lock_cnt < 0) {
245                 TBM_ERR("error bo:%p LOCK_CNT=%d\n",
246                         bo, bo->lock_cnt);
247                 return 0;
248         }
249
250         old = bo->lock_cnt;
251
252         switch (bo->bufmgr->bo_lock_type) {
253         case TBM_BUFMGR_BO_LOCK_TYPE_ONCE:
254                 if (bo->lock_cnt == 0) {
255                         _tbm_bo_mutex_unlock();
256                         ret = _bo_lock(bo, device, opt);
257                         _tbm_bo_mutex_lock();
258                         if (ret)
259                                 bo->lock_cnt++;
260                 } else
261                         ret = 1;
262                 break;
263         case TBM_BUFMGR_BO_LOCK_TYPE_ALWAYS:
264                 _tbm_bo_mutex_unlock();
265                 ret = _bo_lock(bo, device, opt);
266                 _tbm_bo_mutex_lock();
267                 if (ret)
268                         bo->lock_cnt++;
269                 break;
270         default:
271                 TBM_ERR("error bo:%p bo_lock_type[%d] is wrong.\n",
272                                 bo, bo->bufmgr->bo_lock_type);
273                 ret = 0;
274                 break;
275         }
276
277         TBM_DBG(">> LOCK bo:%p(%d->%d)\n", bo, old, bo->lock_cnt);
278
279         return ret;
280 }
281
282 static void
283 _tbm_bo_unlock(tbm_bo bo)
284 {
285         int old;
286
287         /* do not try to unlock the bo */
288         if (bo->bufmgr->bo_lock_type == TBM_BUFMGR_BO_LOCK_TYPE_NEVER)
289                 return;
290
291         old = bo->lock_cnt;
292
293         switch (bo->bufmgr->bo_lock_type) {
294         case TBM_BUFMGR_BO_LOCK_TYPE_ONCE:
295                 if (bo->lock_cnt > 0) {
296                         bo->lock_cnt--;
297                         if (bo->lock_cnt == 0)
298                                 _bo_unlock(bo);
299                 }
300                 break;
301         case TBM_BUFMGR_BO_LOCK_TYPE_ALWAYS:
302                 if (bo->lock_cnt > 0) {
303                         bo->lock_cnt--;
304                         _bo_unlock(bo);
305                 }
306                 break;
307         default:
308                 TBM_ERR("error bo:%p bo_lock_type[%d] is wrong.\n",
309                                 bo, bo->bufmgr->bo_lock_type);
310                 break;
311         }
312
313         if (bo->lock_cnt < 0)
314                 bo->lock_cnt = 0;
315
316         TBM_DBG(">> UNLOCK bo:%p(%d->%d)\n", bo, old, bo->lock_cnt);
317 }
318
319 static int
320 _tbm_bo_is_valid(tbm_bo bo)
321 {
322         tbm_bufmgr bufmgr = NULL;
323         tbm_bo old_data = NULL;
324
325         if (bo == NULL) {
326                 TBM_ERR("error: bo is NULL.\n");
327                 return 0;
328         }
329
330         bufmgr = tbm_bufmgr_get();
331         if (bufmgr == NULL) {
332                 TBM_ERR("error: bufmgr is NULL.\n");
333                 return 0;
334         }
335
336         if (LIST_IS_EMPTY(&bufmgr->bo_list)) {
337                 TBM_ERR("error: bo->bo->bufmgr->bo_list is EMPTY.\n");
338                 return 0;
339         }
340
341         LIST_FOR_EACH_ENTRY(old_data, &bufmgr->bo_list, item_link) {
342                 if (old_data == bo)
343                         return 1;
344         }
345
346         TBM_ERR("error: No valid bo(%p).\n", bo);
347
348         return 0;
349 }
350
351 tbm_bo
352 tbm_bo_alloc(tbm_bufmgr bufmgr, int size, int flags)
353 {
354         tbm_bo bo;
355         void *bo_priv;
356         tbm_backend_bo_data *bo_data;
357         tbm_error_e error;
358
359         _tbm_bo_mutex_lock();
360
361         TBM_BO_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
362         TBM_BO_RETURN_VAL_IF_FAIL(size > 0, NULL);
363
364         bo = calloc(1, sizeof(struct _tbm_bo));
365         if (!bo) {
366                 /* LCOV_EXCL_START */
367                 TBM_ERR("error: fail to create of tbm_bo size(%d) flag(%s)\n",
368                                 size, _tbm_flag_to_str(flags));
369                 _tbm_set_last_result(TBM_BO_ERROR_HEAP_ALLOC_FAILED);
370                 _tbm_bo_mutex_unlock();
371                 return NULL;
372                 /* LCOV_EXCL_STOP */
373         }
374
375         _tbm_util_check_bo_cnt(bufmgr);
376
377         bo->bufmgr = bufmgr;
378
379         if (bufmgr->backend_module_data) {
380                 bo_data = bufmgr->bufmgr_func->bufmgr_alloc_bo(bufmgr->bufmgr_data, (unsigned int)size, flags, &error);
381                 if (!bo_data) {
382                         /* LCOV_EXCL_START */
383                         TBM_ERR("error: fail to create of tbm_bo size(%d) flag(%s)\n",
384                                         size, _tbm_flag_to_str(flags));
385                         _tbm_set_last_result(TBM_BO_ERROR_BO_ALLOC_FAILED);
386                         free(bo);
387                         _tbm_bo_mutex_unlock();
388                         return NULL;
389                         /* LCOV_EXCL_STOP */
390                 }
391                 bo->bo_data = bo_data;
392         } else {
393                 bo_priv = bo->bufmgr->backend->bo_alloc(bo, size, flags);
394                 if (!bo_priv) {
395                         /* LCOV_EXCL_START */
396                         TBM_ERR("error: fail to create of tbm_bo size(%d) flag(%s)\n",
397                                         size, _tbm_flag_to_str(flags));
398                         _tbm_set_last_result(TBM_BO_ERROR_BO_ALLOC_FAILED);
399                         free(bo);
400                         _tbm_bo_mutex_unlock();
401                         return NULL;
402                         /* LCOV_EXCL_STOP */
403                 }
404                 bo->priv = bo_priv;
405         }
406
407         bo->bufmgr->bo_cnt++;
408         bo->ref_cnt = 1;
409         bo->flags = flags;
410
411         TBM_TRACE_BO("bo(%p) size(%d) refcnt(%d), flag(%s)\n", bo, size, bo->ref_cnt,
412                         _tbm_flag_to_str(bo->flags));
413
414         LIST_INITHEAD(&bo->user_data_list);
415
416         LIST_ADD(&bo->item_link, &bo->bufmgr->bo_list);
417
418         _tbm_bo_mutex_unlock();
419
420         return bo;
421 }
422
423 tbm_bo
424 tbm_bo_ref(tbm_bo bo)
425 {
426         _tbm_bo_mutex_lock();
427
428         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), NULL);
429
430         bo->ref_cnt++;
431
432         TBM_TRACE_BO("bo(%p) ref_cnt(%d)\n", bo, bo->ref_cnt);
433
434         _tbm_bo_mutex_unlock();
435
436         return bo;
437 }
438
439 void
440 tbm_bo_unref(tbm_bo bo)
441 {
442         _tbm_bo_mutex_lock();
443
444         TBM_BO_RETURN_IF_FAIL(_tbm_bo_is_valid(bo));
445
446         TBM_TRACE_BO("bo(%p) ref_cnt(%d)\n", bo, bo->ref_cnt - 1);
447
448         if (bo->ref_cnt <= 0) {
449                 _tbm_bo_mutex_unlock();
450                 return;
451         }
452
453         bo->ref_cnt--;
454         if (bo->ref_cnt == 0)
455                 _tbm_bo_free(bo);
456
457         _tbm_bo_mutex_unlock();
458 }
459
460 tbm_bo_handle
461 tbm_bo_map(tbm_bo bo, int device, int opt)
462 {
463         tbm_bo_handle bo_handle;
464         tbm_error_e error;
465
466         _tbm_bo_mutex_lock();
467
468         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) NULL);
469
470         if (!_tbm_bo_lock(bo, device, opt)) {
471                 _tbm_set_last_result(TBM_BO_ERROR_LOCK_FAILED);
472                 TBM_ERR("error: fail to lock bo:%p)\n", bo);
473                 _tbm_bo_mutex_unlock();
474                 return (tbm_bo_handle) NULL;
475         }
476
477         if (bo->bufmgr->backend_module_data) {
478                 bo_handle = bo->bufmgr->bo_func->bo_map(bo->bo_data, device, opt, &error);
479                 if (bo_handle.ptr == NULL) {
480                         /* LCOV_EXCL_START */
481                         _tbm_set_last_result(TBM_BO_ERROR_MAP_FAILED);
482                         TBM_ERR("error: fail to map bo:%p error:%d\n", bo, error);
483                         _tbm_bo_unlock(bo);
484                         _tbm_bo_mutex_unlock();
485                         return (tbm_bo_handle) NULL;
486                         /* LCOV_EXCL_STOP */
487                 }
488         } else {
489                 bo_handle = bo->bufmgr->backend->bo_map(bo, device, opt);
490                 if (bo_handle.ptr == NULL) {
491                         /* LCOV_EXCL_START */
492                         _tbm_set_last_result(TBM_BO_ERROR_MAP_FAILED);
493                         TBM_ERR("error: fail to map bo:%p\n", bo);
494                         _tbm_bo_unlock(bo);
495                         _tbm_bo_mutex_unlock();
496                         return (tbm_bo_handle) NULL;
497                         /* LCOV_EXCL_STOP */
498                 }
499         }
500
501         /* increase the map_count */
502         bo->map_cnt++;
503
504         TBM_TRACE_BO("bo(%p) map_cnt(%d)\n", bo, bo->map_cnt);
505
506         _tbm_bo_mutex_unlock();
507
508         return bo_handle;
509 }
510
511 int
512 tbm_bo_unmap(tbm_bo bo)
513 {
514         int ret = 1;
515         tbm_error_e error;
516
517         _tbm_bo_mutex_lock();
518
519         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
520         TBM_BO_RETURN_VAL_IF_FAIL(bo->map_cnt > 0, 0);
521
522         if (bo->bufmgr->backend_module_data) {
523                 error = bo->bufmgr->bo_func->bo_unmap(bo->bo_data);
524                 if (error != TBM_ERROR_NONE) {
525                         /* LCOV_EXCL_START */
526                         TBM_ERR("error: bo(%p) map_cnt(%d) error(%d)\n", bo, bo->map_cnt, error);
527                         _tbm_set_last_result(TBM_BO_ERROR_UNMAP_FAILED);
528                         ret = 0;
529                         _tbm_bo_mutex_unlock();
530                         return ret;
531                         /* LCOV_EXCL_STOP */
532                 }
533         } else {
534                 ret = bo->bufmgr->backend->bo_unmap(bo);
535                 if (!ret) {
536                         /* LCOV_EXCL_START */
537                         TBM_ERR("error: bo(%p) map_cnt(%d)\n", bo, bo->map_cnt);
538                         _tbm_set_last_result(TBM_BO_ERROR_UNMAP_FAILED);
539                         _tbm_bo_mutex_unlock();
540                         return ret;
541                         /* LCOV_EXCL_STOP */
542                 }
543         }
544
545         /* decrease the map_count */
546         bo->map_cnt--;
547
548         TBM_TRACE_BO("bo(%p) map_cnt(%d)\n", bo, bo->map_cnt);
549
550         _tbm_bo_unlock(bo);
551
552         _tbm_bo_mutex_unlock();
553
554         return ret;
555 }
556
557 tbm_bo_handle
558 tbm_bo_get_handle(tbm_bo bo, int device)
559 {
560         tbm_bo_handle bo_handle;
561         tbm_error_e error;
562
563         _tbm_bo_mutex_lock();
564
565         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) NULL);
566
567         if (bo->bufmgr->backend_module_data) {
568                 bo_handle = bo->bufmgr->bo_func->bo_get_handle(bo->bo_data, device, &error);
569                 if (bo_handle.ptr == NULL) {
570                         /* LCOV_EXCL_START */
571                         _tbm_set_last_result(TBM_BO_ERROR_GET_HANDLE_FAILED);
572                         TBM_ERR("error: bo(%p) bo_handle(%p) error(%d)\n", bo, bo_handle.ptr, error);
573                         _tbm_bo_mutex_unlock();
574                         return (tbm_bo_handle) NULL;
575                         /* LCOV_EXCL_STOP */
576                 }
577         } else {
578                 bo_handle = bo->bufmgr->backend->bo_get_handle(bo, device);
579                 if (bo_handle.ptr == NULL) {
580                         /* LCOV_EXCL_START */
581                         _tbm_set_last_result(TBM_BO_ERROR_GET_HANDLE_FAILED);
582                         TBM_ERR("error: bo(%p) bo_handle(%p)\n", bo, bo_handle.ptr);
583                         _tbm_bo_mutex_unlock();
584                         return (tbm_bo_handle) NULL;
585                         /* LCOV_EXCL_STOP */
586                 }
587         }
588
589         TBM_TRACE_BO("bo(%p) bo_handle(%p)\n", bo, bo_handle.ptr);
590
591         _tbm_bo_mutex_unlock();
592
593         return bo_handle;
594 }
595
596 tbm_key
597 tbm_bo_export(tbm_bo bo)
598 {
599         tbm_key ret;
600         tbm_error_e error;
601
602         _tbm_bo_mutex_lock();
603
604         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
605
606         if (bo->bufmgr->backend_module_data) {
607                 if (!bo->bufmgr->bo_func->bo_export_key) {
608                         /* LCOV_EXCL_START */
609                         _tbm_bo_mutex_unlock();
610                         return 0;
611                         /* LCOV_EXCL_STOP */
612                 }
613
614                 ret = bo->bufmgr->bo_func->bo_export_key(bo->bo_data, &error);
615                 if (!ret) {
616                         /* LCOV_EXCL_START */
617                         _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FAILED);
618                         TBM_ERR("error: bo(%p) tbm_key(%d) error(%d)\n", bo, ret, error);
619                         _tbm_bo_mutex_unlock();
620                         return ret;
621                         /* LCOV_EXCL_STOP */
622                 }
623         } else {
624                 if (!bo->bufmgr->backend->bo_export) {
625                         /* LCOV_EXCL_START */
626                         _tbm_bo_mutex_unlock();
627                         return 0;
628                         /* LCOV_EXCL_STOP */
629                 }
630
631                 ret = bo->bufmgr->backend->bo_export(bo);
632                 if (!ret) {
633                         /* LCOV_EXCL_START */
634                         _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FAILED);
635                         TBM_ERR("error: bo(%p) tbm_key(%d)\n", bo, ret);
636                         _tbm_bo_mutex_unlock();
637                         return ret;
638                         /* LCOV_EXCL_STOP */
639                 }
640         }
641
642         TBM_TRACE_BO("bo(%p) tbm_key(%u)\n", bo, ret);
643
644         _tbm_bo_mutex_unlock();
645
646         return ret;
647 }
648
649 tbm_fd
650 tbm_bo_export_fd(tbm_bo bo)
651 {
652         tbm_fd ret;
653         tbm_error_e error;
654
655         _tbm_bo_mutex_lock();
656
657         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), -1);
658
659         if (bo->bufmgr->backend_module_data) {
660                 if (!bo->bufmgr->bo_func->bo_export_fd) {
661                         /* LCOV_EXCL_START */
662                         _tbm_bo_mutex_unlock();
663                         return -1;
664                         /* LCOV_EXCL_STOP */
665                 }
666
667                 ret = bo->bufmgr->bo_func->bo_export_fd(bo->bo_data, &error);
668                 if (ret < 0) {
669                         /* LCOV_EXCL_START */
670                         _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FD_FAILED);
671                         TBM_ERR("error: bo(%p) tbm_fd(%d) error(%d)\n", bo, ret, error);
672                         _tbm_bo_mutex_unlock();
673                         return ret;
674                         /* LCOV_EXCL_STOP */
675                 }
676         } else {
677                 if (!bo->bufmgr->backend->bo_export_fd) {
678                         /* LCOV_EXCL_START */
679                         _tbm_bo_mutex_unlock();
680                         return -1;
681                         /* LCOV_EXCL_STOP */
682                 }
683
684                 ret = bo->bufmgr->backend->bo_export_fd(bo);
685                 if (ret < 0) {
686                         /* LCOV_EXCL_START */
687                         _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FD_FAILED);
688                         TBM_ERR("error: bo(%p) tbm_fd(%d)\n", bo, ret);
689                         _tbm_bo_mutex_unlock();
690                         return ret;
691                         /* LCOV_EXCL_STOP */
692                 }
693         }
694
695         TBM_TRACE_BO("bo(%p) tbm_fd(%d)\n", bo, ret);
696
697         _tbm_bo_mutex_unlock();
698
699         return ret;
700 }
701
702 tbm_bo
703 tbm_bo_import(tbm_bufmgr bufmgr, unsigned int key)
704 {
705         tbm_bo bo;
706         tbm_bo bo2 = NULL;
707         void *bo_priv;
708         tbm_error_e error;
709         tbm_backend_bo_data *bo_data;
710
711         _tbm_bo_mutex_lock();
712
713         TBM_BO_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
714
715         if (bufmgr->backend_module_data) {
716                 if (!bufmgr->bufmgr_func->bufmgr_import_key) {
717                         /* LCOV_EXCL_START */
718                         _tbm_bo_mutex_unlock();
719                         return NULL;
720                         /* LCOV_EXCL_STOP */
721                 }
722         } else {
723                 if (!bufmgr->backend->bo_import) {
724                         /* LCOV_EXCL_START */
725                         _tbm_bo_mutex_unlock();
726                         return NULL;
727                         /* LCOV_EXCL_STOP */
728                 }
729         }
730
731         _tbm_util_check_bo_cnt(bufmgr);
732
733         bo = calloc(1, sizeof(struct _tbm_bo));
734         if (!bo) {
735                 /* LCOV_EXCL_START */
736                 TBM_ERR("error: fail to import of tbm_bo by key(%d)\n", key);
737                 _tbm_bo_mutex_unlock();
738                 return NULL;
739                 /* LCOV_EXCL_STOP */
740         }
741
742         bo->bufmgr = bufmgr;
743
744         if (bo->bufmgr->backend_module_data) {
745                 bo_data = bo->bufmgr->bufmgr_func->bufmgr_import_key(bufmgr->bufmgr_data, key, &error);
746                 if (!bo_data) {
747                         /* LCOV_EXCL_START */
748                         TBM_ERR("error: fail to import of tbm_bo by key(%d). error(%d)\n", key, error);
749                         _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FAILED);
750                         free(bo);
751                         _tbm_bo_mutex_unlock();
752                         return NULL;
753                         /* LCOV_EXCL_STOP */
754                 }
755
756                 if (!LIST_IS_EMPTY(&bo->bufmgr->bo_list)) {
757                         LIST_FOR_EACH_ENTRY(bo2, &bo->bufmgr->bo_list, item_link) {
758                                 if (bo2->bo_data == bo_data) {
759                                         TBM_TRACE_BO("find bo(%p) ref(%d) key(%d) flag(%s) in list\n",
760                                                         bo2, bo2->ref_cnt, key,
761                                                         _tbm_flag_to_str(bo2->flags));
762                                         bo2->ref_cnt++;
763                                         free(bo);
764                                         _tbm_bo_mutex_unlock();
765                                         return bo2;
766                                 }
767                         }
768                 }
769                 bo->bo_data = bo_data;
770         } else {
771                 bo_priv = bo->bufmgr->backend->bo_import(bo, key);
772                 if (!bo_priv) {
773                         /* LCOV_EXCL_START */
774                         TBM_ERR("error: fail to import of tbm_bo by key(%d)\n", key);
775                         _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FAILED);
776                         free(bo);
777                         _tbm_bo_mutex_unlock();
778                         return NULL;
779                         /* LCOV_EXCL_STOP */
780                 }
781
782                 if (!LIST_IS_EMPTY(&bo->bufmgr->bo_list)) {
783                         LIST_FOR_EACH_ENTRY(bo2, &bo->bufmgr->bo_list, item_link) {
784                                 if (bo2->priv == bo_priv) {
785                                         TBM_TRACE_BO("find bo(%p) ref(%d) key(%d) flag(%s) in list\n",
786                                                         bo2, bo2->ref_cnt, key,
787                                                         _tbm_flag_to_str(bo2->flags));
788                                         bo2->ref_cnt++;
789                                         free(bo);
790                                         _tbm_bo_mutex_unlock();
791                                         return bo2;
792                                 }
793                         }
794                 }
795                 bo->priv = bo_priv;
796         }
797
798         bo->bufmgr->bo_cnt++;
799         bo->ref_cnt = 1;
800
801         if (bo->bufmgr->backend_module_data) {
802                 bo->flags = bo->bufmgr->bo_func->bo_get_memory_types(bo->bo_data, &error);
803                 if (error != TBM_ERROR_NONE) {
804                         TBM_ERR("fail to get the bo flags(memory_types)");
805                         bo->flags = TBM_BO_DEFAULT;
806                 }
807         } else {
808                 if (bo->bufmgr->backend->bo_get_flags)
809                         bo->flags = bo->bufmgr->backend->bo_get_flags(bo);
810                 else
811                         bo->flags = TBM_BO_DEFAULT;
812         }
813
814         TBM_TRACE_BO("import new bo(%p) ref(%d) key(%d) flag(%s) in list\n",
815                           bo, bo->ref_cnt, key, _tbm_flag_to_str(bo->flags));
816
817         LIST_INITHEAD(&bo->user_data_list);
818
819         LIST_ADD(&bo->item_link, &bo->bufmgr->bo_list);
820
821         _tbm_bo_mutex_unlock();
822
823         return bo;
824 }
825
826 tbm_bo
827 tbm_bo_import_fd(tbm_bufmgr bufmgr, tbm_fd fd)
828 {
829         tbm_bo bo;
830         tbm_bo bo2 = NULL;
831         void *bo_priv;
832         tbm_backend_bo_data *bo_data;
833         tbm_error_e error;
834
835         _tbm_bo_mutex_lock();
836
837         TBM_BO_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
838
839         if (bufmgr->backend_module_data) {
840                 if (!bufmgr->bufmgr_func->bufmgr_import_fd) {
841                         /* LCOV_EXCL_START */
842                         _tbm_bo_mutex_unlock();
843                         return NULL;
844                         /* LCOV_EXCL_STOP */
845                 }
846         } else {
847                 if (!bufmgr->backend->bo_import_fd) {
848                         /* LCOV_EXCL_START */
849                         _tbm_bo_mutex_unlock();
850                         return NULL;
851                         /* LCOV_EXCL_STOP */
852                 }
853         }
854
855         _tbm_util_check_bo_cnt(bufmgr);
856
857         bo = calloc(1, sizeof(struct _tbm_bo));
858         if (!bo) {
859                 /* LCOV_EXCL_START */
860                 TBM_ERR("error: fail to import tbm_bo by tbm_fd(%d)\n", fd);
861                 _tbm_bo_mutex_unlock();
862                 return NULL;
863                 /* LCOV_EXCL_STOP */
864         }
865
866         bo->bufmgr = bufmgr;
867
868         if (bo->bufmgr->backend_module_data) {
869                 bo_data = bo->bufmgr->bufmgr_func->bufmgr_import_fd(bufmgr->bufmgr_data, fd, &error);
870                 if (!bo_data) {
871                         /* LCOV_EXCL_START */
872                         TBM_ERR("error: fail to import tbm_bo by tbm_fd(%d). error(%d)\n", fd, error);
873                         _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FD_FAILED);
874                         free(bo);
875                         _tbm_bo_mutex_unlock();
876                         return NULL;
877                         /* LCOV_EXCL_STOP */
878                 }
879
880                 if (!LIST_IS_EMPTY(&bo->bufmgr->bo_list)) {
881                         LIST_FOR_EACH_ENTRY(bo2, &bo->bufmgr->bo_list, item_link) {
882                                 if (bo2->bo_data == bo_data) {
883                                         TBM_TRACE_BO("find bo(%p) ref(%d) fd(%d) flag(%s) in list\n",
884                                                         bo2, bo2->ref_cnt, fd,
885                                                         _tbm_flag_to_str(bo2->flags));
886                                         bo2->ref_cnt++;
887                                         free(bo);
888                                         _tbm_bo_mutex_unlock();
889                                         return bo2;
890                                 }
891                         }
892                 }
893                 bo->bo_data = bo_data;
894         } else {
895                 bo_priv = bo->bufmgr->backend->bo_import_fd(bo, fd);
896                 if (!bo_priv) {
897                         /* LCOV_EXCL_START */
898                         TBM_ERR("error: fail to import tbm_bo by tbm_fd(%d)\n", fd);
899                         _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FD_FAILED);
900                         free(bo);
901                         _tbm_bo_mutex_unlock();
902                         return NULL;
903                         /* LCOV_EXCL_STOP */
904                 }
905
906                 if (!LIST_IS_EMPTY(&bo->bufmgr->bo_list)) {
907                         LIST_FOR_EACH_ENTRY(bo2, &bo->bufmgr->bo_list, item_link) {
908                                 if (bo2->priv == bo_priv) {
909                                         TBM_TRACE_BO("find bo(%p) ref(%d) fd(%d) flag(%s) in list\n",
910                                                         bo2, bo2->ref_cnt, fd,
911                                                         _tbm_flag_to_str(bo2->flags));
912                                         bo2->ref_cnt++;
913                                         free(bo);
914                                         _tbm_bo_mutex_unlock();
915                                         return bo2;
916                                 }
917                         }
918                 }
919                 bo->priv = bo_priv;
920         }
921
922         bo->bufmgr->bo_cnt++;
923         bo->ref_cnt = 1;
924
925         if (bo->bufmgr->backend_module_data) {
926                 bo->flags = bo->bufmgr->bo_func->bo_get_memory_types(bo->bo_data, &error);
927                 if (error != TBM_ERROR_NONE) {
928                         TBM_ERR("fail to get the bo flags(memory_types)");
929                         bo->flags = TBM_BO_DEFAULT;
930                 }
931         } else {
932                 if (bo->bufmgr->backend->bo_get_flags)
933                         bo->flags = bo->bufmgr->backend->bo_get_flags(bo);
934                 else
935                         bo->flags = TBM_BO_DEFAULT;
936         }
937
938         TBM_TRACE_BO("import bo(%p) ref(%d) fd(%d) flag(%s)\n",
939                         bo, bo->ref_cnt, fd, _tbm_flag_to_str(bo->flags));
940
941         LIST_INITHEAD(&bo->user_data_list);
942
943         LIST_ADD(&bo->item_link, &bo->bufmgr->bo_list);
944
945         _tbm_bo_mutex_unlock();
946
947         return bo;
948 }
949
950 int
951 tbm_bo_size(tbm_bo bo)
952 {
953         int size;
954         tbm_error_e error;
955
956         _tbm_bo_mutex_lock();
957
958         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
959
960         if (bo->bufmgr->backend_module_data) {
961                 size = bo->bufmgr->bo_func->bo_get_size(bo->bo_data, &error);
962                 if (error != TBM_ERROR_NONE)
963                         TBM_ERR("fail to get the size of the bo_data(%d).", error);
964         } else
965                 size = bo->bufmgr->backend->bo_size(bo);
966
967         TBM_TRACE_BO("bo(%p) size(%d)\n", bo, size);
968
969         _tbm_bo_mutex_unlock();
970
971         return size;
972 }
973
974 int
975 tbm_bo_locked(tbm_bo bo)
976 {
977         _tbm_bo_mutex_lock();
978
979         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
980
981         if (bo->bufmgr->bo_lock_type == TBM_BUFMGR_BO_LOCK_TYPE_NEVER) {
982                 TBM_ERR("bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
983                 _tbm_bo_mutex_unlock();
984                 return 0;
985         }
986
987         if (bo->lock_cnt > 0) {
988                 TBM_TRACE_BO("error: bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
989                 _tbm_bo_mutex_unlock();
990                 return 1;
991         }
992
993         TBM_TRACE_BO("bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
994         _tbm_bo_mutex_unlock();
995
996         return 0;
997 }
998
999 int
1000 tbm_bo_swap(tbm_bo bo1, tbm_bo bo2)
1001 {
1002         tbm_error_e error1, error2;
1003         int size1 = -1, size2 = -2;
1004         void *temp;
1005
1006         _tbm_bo_mutex_lock();
1007
1008         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo1), 0);
1009         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo2), 0);
1010
1011         TBM_TRACE_BO("before: bo1(%p) bo2(%p)\n", bo1, bo2);
1012
1013         if (bo1->bufmgr->backend_module_data) {
1014                 size1 = bo1->bufmgr->bo_func->bo_get_size(bo1->bo_data, &error1);
1015                 if (error1 != TBM_ERROR_NONE) {
1016                         TBM_ERR("fail to get the size of bo1.(%d)", error1);
1017                         goto fail;
1018                 }
1019                 size2 = bo2->bufmgr->bo_func->bo_get_size(bo2->bo_data, &error2);
1020                 if (error2 != TBM_ERROR_NONE) {
1021                         TBM_ERR("fail to get the size of bo2.(%d)", error2);
1022                         goto fail;
1023                 }
1024         } else {
1025                 size1 = bo1->bufmgr->backend->bo_size(bo1);
1026                 size2 = bo2->bufmgr->backend->bo_size(bo2);
1027         }
1028
1029         if (size1 != size2) {
1030                 TBM_ERR("error: bo1 size(%d) and bo2 size(%d) is different.", size1, size2);
1031                 goto fail;
1032         }
1033
1034         TBM_TRACE_BO("after: bo1(%p) bo2(%p)\n", bo1, bo2);
1035
1036         temp = bo1->priv;
1037         bo1->priv = bo2->priv;
1038         bo2->priv = temp;
1039
1040         _tbm_bo_mutex_unlock();
1041
1042         return 1;
1043
1044 fail:
1045         _tbm_set_last_result(TBM_BO_ERROR_SWAP_FAILED);
1046         TBM_ERR("error: bo1(%p) bo2(%p)\n", bo1, bo2);
1047         _tbm_bo_mutex_unlock();
1048
1049         return 0;
1050 }
1051
1052 int
1053 tbm_bo_add_user_data(tbm_bo bo, unsigned long key,
1054                      tbm_data_free data_free_func)
1055 {
1056         tbm_user_data *data;
1057
1058         _tbm_bo_mutex_lock();
1059
1060         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1061
1062         /* check if the data according to the key exist if so, return false. */
1063         data = user_data_lookup(&bo->user_data_list, key);
1064         if (data) {
1065                 TBM_TRACE_BO("warning: user data already exist key(%ld)\n", key);
1066                 _tbm_bo_mutex_unlock();
1067                 return 0;
1068         }
1069
1070         data = user_data_create(key, data_free_func);
1071         if (!data) {
1072                 TBM_ERR("error: bo(%p) key(%lu)\n", bo, key);
1073                 _tbm_bo_mutex_unlock();
1074                 return 0;
1075         }
1076
1077         TBM_TRACE_BO("bo(%p) key(%lu) data(%p)\n", bo, key, data->data);
1078
1079         LIST_ADD(&data->item_link, &bo->user_data_list);
1080
1081         _tbm_bo_mutex_unlock();
1082
1083         return 1;
1084 }
1085
1086 int
1087 tbm_bo_delete_user_data(tbm_bo bo, unsigned long key)
1088 {
1089         tbm_user_data *old_data;
1090
1091         _tbm_bo_mutex_lock();
1092
1093         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1094
1095         if (LIST_IS_EMPTY(&bo->user_data_list)) {
1096                 TBM_TRACE_BO("error: bo(%p) key(%lu)\n", bo, key);
1097                 _tbm_bo_mutex_unlock();
1098                 return 0;
1099         }
1100
1101         old_data = user_data_lookup(&bo->user_data_list, key);
1102         if (!old_data) {
1103                 TBM_TRACE_BO("error: bo(%p) key(%lu)\n", bo, key);
1104                 _tbm_bo_mutex_unlock();
1105                 return 0;
1106         }
1107
1108         TBM_TRACE_BO("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
1109
1110         user_data_delete(old_data);
1111
1112         _tbm_bo_mutex_unlock();
1113
1114         return 1;
1115 }
1116
1117 int
1118 tbm_bo_set_user_data(tbm_bo bo, unsigned long key, void *data)
1119 {
1120         tbm_user_data *old_data;
1121
1122         _tbm_bo_mutex_lock();
1123
1124         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1125
1126         if (LIST_IS_EMPTY(&bo->user_data_list)) {
1127                 TBM_TRACE_BO("error: bo(%p) key(%lu)\n", bo, key);
1128                 _tbm_bo_mutex_unlock();
1129                 return 0;
1130         }
1131
1132         old_data = user_data_lookup(&bo->user_data_list, key);
1133         if (!old_data) {
1134                 TBM_TRACE_BO("error: bo(%p) key(%lu)\n", bo, key);
1135                 _tbm_bo_mutex_unlock();
1136                 return 0;
1137         }
1138
1139         if (old_data->data && old_data->free_func)
1140                 old_data->free_func(old_data->data);
1141         old_data->data = data;
1142
1143         TBM_TRACE_BO("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
1144
1145         _tbm_bo_mutex_unlock();
1146
1147         return 1;
1148 }
1149
1150 int
1151 tbm_bo_get_user_data(tbm_bo bo, unsigned long key, void **data)
1152 {
1153         tbm_user_data *old_data;
1154
1155         _tbm_bo_mutex_lock();
1156
1157         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1158
1159         if (!data || LIST_IS_EMPTY(&bo->user_data_list)) {
1160                 TBM_TRACE_BO("error: bo(%p) key(%lu)\n", bo, key);
1161                 _tbm_bo_mutex_unlock();
1162                 return 0;
1163         }
1164
1165         old_data = user_data_lookup(&bo->user_data_list, key);
1166         if (!old_data) {
1167                 TBM_TRACE_BO("error: bo(%p) key(%lu)\n", bo, key);
1168                 *data = NULL;
1169                 _tbm_bo_mutex_unlock();
1170                 return 0;
1171         }
1172
1173         *data = old_data->data;
1174
1175         TBM_TRACE_BO("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
1176
1177         _tbm_bo_mutex_unlock();
1178
1179         return 1;
1180 }
1181
1182 /* LCOV_EXCL_START */
1183 tbm_error_e
1184 tbm_get_last_error(void)
1185 {
1186         return tbm_last_error;
1187 }
1188 /* LCOV_EXCL_STOP */
1189
1190 int
1191 tbm_bo_get_flags(tbm_bo bo)
1192 {
1193         int flags;
1194
1195         _tbm_bo_mutex_lock();
1196
1197         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1198
1199         flags = bo->flags;
1200
1201         TBM_TRACE_BO("bo(%p)\n", bo);
1202
1203         _tbm_bo_mutex_unlock();
1204
1205         return flags;
1206 }
1207
1208 /* LCOV_EXCL_START */
1209 /* internal function */
1210 int
1211 _tbm_bo_set_surface(tbm_bo bo, tbm_surface_h surface)
1212 {
1213         _tbm_bo_mutex_lock();
1214
1215         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1216
1217         bo->surface = surface;
1218
1219         _tbm_bo_mutex_unlock();
1220
1221         return 1;
1222 }
1223
1224 void
1225 _tbm_bo_free(tbm_bo bo)
1226 {
1227         /* destory the user_data_list */
1228         if (!LIST_IS_EMPTY(&bo->user_data_list)) {
1229                 tbm_user_data *old_data = NULL, *tmp;
1230
1231                 LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp,
1232                                 &bo->user_data_list, item_link) {
1233                         TBM_DBG("free user_data\n");
1234                         user_data_delete(old_data);
1235                 }
1236         }
1237
1238         while (bo->lock_cnt > 0) {
1239                 TBM_ERR("error lock_cnt:%d\n", bo->lock_cnt);
1240                 _bo_unlock(bo);
1241                 bo->lock_cnt--;
1242         }
1243
1244         /* call the bo_free */
1245         if (bo->bufmgr->backend_module_data) {
1246                 bo->bufmgr->bo_func->bo_free(bo->bo_data);
1247                 bo->bo_data = NULL;
1248         } else {
1249                 bo->bufmgr->backend->bo_free(bo);
1250                 bo->priv = NULL;
1251         }
1252
1253         bo->bufmgr->bo_cnt--;
1254
1255         LIST_DEL(&bo->item_link);
1256         free(bo);
1257 }
1258 /* LCOV_EXCL_STOP */