ed12dfc8f5d4c40ec122470939377d0ed713e431
[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_LOG_E("'%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_LOG_E("'%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_LOG_E("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_LOG_E("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_DEBUG("============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_LOG_E("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
198         if (bo->bufmgr->backend->bo_lock)
199                 ret = bo->bufmgr->backend->bo_lock(bo, device, opt);
200
201         return ret;
202 }
203
204 static void
205 _bo_unlock(tbm_bo bo)
206 {
207         if (bo->bufmgr->backend->bo_unlock)
208                 bo->bufmgr->backend->bo_unlock(bo);
209 }
210
211 static int
212 _tbm_bo_lock(tbm_bo bo, int device, int opt)
213 {
214         int old, ret;
215
216         if (!bo)
217                 return 0;
218
219         /* do not try to lock the bo */
220         if (bo->bufmgr->bo_lock_type == TBM_BUFMGR_BO_LOCK_TYPE_NEVER)
221                 return 1;
222
223         if (bo->lock_cnt < 0) {
224                 TBM_LOG_E("error bo:%p LOCK_CNT=%d\n",
225                         bo, bo->lock_cnt);
226                 return 0;
227         }
228
229         old = bo->lock_cnt;
230
231         switch (bo->bufmgr->bo_lock_type) {
232         case TBM_BUFMGR_BO_LOCK_TYPE_ONCE:
233                 if (bo->lock_cnt == 0) {
234                         _tbm_bo_mutex_unlock();
235                         ret = _bo_lock(bo, device, opt);
236                         _tbm_bo_mutex_lock();
237                         if (ret)
238                                 bo->lock_cnt++;
239                 } else
240                         ret = 1;
241                 break;
242         case TBM_BUFMGR_BO_LOCK_TYPE_ALWAYS:
243                 _tbm_bo_mutex_unlock();
244                 ret = _bo_lock(bo, device, opt);
245                 _tbm_bo_mutex_lock();
246                 if (ret)
247                         bo->lock_cnt++;
248                 break;
249         default:
250                 TBM_LOG_E("error bo:%p bo_lock_type[%d] is wrong.\n",
251                                 bo, bo->bufmgr->bo_lock_type);
252                 ret = 0;
253                 break;
254         }
255
256         TBM_DBG_LOCK(">> LOCK bo:%p(%d->%d)\n", bo, old, bo->lock_cnt);
257
258         return ret;
259 }
260
261 static void
262 _tbm_bo_unlock(tbm_bo bo)
263 {
264         int old;
265
266         /* do not try to unlock the bo */
267         if (bo->bufmgr->bo_lock_type == TBM_BUFMGR_BO_LOCK_TYPE_NEVER)
268                 return;
269
270         old = bo->lock_cnt;
271
272         switch (bo->bufmgr->bo_lock_type) {
273         case TBM_BUFMGR_BO_LOCK_TYPE_ONCE:
274                 if (bo->lock_cnt > 0) {
275                         bo->lock_cnt--;
276                         if (bo->lock_cnt == 0)
277                                 _bo_unlock(bo);
278                 }
279                 break;
280         case TBM_BUFMGR_BO_LOCK_TYPE_ALWAYS:
281                 if (bo->lock_cnt > 0) {
282                         bo->lock_cnt--;
283                         _bo_unlock(bo);
284                 }
285                 break;
286         default:
287                 TBM_LOG_E("error bo:%p bo_lock_type[%d] is wrong.\n",
288                                 bo, bo->bufmgr->bo_lock_type);
289                 break;
290         }
291
292         if (bo->lock_cnt < 0)
293                 bo->lock_cnt = 0;
294
295         TBM_DBG_LOCK(">> UNLOCK bo:%p(%d->%d)\n", bo, old, bo->lock_cnt);
296 }
297
298 static int
299 _tbm_bo_is_valid(tbm_bo bo)
300 {
301         tbm_bufmgr bufmgr = NULL;
302         tbm_bo old_data = NULL;
303
304         if (bo == NULL) {
305                 TBM_LOG_E("error: bo is NULL.\n");
306                 return 0;
307         }
308
309         bufmgr = bo->bufmgr;
310
311         if (!TBM_BUFMGR_IS_VALID(bufmgr)) {
312                 TBM_LOG_E("error: bo->bufmgr is not valid.\n");
313                 return 0;
314         }
315
316         if (LIST_IS_EMPTY(&bo->bufmgr->bo_list)) {
317                 TBM_LOG_E("error: bo->bo->bufmgr->bo_list is EMPTY.\n");
318                 return 0;
319         }
320
321         LIST_FOR_EACH_ENTRY(old_data, &bo->bufmgr->bo_list, item_link) {
322                 if (old_data == bo)
323                         return 1;
324         }
325
326         TBM_LOG_E("error: No valid bo(%p).\n", bo);
327
328         return 0;
329 }
330
331 tbm_bo
332 tbm_bo_alloc(tbm_bufmgr bufmgr, int size, int flags)
333 {
334         void *bo_priv;
335         tbm_bo bo;
336
337         _tbm_bo_mutex_lock();
338
339         TBM_BO_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
340         TBM_BO_RETURN_VAL_IF_FAIL(size > 0, NULL);
341
342         bo = calloc(1, sizeof(struct _tbm_bo));
343         if (!bo) {
344                 /* LCOV_EXCL_START */
345                 TBM_LOG_E("error: fail to create of tbm_bo size(%d) flag(%s)\n",
346                                 size, _tbm_flag_to_str(flags));
347                 _tbm_set_last_result(TBM_BO_ERROR_HEAP_ALLOC_FAILED);
348                 _tbm_bo_mutex_unlock();
349                 return NULL;
350                 /* LCOV_EXCL_STOP */
351         }
352
353         _tbm_util_check_bo_cnt(bufmgr);
354
355         bo->bufmgr = bufmgr;
356
357         bo_priv = bo->bufmgr->backend->bo_alloc(bo, size, flags);
358         if (!bo_priv) {
359                 /* LCOV_EXCL_START */
360                 TBM_LOG_E("error: fail to create of tbm_bo size(%d) flag(%s)\n",
361                                 size, _tbm_flag_to_str(flags));
362                 _tbm_set_last_result(TBM_BO_ERROR_BO_ALLOC_FAILED);
363                 free(bo);
364                 _tbm_bo_mutex_unlock();
365                 return NULL;
366                 /* LCOV_EXCL_STOP */
367         }
368
369         bo->bufmgr->bo_cnt++;
370
371         bo->ref_cnt = 1;
372         bo->flags = flags;
373         bo->priv = bo_priv;
374
375         TBM_TRACE("bo(%p) size(%d) refcnt(%d), flag(%s)\n", bo, size, bo->ref_cnt,
376                         _tbm_flag_to_str(bo->flags));
377
378         LIST_INITHEAD(&bo->user_data_list);
379
380         LIST_ADD(&bo->item_link, &bo->bufmgr->bo_list);
381
382         _tbm_bo_mutex_unlock();
383
384         return bo;
385 }
386
387 tbm_bo
388 tbm_bo_ref(tbm_bo bo)
389 {
390         _tbm_bo_mutex_lock();
391
392         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), NULL);
393
394         bo->ref_cnt++;
395
396         TBM_TRACE("bo(%p) ref_cnt(%d)\n", bo, bo->ref_cnt);
397
398         _tbm_bo_mutex_unlock();
399
400         return bo;
401 }
402
403 void
404 tbm_bo_unref(tbm_bo bo)
405 {
406         _tbm_bo_mutex_lock();
407
408         TBM_BO_RETURN_IF_FAIL(_tbm_bo_is_valid(bo));
409
410         TBM_TRACE("bo(%p) ref_cnt(%d)\n", bo, bo->ref_cnt - 1);
411
412         if (bo->ref_cnt <= 0) {
413                 _tbm_bo_mutex_unlock();
414                 return;
415         }
416
417         bo->ref_cnt--;
418         if (bo->ref_cnt == 0)
419                 _tbm_bo_free(bo);
420
421         _tbm_bo_mutex_unlock();
422 }
423
424 tbm_bo_handle
425 tbm_bo_map(tbm_bo bo, int device, int opt)
426 {
427         tbm_bo_handle bo_handle;
428
429         _tbm_bo_mutex_lock();
430
431         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) NULL);
432
433         if (!_tbm_bo_lock(bo, device, opt)) {
434                 _tbm_set_last_result(TBM_BO_ERROR_LOCK_FAILED);
435                 TBM_LOG_E("error: fail to lock bo:%p)\n", bo);
436                 _tbm_bo_mutex_unlock();
437                 return (tbm_bo_handle) NULL;
438         }
439
440         bo_handle = bo->bufmgr->backend->bo_map(bo, device, opt);
441         if (bo_handle.ptr == NULL) {
442                 /* LCOV_EXCL_START */
443                 _tbm_set_last_result(TBM_BO_ERROR_MAP_FAILED);
444                 TBM_LOG_E("error: fail to map bo:%p\n", bo);
445                 _tbm_bo_unlock(bo);
446                 _tbm_bo_mutex_unlock();
447                 return (tbm_bo_handle) NULL;
448                 /* LCOV_EXCL_STOP */
449         }
450
451         /* increase the map_count */
452         bo->map_cnt++;
453
454         TBM_TRACE("bo(%p) map_cnt(%d)\n", bo, bo->map_cnt);
455
456         _tbm_bo_mutex_unlock();
457
458         return bo_handle;
459 }
460
461 int
462 tbm_bo_unmap(tbm_bo bo)
463 {
464         int ret;
465
466         _tbm_bo_mutex_lock();
467
468         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
469         TBM_BO_RETURN_VAL_IF_FAIL(bo->map_cnt > 0, 0);
470
471         ret = bo->bufmgr->backend->bo_unmap(bo);
472         if (!ret) {
473                 /* LCOV_EXCL_START */
474                 TBM_LOG_E("error: bo(%p) map_cnt(%d)\n", bo, bo->map_cnt);
475                 _tbm_set_last_result(TBM_BO_ERROR_UNMAP_FAILED);
476                 _tbm_bo_mutex_unlock();
477                 return ret;
478                 /* LCOV_EXCL_STOP */
479         }
480
481         /* decrease the map_count */
482         bo->map_cnt--;
483
484         TBM_TRACE("bo(%p) map_cnt(%d)\n", bo, bo->map_cnt);
485
486         _tbm_bo_unlock(bo);
487
488         _tbm_bo_mutex_unlock();
489
490         return ret;
491 }
492
493 tbm_bo_handle
494 tbm_bo_get_handle(tbm_bo bo, int device)
495 {
496         tbm_bo_handle bo_handle;
497
498         _tbm_bo_mutex_lock();
499
500         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) NULL);
501
502         bo_handle = bo->bufmgr->backend->bo_get_handle(bo, device);
503         if (bo_handle.ptr == NULL) {
504                 /* LCOV_EXCL_START */
505                 _tbm_set_last_result(TBM_BO_ERROR_GET_HANDLE_FAILED);
506                 TBM_LOG_E("error: bo(%p) bo_handle(%p)\n", bo, bo_handle.ptr);
507                 _tbm_bo_mutex_unlock();
508                 return (tbm_bo_handle) NULL;
509                 /* LCOV_EXCL_STOP */
510         }
511
512         TBM_TRACE("bo(%p) bo_handle(%p)\n", bo, bo_handle.ptr);
513
514         _tbm_bo_mutex_unlock();
515
516         return bo_handle;
517 }
518
519 tbm_key
520 tbm_bo_export(tbm_bo bo)
521 {
522         tbm_key ret;
523
524         _tbm_bo_mutex_lock();
525
526         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
527
528         if (!bo->bufmgr->backend->bo_export) {
529                 /* LCOV_EXCL_START */
530                 _tbm_bo_mutex_unlock();
531                 return 0;
532                 /* LCOV_EXCL_STOP */
533         }
534
535         ret = bo->bufmgr->backend->bo_export(bo);
536         if (!ret) {
537                 /* LCOV_EXCL_START */
538                 _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FAILED);
539                 TBM_LOG_E("error: bo(%p) tbm_key(%d)\n", bo, ret);
540                 _tbm_bo_mutex_unlock();
541                 return ret;
542                 /* LCOV_EXCL_STOP */
543         }
544
545         TBM_TRACE("bo(%p) tbm_key(%u)\n", bo, ret);
546
547         _tbm_bo_mutex_unlock();
548
549         return ret;
550 }
551
552 tbm_fd
553 tbm_bo_export_fd(tbm_bo bo)
554 {
555         tbm_fd ret;
556
557         _tbm_bo_mutex_lock();
558
559         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), -1);
560
561         if (!bo->bufmgr->backend->bo_export_fd) {
562                 /* LCOV_EXCL_START */
563                 _tbm_bo_mutex_unlock();
564                 return -1;
565                 /* LCOV_EXCL_STOP */
566         }
567
568         ret = bo->bufmgr->backend->bo_export_fd(bo);
569         if (ret < 0) {
570                 /* LCOV_EXCL_START */
571                 _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FD_FAILED);
572                 TBM_LOG_E("error: bo(%p) tbm_fd(%d)\n", bo, ret);
573                 _tbm_bo_mutex_unlock();
574                 return ret;
575                 /* LCOV_EXCL_STOP */
576         }
577
578         TBM_TRACE("bo(%p) tbm_fd(%d)\n", bo, ret);
579
580         _tbm_bo_mutex_unlock();
581
582         return ret;
583 }
584
585 tbm_bo
586 tbm_bo_import(tbm_bufmgr bufmgr, unsigned int key)
587 {
588         tbm_bo bo;
589         tbm_bo bo2 = NULL;
590         void *bo_priv;
591
592         _tbm_bo_mutex_lock();
593
594         TBM_BO_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
595
596         if (!bufmgr->backend->bo_import) {
597                 /* LCOV_EXCL_START */
598                 _tbm_bo_mutex_unlock();
599                 return NULL;
600                 /* LCOV_EXCL_STOP */
601         }
602
603         _tbm_util_check_bo_cnt(bufmgr);
604
605         bo = calloc(1, sizeof(struct _tbm_bo));
606         if (!bo) {
607                 /* LCOV_EXCL_START */
608                 TBM_LOG_E("error: fail to import of tbm_bo by key(%d)\n", key);
609                 _tbm_bo_mutex_unlock();
610                 return NULL;
611                 /* LCOV_EXCL_STOP */
612         }
613
614         bo->bufmgr = bufmgr;
615
616         bo_priv = bo->bufmgr->backend->bo_import(bo, key);
617         if (!bo_priv) {
618                 /* LCOV_EXCL_START */
619                 TBM_LOG_E("error: fail to import of tbm_bo by key(%d)\n", key);
620                 _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FAILED);
621                 free(bo);
622                 _tbm_bo_mutex_unlock();
623                 return NULL;
624                 /* LCOV_EXCL_STOP */
625         }
626
627         if (!LIST_IS_EMPTY(&bo->bufmgr->bo_list)) {
628                 LIST_FOR_EACH_ENTRY(bo2, &bo->bufmgr->bo_list, item_link) {
629                         if (bo2->priv == bo_priv) {
630                                 TBM_TRACE("find bo(%p) ref(%d) key(%d) flag(%s) in list\n",
631                                                 bo2, bo2->ref_cnt, key,
632                                                 _tbm_flag_to_str(bo2->flags));
633                                 bo2->ref_cnt++;
634                                 free(bo);
635                                 _tbm_bo_mutex_unlock();
636                                 return bo2;
637                         }
638                 }
639         }
640
641         bo->bufmgr->bo_cnt++;
642
643         bo->ref_cnt = 1;
644         bo->priv = bo_priv;
645
646         if (bo->bufmgr->backend->bo_get_flags)
647                 bo->flags = bo->bufmgr->backend->bo_get_flags(bo);
648         else
649                 bo->flags = TBM_BO_DEFAULT;
650
651         TBM_TRACE("import new bo(%p) ref(%d) key(%d) flag(%s) in list\n",
652                           bo, bo->ref_cnt, key, _tbm_flag_to_str(bo->flags));
653
654         LIST_INITHEAD(&bo->user_data_list);
655
656         LIST_ADD(&bo->item_link, &bo->bufmgr->bo_list);
657
658         _tbm_bo_mutex_unlock();
659
660         return bo;
661 }
662
663 tbm_bo
664 tbm_bo_import_fd(tbm_bufmgr bufmgr, tbm_fd fd)
665 {
666         tbm_bo bo;
667         tbm_bo bo2 = NULL;
668         void *bo_priv;
669
670         _tbm_bo_mutex_lock();
671
672         TBM_BO_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
673
674         if (!bufmgr->backend->bo_import_fd) {
675                 /* LCOV_EXCL_START */
676                 _tbm_bo_mutex_unlock();
677                 return NULL;
678                 /* LCOV_EXCL_STOP */
679         }
680
681         _tbm_util_check_bo_cnt(bufmgr);
682
683         bo = calloc(1, sizeof(struct _tbm_bo));
684         if (!bo) {
685                 /* LCOV_EXCL_START */
686                 TBM_LOG_E("error: fail to import tbm_bo by tbm_fd(%d)\n", fd);
687                 _tbm_bo_mutex_unlock();
688                 return NULL;
689                 /* LCOV_EXCL_STOP */
690         }
691
692         bo->bufmgr = bufmgr;
693
694         bo_priv = bo->bufmgr->backend->bo_import_fd(bo, fd);
695         if (!bo_priv) {
696                 /* LCOV_EXCL_START */
697                 TBM_LOG_E("error: fail to import tbm_bo by tbm_fd(%d)\n", fd);
698                 _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FD_FAILED);
699                 free(bo);
700                 _tbm_bo_mutex_unlock();
701                 return NULL;
702                 /* LCOV_EXCL_STOP */
703         }
704
705         if (!LIST_IS_EMPTY(&bo->bufmgr->bo_list)) {
706
707                 LIST_FOR_EACH_ENTRY(bo2, &bo->bufmgr->bo_list, item_link) {
708                         if (bo2->priv == bo_priv) {
709                                 TBM_TRACE("find bo(%p) ref(%d) fd(%d) flag(%s) in list\n",
710                                                 bo2, bo2->ref_cnt, fd,
711                                                 _tbm_flag_to_str(bo2->flags));
712                                 bo2->ref_cnt++;
713                                 free(bo);
714                                 _tbm_bo_mutex_unlock();
715                                 return bo2;
716                         }
717                 }
718         }
719
720         bo->bufmgr->bo_cnt++;
721
722         bo->ref_cnt = 1;
723         bo->priv = bo_priv;
724
725         if (bo->bufmgr->backend->bo_get_flags)
726                 bo->flags = bo->bufmgr->backend->bo_get_flags(bo);
727         else
728                 bo->flags = TBM_BO_DEFAULT;
729
730         TBM_TRACE("import bo(%p) ref(%d) fd(%d) flag(%s)\n",
731                         bo, bo->ref_cnt, fd, _tbm_flag_to_str(bo->flags));
732
733         LIST_INITHEAD(&bo->user_data_list);
734
735         LIST_ADD(&bo->item_link, &bo->bufmgr->bo_list);
736
737         _tbm_bo_mutex_unlock();
738
739         return bo;
740 }
741
742 int
743 tbm_bo_size(tbm_bo bo)
744 {
745         int size;
746
747         _tbm_bo_mutex_lock();
748
749         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
750
751         size = bo->bufmgr->backend->bo_size(bo);
752
753         TBM_TRACE("bo(%p) size(%d)\n", bo, size);
754
755         _tbm_bo_mutex_unlock();
756
757         return size;
758 }
759
760 int
761 tbm_bo_locked(tbm_bo bo)
762 {
763         _tbm_bo_mutex_lock();
764
765         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
766
767         if (bo->bufmgr->bo_lock_type == TBM_BUFMGR_BO_LOCK_TYPE_NEVER) {
768                 TBM_LOG_E("bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
769                 _tbm_bo_mutex_unlock();
770                 return 0;
771         }
772
773         if (bo->lock_cnt > 0) {
774                 TBM_TRACE("error: bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
775                 _tbm_bo_mutex_unlock();
776                 return 1;
777         }
778
779         TBM_TRACE("bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
780         _tbm_bo_mutex_unlock();
781
782         return 0;
783 }
784
785 int
786 tbm_bo_swap(tbm_bo bo1, tbm_bo bo2)
787 {
788         void *temp;
789
790         _tbm_bo_mutex_lock();
791
792         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo1), 0);
793         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo2), 0);
794
795         TBM_TRACE("before: bo1(%p) bo2(%p)\n", bo1, bo2);
796
797         if (bo1->bufmgr->backend->bo_size(bo1) != bo2->bufmgr->backend->bo_size(bo2)) {
798                 _tbm_set_last_result(TBM_BO_ERROR_SWAP_FAILED);
799                 TBM_LOG_E("error: bo1(%p) bo2(%p)\n", bo1, bo2);
800                 _tbm_bo_mutex_unlock();
801                 return 0;
802         }
803
804         TBM_TRACE("after: bo1(%p) bo2(%p)\n", bo1, bo2);
805
806         temp = bo1->priv;
807         bo1->priv = bo2->priv;
808         bo2->priv = temp;
809
810         _tbm_bo_mutex_unlock();
811
812         return 1;
813 }
814
815 int
816 tbm_bo_add_user_data(tbm_bo bo, unsigned long key,
817                      tbm_data_free data_free_func)
818 {
819         tbm_user_data *data;
820
821         _tbm_bo_mutex_lock();
822
823         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
824
825         /* check if the data according to the key exist if so, return false. */
826         data = user_data_lookup(&bo->user_data_list, key);
827         if (data) {
828                 TBM_TRACE("warning: user data already exist key(%ld)\n", key);
829                 _tbm_bo_mutex_unlock();
830                 return 0;
831         }
832
833         data = user_data_create(key, data_free_func);
834         if (!data) {
835                 TBM_LOG_E("error: bo(%p) key(%lu)\n", bo, key);
836                 _tbm_bo_mutex_unlock();
837                 return 0;
838         }
839
840         TBM_TRACE("bo(%p) key(%lu) data(%p)\n", bo, key, data->data);
841
842         LIST_ADD(&data->item_link, &bo->user_data_list);
843
844         _tbm_bo_mutex_unlock();
845
846         return 1;
847 }
848
849 int
850 tbm_bo_delete_user_data(tbm_bo bo, unsigned long key)
851 {
852         tbm_user_data *old_data;
853
854         _tbm_bo_mutex_lock();
855
856         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
857
858         if (LIST_IS_EMPTY(&bo->user_data_list)) {
859                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
860                 _tbm_bo_mutex_unlock();
861                 return 0;
862         }
863
864         old_data = user_data_lookup(&bo->user_data_list, key);
865         if (!old_data) {
866                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
867                 _tbm_bo_mutex_unlock();
868                 return 0;
869         }
870
871         TBM_TRACE("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
872
873         user_data_delete(old_data);
874
875         _tbm_bo_mutex_unlock();
876
877         return 1;
878 }
879
880 int
881 tbm_bo_set_user_data(tbm_bo bo, unsigned long key, void *data)
882 {
883         tbm_user_data *old_data;
884
885         _tbm_bo_mutex_lock();
886
887         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
888
889         if (LIST_IS_EMPTY(&bo->user_data_list)) {
890                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
891                 _tbm_bo_mutex_unlock();
892                 return 0;
893         }
894
895         old_data = user_data_lookup(&bo->user_data_list, key);
896         if (!old_data) {
897                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
898                 _tbm_bo_mutex_unlock();
899                 return 0;
900         }
901
902         if (old_data->data && old_data->free_func)
903                 old_data->free_func(old_data->data);
904         old_data->data = data;
905
906         TBM_TRACE("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
907
908         _tbm_bo_mutex_unlock();
909
910         return 1;
911 }
912
913 int
914 tbm_bo_get_user_data(tbm_bo bo, unsigned long key, void **data)
915 {
916         tbm_user_data *old_data;
917
918         _tbm_bo_mutex_lock();
919
920         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
921
922         if (!data || LIST_IS_EMPTY(&bo->user_data_list)) {
923                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
924                 _tbm_bo_mutex_unlock();
925                 return 0;
926         }
927
928         old_data = user_data_lookup(&bo->user_data_list, key);
929         if (!old_data) {
930                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
931                 *data = NULL;
932                 _tbm_bo_mutex_unlock();
933                 return 0;
934         }
935
936         *data = old_data->data;
937
938         TBM_TRACE("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
939
940         _tbm_bo_mutex_unlock();
941
942         return 1;
943 }
944
945 /* LCOV_EXCL_START */
946 tbm_error_e
947 tbm_get_last_error(void)
948 {
949         return tbm_last_error;
950 }
951 /* LCOV_EXCL_STOP */
952
953 int
954 tbm_bo_get_flags(tbm_bo bo)
955 {
956         int flags;
957
958         _tbm_bo_mutex_lock();
959
960         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
961
962         flags = bo->flags;
963
964         TBM_TRACE("bo(%p)\n", bo);
965
966         _tbm_bo_mutex_unlock();
967
968         return flags;
969 }
970
971 /* LCOV_EXCL_START */
972 /* internal function */
973 int
974 _tbm_bo_set_surface(tbm_bo bo, tbm_surface_h surface)
975 {
976         _tbm_bo_mutex_lock();
977
978         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
979
980         bo->surface = surface;
981
982         _tbm_bo_mutex_unlock();
983
984         return 1;
985 }
986
987 void
988 _tbm_bo_free(tbm_bo bo)
989 {
990         /* destory the user_data_list */
991         if (!LIST_IS_EMPTY(&bo->user_data_list)) {
992                 tbm_user_data *old_data = NULL, *tmp;
993
994                 LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp,
995                                 &bo->user_data_list, item_link) {
996                         TBM_DBG("free user_data\n");
997                         user_data_delete(old_data);
998                 }
999         }
1000
1001         while (bo->lock_cnt > 0) {
1002                 TBM_LOG_E("error lock_cnt:%d\n", bo->lock_cnt);
1003                 _bo_unlock(bo);
1004                 bo->lock_cnt--;
1005         }
1006
1007         /* call the bo_free */
1008         bo->bufmgr->backend->bo_free(bo);
1009         bo->priv = NULL;
1010
1011         bo->bufmgr->bo_cnt--;
1012
1013         LIST_DEL(&bo->item_link);
1014         free(bo);
1015 }
1016 /* LCOV_EXCL_STOP */