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