42552fb472d0a7832ecc77e0df63f4d54ed14eec
[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 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 /* LCOV_EXCL_STOP */
90
91 tbm_user_data *
92 user_data_lookup(struct list_head *user_data_list, unsigned long key)
93 {
94         tbm_user_data *old_data = NULL;
95
96         if (LIST_IS_EMPTY(user_data_list))
97                 return NULL;
98
99         LIST_FOR_EACH_ENTRY(old_data, user_data_list, item_link) {
100                 if (old_data->key == key)
101                         return old_data;
102         }
103
104         return NULL;
105 }
106
107 tbm_user_data *
108 user_data_create(unsigned long key, tbm_data_free data_free_func)
109 {
110         tbm_user_data *user_data;
111
112         user_data = calloc(1, sizeof(tbm_user_data));
113         if (!user_data) {
114                 /* LCOV_EXCL_START */
115                 TBM_ERR("fail to allocate an user_date\n");
116                 _tbm_set_last_result(TBM_ERROR_OUT_OF_MEMORY);
117                 return NULL;
118                 /* LCOV_EXCL_STOP */
119         }
120
121         user_data->key = key;
122         user_data->free_func = data_free_func;
123
124         return user_data;
125 }
126
127 void
128 user_data_delete(tbm_user_data *user_data)
129 {
130         if (user_data->data && user_data->free_func)
131                 user_data->free_func(user_data->data);
132
133         LIST_DEL(&user_data->item_link);
134
135         free(user_data);
136 }
137
138 static int
139 _bo_lock(tbm_bo bo, int device, int opt)
140 {
141         tbm_error_e error;
142         int ret;
143
144         error = tbm_bo_data_lock(bo->bo_data, device, opt);
145         _tbm_set_last_result(error);
146         switch(error) {
147                 case TBM_ERROR_NONE:
148                         ret = 1;
149                         break;
150                 case TBM_ERROR_NOT_SUPPORTED:
151                         ret = 1;
152                         _tbm_set_last_result(TBM_ERROR_NONE);
153                         break;
154                 default:
155                         ret = 0;
156                         TBM_WRN("fail to lock. error:%d", error);
157                         break;
158         }
159
160         return ret;
161 }
162
163 static void
164 _bo_unlock(tbm_bo bo)
165 {
166         tbm_error_e error;
167
168         error = tbm_bo_data_unlock(bo->bo_data);
169         _tbm_set_last_result(error);
170         switch(error) {
171                 case TBM_ERROR_NONE:
172                         break;
173                 case TBM_ERROR_NOT_SUPPORTED:
174                         _tbm_set_last_result(TBM_ERROR_NONE);
175                         break;
176                 default:
177                         TBM_WRN("fail to lock. error:%d", error);
178                         break;
179         }
180 }
181
182 static int
183 _tbm_bo_lock(tbm_bo bo, int device, int opt)
184 {
185         int old, ret;
186
187         if (!bo)
188                 return 0;
189
190         /* do not try to lock the bo */
191         if (bo->bufmgr->bo_lock_type == TBM_BUFMGR_BO_LOCK_TYPE_NEVER)
192                 return 1;
193
194         if (bo->lock_cnt < 0) {
195                 TBM_ERR("error bo:%p LOCK_CNT=%d\n",
196                         bo, bo->lock_cnt);
197                 return 0;
198         }
199
200         old = bo->lock_cnt;
201
202         switch (bo->bufmgr->bo_lock_type) {
203         case TBM_BUFMGR_BO_LOCK_TYPE_ONCE:
204                 if (bo->lock_cnt == 0) {
205                         _tbm_bufmgr_mutex_unlock();
206                         ret = _bo_lock(bo, device, opt);
207                         _tbm_bufmgr_mutex_lock();
208                         if (ret)
209                                 bo->lock_cnt++;
210                 } else
211                         ret = 1;
212                 break;
213         case TBM_BUFMGR_BO_LOCK_TYPE_ALWAYS:
214                 _tbm_bufmgr_mutex_unlock();
215                 ret = _bo_lock(bo, device, opt);
216                 _tbm_bufmgr_mutex_lock();
217                 if (ret)
218                         bo->lock_cnt++;
219                 break;
220         default:
221                 TBM_ERR("error bo:%p bo_lock_type[%d] is wrong.\n",
222                                 bo, bo->bufmgr->bo_lock_type);
223                 ret = 0;
224                 break;
225         }
226
227         TBM_DBG(">> LOCK bo:%p(%d->%d)\n", bo, old, bo->lock_cnt);
228
229         return ret;
230 }
231
232 static void
233 _tbm_bo_unlock(tbm_bo bo)
234 {
235         int old;
236
237         /* do not try to unlock the bo */
238         if (bo->bufmgr->bo_lock_type == TBM_BUFMGR_BO_LOCK_TYPE_NEVER)
239                 return;
240
241         old = bo->lock_cnt;
242
243         switch (bo->bufmgr->bo_lock_type) {
244         case TBM_BUFMGR_BO_LOCK_TYPE_ONCE:
245                 if (bo->lock_cnt > 0) {
246                         bo->lock_cnt--;
247                         if (bo->lock_cnt == 0)
248                                 _bo_unlock(bo);
249                 }
250                 break;
251         case TBM_BUFMGR_BO_LOCK_TYPE_ALWAYS:
252                 if (bo->lock_cnt > 0) {
253                         bo->lock_cnt--;
254                         _bo_unlock(bo);
255                 }
256                 break;
257         default:
258                 TBM_ERR("error bo:%p bo_lock_type[%d] is wrong.\n",
259                                 bo, bo->bufmgr->bo_lock_type);
260                 break;
261         }
262
263         if (bo->lock_cnt < 0)
264                 bo->lock_cnt = 0;
265
266         TBM_DBG(">> UNLOCK bo:%p(%d->%d)\n", bo, old, bo->lock_cnt);
267 }
268
269 static int
270 _tbm_bo_magic_check(tbm_bo bo)
271 {
272         if (bo->magic != TBM_BO_MAGIC)
273                 return 0;
274
275         return 1;
276 }
277
278 static int
279 _tbm_bo_is_valid(tbm_bo bo)
280 {
281         if (!bo) {
282                 TBM_ERR("error: bo is NULL.\n");
283                 return 0;
284         }
285
286         if (!_tbm_bo_magic_check(bo)) {
287                 TBM_ERR("error: No valid bo(%p).\n", bo);
288                 return 0;
289         }
290
291         return 1;
292 }
293
294 static void
295 _tbm_bo_deinit(tbm_bo bo)
296 {
297         bo->magic = 0;
298
299         bo->bufmgr->bo_cnt--;
300         LIST_DEL(&bo->item_link);
301 }
302
303 tbm_bo
304 tbm_bo_alloc(tbm_bufmgr bufmgr, int size, int flags)
305 {
306         tbm_bo bo;
307         tbm_error_e error;
308
309         _tbm_bufmgr_mutex_lock();
310         _tbm_set_last_result(TBM_ERROR_NONE);
311
312         TBM_BO_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
313         TBM_BO_RETURN_VAL_IF_FAIL(size > 0, NULL);
314
315         bo = tbm_bufmgr_internal_alloc_bo(bufmgr, size, flags, &error);
316         if (!bo) {
317                 /* LCOV_EXCL_START */
318                 TBM_ERR("tbm_bufmgr_internal_alloc_bo failed. error:%d", error);
319                 _tbm_set_last_result(error);
320                 _tbm_bufmgr_mutex_unlock();
321                 return NULL;
322                 /* LCOV_EXCL_STOP */
323         }
324
325         TBM_TRACE_BO("bo(%p) size(%d) refcnt(%d), flag(%s)\n", bo, size, bo->ref_cnt,
326                         _tbm_flag_to_str(bo->flags));
327
328         _tbm_bufmgr_mutex_unlock();
329
330         return bo;
331 }
332
333 tbm_bo
334 tbm_bo_ref(tbm_bo bo)
335 {
336         _tbm_bufmgr_mutex_lock();
337         _tbm_set_last_result(TBM_ERROR_NONE);
338
339         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), NULL);
340
341         bo->ref_cnt++;
342
343         TBM_TRACE_BO("bo(%p) ref_cnt(%d)\n", bo, bo->ref_cnt);
344
345         _tbm_bufmgr_mutex_unlock();
346
347         return bo;
348 }
349
350 void
351 tbm_bo_unref(tbm_bo bo)
352 {
353         _tbm_bufmgr_mutex_lock();
354         _tbm_set_last_result(TBM_ERROR_NONE);
355
356         TBM_BO_RETURN_IF_FAIL(_tbm_bo_is_valid(bo));
357
358         TBM_TRACE_BO("bo(%p) ref_cnt(%d)\n", bo, bo->ref_cnt - 1);
359
360         if (bo->ref_cnt <= 0) {
361                 _tbm_bufmgr_mutex_unlock();
362                 return;
363         }
364
365         bo->ref_cnt--;
366         if (bo->ref_cnt == 0)
367                 _tbm_bo_free(bo);
368
369         _tbm_bufmgr_mutex_unlock();
370 }
371
372 tbm_bo_handle
373 tbm_bo_map(tbm_bo bo, int device, int opt)
374 {
375         tbm_bo_handle bo_handle;
376         tbm_error_e error;
377
378         _tbm_bufmgr_mutex_lock();
379         _tbm_set_last_result(TBM_ERROR_NONE);
380
381         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) NULL);
382
383         if (!_tbm_bo_lock(bo, device, opt)) {
384                 TBM_ERR("error: fail to lock bo:%p)\n", bo);
385                 _tbm_bufmgr_mutex_unlock();
386                 return (tbm_bo_handle) NULL;
387         }
388
389         bo_handle = tbm_bo_data_map(bo->bo_data, device, opt, &error);
390         if (bo_handle.ptr == NULL) {
391                 /* LCOV_EXCL_START */
392                 TBM_ERR("error: fail to map bo:%p error:%d\n", bo, error);
393                 _tbm_set_last_result(error);
394                 _tbm_bo_unlock(bo);
395                 _tbm_bufmgr_mutex_unlock();
396                 return (tbm_bo_handle) NULL;
397                 /* LCOV_EXCL_STOP */
398         }
399
400         /* increase the map_count */
401         bo->map_cnt++;
402
403         TBM_TRACE_BO("bo(%p) map_cnt(%d)\n", bo, bo->map_cnt);
404
405         _tbm_bufmgr_mutex_unlock();
406
407         return bo_handle;
408 }
409
410 int
411 tbm_bo_unmap(tbm_bo bo)
412 {
413         tbm_error_e error;
414
415         _tbm_bufmgr_mutex_lock();
416         _tbm_set_last_result(TBM_ERROR_NONE);
417
418         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
419         TBM_BO_RETURN_VAL_IF_FAIL(bo->map_cnt > 0, 0);
420
421         error = tbm_bo_data_unmap(bo->bo_data);
422         if (error != TBM_ERROR_NONE) {
423                 /* LCOV_EXCL_START */
424                 TBM_ERR("error: bo(%p) map_cnt(%d) error(%d)\n", bo, bo->map_cnt, error);
425                 _tbm_set_last_result(error);
426                 _tbm_bufmgr_mutex_unlock();
427                 return 0;
428                 /* LCOV_EXCL_STOP */
429         }
430
431         /* decrease the map_count */
432         bo->map_cnt--;
433
434         TBM_TRACE_BO("bo(%p) map_cnt(%d)\n", bo, bo->map_cnt);
435
436         _tbm_bo_unlock(bo);
437
438         _tbm_bufmgr_mutex_unlock();
439
440         return 1;
441 }
442
443 tbm_bo_handle
444 tbm_bo_get_handle(tbm_bo bo, int device)
445 {
446         tbm_bo_handle bo_handle;
447         tbm_error_e error;
448
449         _tbm_bufmgr_mutex_lock();
450         _tbm_set_last_result(TBM_ERROR_NONE);
451
452         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) NULL);
453
454         bo_handle = tbm_bo_data_get_handle(bo->bo_data, device, &error);
455         if (bo_handle.ptr == NULL) {
456                 /* LCOV_EXCL_START */
457                 TBM_ERR("error: bo(%p) bo_handle(%p) error(%d)\n", bo, bo_handle.ptr, error);
458                 _tbm_set_last_result(error);
459                 _tbm_bufmgr_mutex_unlock();
460                 return (tbm_bo_handle)NULL;
461                 /* LCOV_EXCL_STOP */
462         }
463
464         TBM_TRACE_BO("bo(%p) bo_handle(%p)\n", bo, bo_handle.ptr);
465
466         _tbm_bufmgr_mutex_unlock();
467
468         return bo_handle;
469 }
470
471 tbm_key
472 tbm_bo_export(tbm_bo bo)
473 {
474         tbm_key ret;
475         tbm_error_e error;
476
477         _tbm_bufmgr_mutex_lock();
478         _tbm_set_last_result(TBM_ERROR_NONE);
479
480         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
481
482         ret = tbm_bo_data_export_key(bo->bo_data, &error);
483         if (!ret) {
484                 /* LCOV_EXCL_START */
485                 TBM_ERR("tbm_moule_bo_export_key failed. bo:%p tbm_key:%d error:%d", bo, ret, error);
486                 _tbm_set_last_result(error);
487                 _tbm_bufmgr_mutex_unlock();
488                 return ret;
489                 /* LCOV_EXCL_STOP */
490         }
491
492         TBM_TRACE_BO("bo:%p tbm_key:%u", bo, ret);
493
494         _tbm_bufmgr_mutex_unlock();
495
496         return ret;
497 }
498
499 tbm_fd
500 tbm_bo_export_fd(tbm_bo bo)
501 {
502         tbm_fd fd;
503         tbm_error_e error;
504
505         _tbm_bufmgr_mutex_lock();
506         _tbm_set_last_result(TBM_ERROR_NONE);
507
508         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), -1);
509
510         fd = tbm_bo_data_export_fd(bo->bo_data, &error);
511         if (fd < 0) {
512                 /* LCOV_EXCL_START */
513                 TBM_ERR("tbm_bo_data_export_fd filed. bo:%p tbm_fd:%d error:%d", bo, fd, error);
514                 _tbm_set_last_result(error);
515                 _tbm_bufmgr_mutex_unlock();
516                 return fd;
517                 /* LCOV_EXCL_STOP */
518         }
519
520         TBM_TRACE_BO("bo:%p tbm_fd:%d", bo, fd);
521
522         _tbm_bufmgr_mutex_unlock();
523
524         return fd;
525 }
526
527 tbm_bo
528 tbm_bo_import(tbm_bufmgr bufmgr, unsigned int key)
529 {
530         tbm_bo bo;
531
532         bo = tbm_bufmgr_internal_import_bo_with_key(bufmgr, key);
533         if (!bo) {
534                 /* LCOV_EXCL_START */
535                 TBM_ERR("tbm_bufmgr_internal_import_bo_with_key failed");
536                 return NULL;
537                 /* LCOV_EXCL_STOP */
538         }
539
540         return bo;
541 }
542
543 tbm_bo
544 tbm_bo_import_fd(tbm_bufmgr bufmgr, tbm_fd fd)
545 {
546         tbm_bo bo;
547
548         bo = tbm_bufmgr_internal_import_bo_with_fd(bufmgr, fd);
549         if (!bo) {
550                 /* LCOV_EXCL_START */
551                 TBM_ERR("tbm_bufmgr_internal_import_fd failed.");
552                 return NULL;
553                 /* LCOV_EXCL_STOP */
554         }
555
556         return bo;
557 }
558
559 int
560 tbm_bo_size(tbm_bo bo)
561 {
562         int size;
563         tbm_error_e error;
564
565         _tbm_bufmgr_mutex_lock();
566         _tbm_set_last_result(TBM_ERROR_NONE);
567
568         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
569
570         size = tbm_bo_data_get_size(bo->bo_data, &error);
571         _tbm_set_last_result(error);
572
573         TBM_TRACE_BO("bo(%p) size(%d)\n", bo, size);
574
575         _tbm_bufmgr_mutex_unlock();
576
577         return size;
578 }
579
580 int
581 tbm_bo_locked(tbm_bo bo)
582 {
583         _tbm_bufmgr_mutex_lock();
584         _tbm_set_last_result(TBM_ERROR_NONE);
585
586         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
587
588         if (bo->bufmgr->bo_lock_type == TBM_BUFMGR_BO_LOCK_TYPE_NEVER) {
589                 TBM_ERR("bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
590                 _tbm_set_last_result(TBM_ERROR_INVALID_OPERATION);
591                 _tbm_bufmgr_mutex_unlock();
592                 return 0;
593         }
594
595         if (bo->lock_cnt > 0) {
596                 TBM_TRACE_BO("error: bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
597                 _tbm_bufmgr_mutex_unlock();
598                 return 1;
599         }
600
601         TBM_TRACE_BO("bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
602         _tbm_bufmgr_mutex_unlock();
603
604         return 0;
605 }
606
607 int
608 tbm_bo_swap(tbm_bo bo1, tbm_bo bo2)
609 {
610         tbm_error_e error1, error2;
611         int size1 = -1, size2 = -2;
612         void *temp;
613
614         _tbm_bufmgr_mutex_lock();
615         _tbm_set_last_result(TBM_ERROR_NONE);
616
617         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo1), 0);
618         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo2), 0);
619
620         TBM_TRACE_BO("before: bo1(%p) bo2(%p)\n", bo1, bo2);
621
622         size1 = tbm_bo_data_get_size(bo1->bo_data, &error1);
623         _tbm_set_last_result(error1);
624         size2 = tbm_bo_data_get_size(bo2->bo_data, &error2);
625         _tbm_set_last_result(error2);
626
627         if (size1 != size2) {
628                 TBM_ERR("error: bo1 size(%d) and bo2 size(%d) is different.", size1, size2);
629                 _tbm_set_last_result(TBM_ERROR_INVALID_OPERATION);
630                 goto fail;
631         }
632
633         temp = bo1->bo_data;
634         bo1->bo_data = bo2->bo_data;
635         bo2->bo_data = temp;
636
637         TBM_TRACE_BO("after: bo1(%p) bo2(%p)\n", bo1, bo2);
638
639         _tbm_bufmgr_mutex_unlock();
640
641         return 1;
642
643 fail:
644         TBM_ERR("error: bo1(%p) bo2(%p)\n", bo1, bo2);
645         _tbm_bufmgr_mutex_unlock();
646
647         return 0;
648 }
649
650 int
651 tbm_bo_add_user_data(tbm_bo bo, unsigned long key,
652                      tbm_data_free data_free_func)
653 {
654         tbm_user_data *data;
655
656         _tbm_bufmgr_mutex_lock();
657         _tbm_set_last_result(TBM_ERROR_NONE);
658
659         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
660
661         /* check if the data according to the key exist if so, return false. */
662         data = user_data_lookup(&bo->user_data_list, key);
663         if (data) {
664                 TBM_TRACE_BO("warning: user data already exist key(%ld)\n", key);
665                 _tbm_set_last_result(TBM_ERROR_INVALID_PARAMETER);
666                 _tbm_bufmgr_mutex_unlock();
667                 return 0;
668         }
669
670         data = user_data_create(key, data_free_func);
671         if (!data) {
672                 TBM_ERR("error: bo(%p) key(%lu)\n", bo, key);
673                 _tbm_set_last_result(TBM_ERROR_INVALID_PARAMETER);
674                 _tbm_bufmgr_mutex_unlock();
675                 return 0;
676         }
677
678         TBM_TRACE_BO("bo(%p) key(%lu) data(%p)\n", bo, key, data->data);
679
680         LIST_ADD(&data->item_link, &bo->user_data_list);
681
682         _tbm_bufmgr_mutex_unlock();
683
684         return 1;
685 }
686
687 int
688 tbm_bo_delete_user_data(tbm_bo bo, unsigned long key)
689 {
690         tbm_user_data *old_data;
691
692         _tbm_bufmgr_mutex_lock();
693         _tbm_set_last_result(TBM_ERROR_NONE);
694
695         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
696
697         if (LIST_IS_EMPTY(&bo->user_data_list)) {
698                 TBM_TRACE_BO("bo(%p) key(%lu)\n", bo, key);
699                 _tbm_set_last_result(TBM_ERROR_INVALID_PARAMETER);
700                 _tbm_bufmgr_mutex_unlock();
701                 return 0;
702         }
703
704         old_data = user_data_lookup(&bo->user_data_list, key);
705         if (!old_data) {
706                 TBM_TRACE_BO("bo(%p) key(%lu)\n", bo, key);
707                 _tbm_set_last_result(TBM_ERROR_INVALID_PARAMETER);
708                 _tbm_bufmgr_mutex_unlock();
709                 return 0;
710         }
711
712         TBM_TRACE_BO("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
713
714         user_data_delete(old_data);
715
716         _tbm_bufmgr_mutex_unlock();
717
718         return 1;
719 }
720
721 int
722 tbm_bo_set_user_data(tbm_bo bo, unsigned long key, void *data)
723 {
724         tbm_user_data *old_data;
725
726         _tbm_bufmgr_mutex_lock();
727         _tbm_set_last_result(TBM_ERROR_NONE);
728
729         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
730
731         if (LIST_IS_EMPTY(&bo->user_data_list)) {
732                 TBM_TRACE_BO("error: bo(%p) key(%lu)\n", bo, key);
733                 _tbm_set_last_result(TBM_ERROR_INVALID_PARAMETER);
734                 _tbm_bufmgr_mutex_unlock();
735                 return 0;
736         }
737
738         old_data = user_data_lookup(&bo->user_data_list, key);
739         if (!old_data) {
740                 TBM_TRACE_BO("error: bo(%p) key(%lu)\n", bo, key);
741                 _tbm_set_last_result(TBM_ERROR_INVALID_PARAMETER);
742                 _tbm_bufmgr_mutex_unlock();
743                 return 0;
744         }
745
746         if (old_data->data && old_data->free_func)
747                 old_data->free_func(old_data->data);
748         old_data->data = data;
749
750         TBM_TRACE_BO("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
751
752         _tbm_bufmgr_mutex_unlock();
753
754         return 1;
755 }
756
757 int
758 tbm_bo_get_user_data(tbm_bo bo, unsigned long key, void **data)
759 {
760         tbm_user_data *old_data;
761
762         _tbm_bufmgr_mutex_lock();
763         _tbm_set_last_result(TBM_ERROR_NONE);
764
765         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
766
767         if (!data || LIST_IS_EMPTY(&bo->user_data_list)) {
768                 TBM_TRACE_BO("error: bo(%p) key(%lu)\n", bo, key);
769                 _tbm_set_last_result(TBM_ERROR_INVALID_PARAMETER);
770                 _tbm_bufmgr_mutex_unlock();
771                 return 0;
772         }
773
774         old_data = user_data_lookup(&bo->user_data_list, key);
775         if (!old_data) {
776                 *data = NULL;
777                 TBM_TRACE_BO("error: bo(%p) key(%lu)\n", bo, key);
778                 _tbm_set_last_result(TBM_ERROR_INVALID_PARAMETER);
779                 _tbm_bufmgr_mutex_unlock();
780                 return 0;
781         }
782
783         *data = old_data->data;
784
785         TBM_TRACE_BO("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
786
787         _tbm_bufmgr_mutex_unlock();
788
789         return 1;
790 }
791
792 int
793 tbm_bo_get_flags(tbm_bo bo)
794 {
795         int flags;
796
797         _tbm_bufmgr_mutex_lock();
798
799         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
800
801         flags = bo->flags;
802
803         TBM_TRACE_BO("bo(%p)\n", bo);
804
805         _tbm_bufmgr_mutex_unlock();
806
807         return flags;
808 }
809
810 /* LCOV_EXCL_START */
811 /* internal function */
812 int
813 _tbm_bo_set_surface(tbm_bo bo, tbm_surface_h surface)
814 {
815         _tbm_bufmgr_mutex_lock();
816
817         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
818
819         bo->surface = surface;
820
821         _tbm_bufmgr_mutex_unlock();
822
823         return 1;
824 }
825
826 void
827 _tbm_bo_free(tbm_bo bo)
828 {
829         /* destory the user_data_list */
830         if (!LIST_IS_EMPTY(&bo->user_data_list)) {
831                 tbm_user_data *old_data = NULL, *tmp;
832
833                 LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp, &bo->user_data_list, item_link) {
834                         TBM_DBG("free user_data\n");
835                         user_data_delete(old_data);
836                 }
837
838                 LIST_INITHEAD(&bo->user_data_list); // TODO: remove this. build-break when it is removed.
839         }
840
841         while (bo->lock_cnt > 0) {
842                 TBM_ERR("error lock_cnt:%d\n", bo->lock_cnt);
843                 _bo_unlock(bo);
844                 bo->lock_cnt--;
845         }
846
847         tbm_bo_data_free(bo->bo_data, bo->get_from_surface_data);
848
849         _tbm_bo_deinit(bo);
850
851         free(bo);
852 }
853 /* LCOV_EXCL_STOP */