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