tbm_bufmgr: lock/unlock tbm_bufmgr_mutex at tbm_bufmgr function
[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
308         bo = tbm_bufmgr_internal_alloc_bo(bufmgr, size, flags);
309         if (!bo) {
310                 /* LCOV_EXCL_START */
311                 TBM_ERR("tbm_bufmgr_internal_alloc_bo failed.");
312                 return NULL;
313                 /* LCOV_EXCL_STOP */
314         }
315
316         return bo;
317 }
318
319 tbm_bo
320 tbm_bo_ref(tbm_bo bo)
321 {
322         _tbm_bufmgr_mutex_lock();
323         _tbm_set_last_result(TBM_ERROR_NONE);
324
325         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), NULL);
326
327         bo->ref_cnt++;
328
329         TBM_TRACE_BO("bo(%p) ref_cnt(%d)\n", bo, bo->ref_cnt);
330
331         _tbm_bufmgr_mutex_unlock();
332
333         return bo;
334 }
335
336 void
337 tbm_bo_unref(tbm_bo bo)
338 {
339         _tbm_bufmgr_mutex_lock();
340         _tbm_set_last_result(TBM_ERROR_NONE);
341
342         TBM_BO_RETURN_IF_FAIL(_tbm_bo_is_valid(bo));
343
344         TBM_TRACE_BO("bo(%p) ref_cnt(%d)\n", bo, bo->ref_cnt - 1);
345
346         if (bo->ref_cnt <= 0) {
347                 _tbm_bufmgr_mutex_unlock();
348                 return;
349         }
350
351         bo->ref_cnt--;
352         if (bo->ref_cnt == 0)
353                 _tbm_bo_free(bo);
354
355         _tbm_bufmgr_mutex_unlock();
356 }
357
358 tbm_bo_handle
359 tbm_bo_map(tbm_bo bo, int device, int opt)
360 {
361         tbm_bo_handle bo_handle;
362         tbm_error_e error;
363
364         _tbm_bufmgr_mutex_lock();
365         _tbm_set_last_result(TBM_ERROR_NONE);
366
367         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) NULL);
368
369         if (!_tbm_bo_lock(bo, device, opt)) {
370                 TBM_ERR("error: fail to lock bo:%p)\n", bo);
371                 _tbm_bufmgr_mutex_unlock();
372                 return (tbm_bo_handle) NULL;
373         }
374
375         bo_handle = tbm_bo_data_map(bo->bo_data, device, opt, &error);
376         if (bo_handle.ptr == NULL) {
377                 /* LCOV_EXCL_START */
378                 TBM_ERR("error: fail to map bo:%p error:%d\n", bo, error);
379                 _tbm_set_last_result(error);
380                 _tbm_bo_unlock(bo);
381                 _tbm_bufmgr_mutex_unlock();
382                 return (tbm_bo_handle) NULL;
383                 /* LCOV_EXCL_STOP */
384         }
385
386         /* increase the map_count */
387         bo->map_cnt++;
388
389         TBM_TRACE_BO("bo(%p) map_cnt(%d)\n", bo, bo->map_cnt);
390
391         _tbm_bufmgr_mutex_unlock();
392
393         return bo_handle;
394 }
395
396 int
397 tbm_bo_unmap(tbm_bo bo)
398 {
399         tbm_error_e error;
400
401         _tbm_bufmgr_mutex_lock();
402         _tbm_set_last_result(TBM_ERROR_NONE);
403
404         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
405         TBM_BO_RETURN_VAL_IF_FAIL(bo->map_cnt > 0, 0);
406
407         error = tbm_bo_data_unmap(bo->bo_data);
408         if (error != TBM_ERROR_NONE) {
409                 /* LCOV_EXCL_START */
410                 TBM_ERR("error: bo(%p) map_cnt(%d) error(%d)\n", bo, bo->map_cnt, error);
411                 _tbm_set_last_result(error);
412                 _tbm_bufmgr_mutex_unlock();
413                 return 0;
414                 /* LCOV_EXCL_STOP */
415         }
416
417         /* decrease the map_count */
418         bo->map_cnt--;
419
420         TBM_TRACE_BO("bo(%p) map_cnt(%d)\n", bo, bo->map_cnt);
421
422         _tbm_bo_unlock(bo);
423
424         _tbm_bufmgr_mutex_unlock();
425
426         return 1;
427 }
428
429 tbm_bo_handle
430 tbm_bo_get_handle(tbm_bo bo, int device)
431 {
432         tbm_bo_handle bo_handle;
433         tbm_error_e error;
434
435         _tbm_bufmgr_mutex_lock();
436         _tbm_set_last_result(TBM_ERROR_NONE);
437
438         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) NULL);
439
440         bo_handle = tbm_bo_data_get_handle(bo->bo_data, device, &error);
441         if (bo_handle.ptr == NULL) {
442                 /* LCOV_EXCL_START */
443                 TBM_ERR("error: bo(%p) bo_handle(%p) error(%d)\n", bo, bo_handle.ptr, error);
444                 _tbm_set_last_result(error);
445                 _tbm_bufmgr_mutex_unlock();
446                 return (tbm_bo_handle)NULL;
447                 /* LCOV_EXCL_STOP */
448         }
449
450         TBM_TRACE_BO("bo(%p) bo_handle(%p)\n", bo, bo_handle.ptr);
451
452         _tbm_bufmgr_mutex_unlock();
453
454         return bo_handle;
455 }
456
457 tbm_key
458 tbm_bo_export(tbm_bo bo)
459 {
460         tbm_key ret;
461         tbm_error_e error;
462
463         _tbm_bufmgr_mutex_lock();
464         _tbm_set_last_result(TBM_ERROR_NONE);
465
466         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
467
468         ret = tbm_bo_data_export_key(bo->bo_data, &error);
469         if (!ret) {
470                 /* LCOV_EXCL_START */
471                 TBM_ERR("tbm_moule_bo_export_key failed. bo:%p tbm_key:%d error:%d", bo, ret, error);
472                 _tbm_set_last_result(error);
473                 _tbm_bufmgr_mutex_unlock();
474                 return ret;
475                 /* LCOV_EXCL_STOP */
476         }
477
478         TBM_TRACE_BO("bo:%p tbm_key:%u", bo, ret);
479
480         _tbm_bufmgr_mutex_unlock();
481
482         return ret;
483 }
484
485 tbm_fd
486 tbm_bo_export_fd(tbm_bo bo)
487 {
488         tbm_fd fd;
489         tbm_error_e error;
490
491         _tbm_bufmgr_mutex_lock();
492         _tbm_set_last_result(TBM_ERROR_NONE);
493
494         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), -1);
495
496         fd = tbm_bo_data_export_fd(bo->bo_data, &error);
497         if (fd < 0) {
498                 /* LCOV_EXCL_START */
499                 TBM_ERR("tbm_bo_data_export_fd filed. bo:%p tbm_fd:%d error:%d", bo, fd, error);
500                 _tbm_set_last_result(error);
501                 _tbm_bufmgr_mutex_unlock();
502                 return fd;
503                 /* LCOV_EXCL_STOP */
504         }
505
506         TBM_TRACE_BO("bo:%p tbm_fd:%d", bo, fd);
507
508         _tbm_bufmgr_mutex_unlock();
509
510         return fd;
511 }
512
513 tbm_bo
514 tbm_bo_import(tbm_bufmgr bufmgr, unsigned int key)
515 {
516         tbm_bo bo;
517
518         bo = tbm_bufmgr_internal_import_bo_with_key(bufmgr, key);
519         if (!bo) {
520                 /* LCOV_EXCL_START */
521                 TBM_ERR("tbm_bufmgr_internal_import_bo_with_key failed");
522                 return NULL;
523                 /* LCOV_EXCL_STOP */
524         }
525
526         return bo;
527 }
528
529 tbm_bo
530 tbm_bo_import_fd(tbm_bufmgr bufmgr, tbm_fd fd)
531 {
532         tbm_bo bo;
533
534         bo = tbm_bufmgr_internal_import_bo_with_fd(bufmgr, fd);
535         if (!bo) {
536                 /* LCOV_EXCL_START */
537                 TBM_ERR("tbm_bufmgr_internal_import_fd failed.");
538                 return NULL;
539                 /* LCOV_EXCL_STOP */
540         }
541
542         return bo;
543 }
544
545 int
546 tbm_bo_size(tbm_bo bo)
547 {
548         int size;
549         tbm_error_e error;
550
551         _tbm_bufmgr_mutex_lock();
552         _tbm_set_last_result(TBM_ERROR_NONE);
553
554         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
555
556         size = tbm_bo_data_get_size(bo->bo_data, &error);
557         _tbm_set_last_result(error);
558
559         TBM_TRACE_BO("bo(%p) size(%d)\n", bo, size);
560
561         _tbm_bufmgr_mutex_unlock();
562
563         return size;
564 }
565
566 int
567 tbm_bo_locked(tbm_bo bo)
568 {
569         _tbm_bufmgr_mutex_lock();
570         _tbm_set_last_result(TBM_ERROR_NONE);
571
572         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
573
574         if (bo->bufmgr->bo_lock_type == TBM_BUFMGR_BO_LOCK_TYPE_NEVER) {
575                 TBM_ERR("bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
576                 _tbm_set_last_result(TBM_ERROR_INVALID_OPERATION);
577                 _tbm_bufmgr_mutex_unlock();
578                 return 0;
579         }
580
581         if (bo->lock_cnt > 0) {
582                 TBM_TRACE_BO("error: bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
583                 _tbm_bufmgr_mutex_unlock();
584                 return 1;
585         }
586
587         TBM_TRACE_BO("bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
588         _tbm_bufmgr_mutex_unlock();
589
590         return 0;
591 }
592
593 int
594 tbm_bo_swap(tbm_bo bo1, tbm_bo bo2)
595 {
596         tbm_error_e error1, error2;
597         int size1 = -1, size2 = -2;
598         void *temp;
599
600         _tbm_bufmgr_mutex_lock();
601         _tbm_set_last_result(TBM_ERROR_NONE);
602
603         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo1), 0);
604         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo2), 0);
605
606         TBM_TRACE_BO("before: bo1(%p) bo2(%p)\n", bo1, bo2);
607
608         size1 = tbm_bo_data_get_size(bo1->bo_data, &error1);
609         _tbm_set_last_result(error1);
610         size2 = tbm_bo_data_get_size(bo2->bo_data, &error2);
611         _tbm_set_last_result(error2);
612
613         if (size1 != size2) {
614                 TBM_ERR("error: bo1 size(%d) and bo2 size(%d) is different.", size1, size2);
615                 _tbm_set_last_result(TBM_ERROR_INVALID_OPERATION);
616                 goto fail;
617         }
618
619         temp = bo1->bo_data;
620         bo1->bo_data = bo2->bo_data;
621         bo2->bo_data = temp;
622
623         TBM_TRACE_BO("after: bo1(%p) bo2(%p)\n", bo1, bo2);
624
625         _tbm_bufmgr_mutex_unlock();
626
627         return 1;
628
629 fail:
630         TBM_ERR("error: bo1(%p) bo2(%p)\n", bo1, bo2);
631         _tbm_bufmgr_mutex_unlock();
632
633         return 0;
634 }
635
636 int
637 tbm_bo_add_user_data(tbm_bo bo, unsigned long key,
638                      tbm_data_free data_free_func)
639 {
640         tbm_user_data *data;
641
642         _tbm_bufmgr_mutex_lock();
643         _tbm_set_last_result(TBM_ERROR_NONE);
644
645         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
646
647         /* check if the data according to the key exist if so, return false. */
648         data = user_data_lookup(&bo->user_data_list, key);
649         if (data) {
650                 TBM_TRACE_BO("warning: user data already exist key(%ld)\n", key);
651                 _tbm_set_last_result(TBM_ERROR_INVALID_PARAMETER);
652                 _tbm_bufmgr_mutex_unlock();
653                 return 0;
654         }
655
656         data = user_data_create(key, data_free_func);
657         if (!data) {
658                 TBM_ERR("error: bo(%p) key(%lu)\n", bo, key);
659                 _tbm_set_last_result(TBM_ERROR_INVALID_PARAMETER);
660                 _tbm_bufmgr_mutex_unlock();
661                 return 0;
662         }
663
664         TBM_TRACE_BO("bo(%p) key(%lu) data(%p)\n", bo, key, data->data);
665
666         LIST_ADD(&data->item_link, &bo->user_data_list);
667
668         _tbm_bufmgr_mutex_unlock();
669
670         return 1;
671 }
672
673 int
674 tbm_bo_delete_user_data(tbm_bo bo, unsigned long key)
675 {
676         tbm_user_data *old_data;
677
678         _tbm_bufmgr_mutex_lock();
679         _tbm_set_last_result(TBM_ERROR_NONE);
680
681         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
682
683         if (LIST_IS_EMPTY(&bo->user_data_list)) {
684                 TBM_TRACE_BO("bo(%p) key(%lu)\n", bo, key);
685                 _tbm_set_last_result(TBM_ERROR_INVALID_PARAMETER);
686                 _tbm_bufmgr_mutex_unlock();
687                 return 0;
688         }
689
690         old_data = user_data_lookup(&bo->user_data_list, key);
691         if (!old_data) {
692                 TBM_TRACE_BO("bo(%p) key(%lu)\n", bo, key);
693                 _tbm_set_last_result(TBM_ERROR_INVALID_PARAMETER);
694                 _tbm_bufmgr_mutex_unlock();
695                 return 0;
696         }
697
698         TBM_TRACE_BO("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
699
700         user_data_delete(old_data);
701
702         _tbm_bufmgr_mutex_unlock();
703
704         return 1;
705 }
706
707 int
708 tbm_bo_set_user_data(tbm_bo bo, unsigned long key, void *data)
709 {
710         tbm_user_data *old_data;
711
712         _tbm_bufmgr_mutex_lock();
713         _tbm_set_last_result(TBM_ERROR_NONE);
714
715         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
716
717         if (LIST_IS_EMPTY(&bo->user_data_list)) {
718                 TBM_TRACE_BO("error: bo(%p) key(%lu)\n", bo, key);
719                 _tbm_set_last_result(TBM_ERROR_INVALID_PARAMETER);
720                 _tbm_bufmgr_mutex_unlock();
721                 return 0;
722         }
723
724         old_data = user_data_lookup(&bo->user_data_list, key);
725         if (!old_data) {
726                 TBM_TRACE_BO("error: bo(%p) key(%lu)\n", bo, key);
727                 _tbm_set_last_result(TBM_ERROR_INVALID_PARAMETER);
728                 _tbm_bufmgr_mutex_unlock();
729                 return 0;
730         }
731
732         if (old_data->data && old_data->free_func)
733                 old_data->free_func(old_data->data);
734         old_data->data = data;
735
736         TBM_TRACE_BO("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
737
738         _tbm_bufmgr_mutex_unlock();
739
740         return 1;
741 }
742
743 int
744 tbm_bo_get_user_data(tbm_bo bo, unsigned long key, void **data)
745 {
746         tbm_user_data *old_data;
747
748         _tbm_bufmgr_mutex_lock();
749         _tbm_set_last_result(TBM_ERROR_NONE);
750
751         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
752
753         if (!data || LIST_IS_EMPTY(&bo->user_data_list)) {
754                 TBM_TRACE_BO("error: bo(%p) key(%lu)\n", bo, key);
755                 _tbm_set_last_result(TBM_ERROR_INVALID_PARAMETER);
756                 _tbm_bufmgr_mutex_unlock();
757                 return 0;
758         }
759
760         old_data = user_data_lookup(&bo->user_data_list, key);
761         if (!old_data) {
762                 *data = NULL;
763                 TBM_TRACE_BO("error: bo(%p) key(%lu)\n", bo, key);
764                 _tbm_set_last_result(TBM_ERROR_INVALID_PARAMETER);
765                 _tbm_bufmgr_mutex_unlock();
766                 return 0;
767         }
768
769         *data = old_data->data;
770
771         TBM_TRACE_BO("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
772
773         _tbm_bufmgr_mutex_unlock();
774
775         return 1;
776 }
777
778 int
779 tbm_bo_get_flags(tbm_bo bo)
780 {
781         int flags;
782
783         _tbm_bufmgr_mutex_lock();
784
785         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
786
787         flags = bo->flags;
788
789         TBM_TRACE_BO("bo(%p)\n", bo);
790
791         _tbm_bufmgr_mutex_unlock();
792
793         return flags;
794 }
795
796 /* LCOV_EXCL_START */
797 /* internal function */
798 int
799 _tbm_bo_set_surface(tbm_bo bo, tbm_surface_h surface)
800 {
801         _tbm_bufmgr_mutex_lock();
802
803         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
804
805         bo->surface = surface;
806
807         _tbm_bufmgr_mutex_unlock();
808
809         return 1;
810 }
811
812 void
813 _tbm_bo_free(tbm_bo bo)
814 {
815         /* destory the user_data_list */
816         if (!LIST_IS_EMPTY(&bo->user_data_list)) {
817                 tbm_user_data *old_data = NULL, *tmp;
818
819                 LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp, &bo->user_data_list, item_link) {
820                         TBM_DBG("free user_data\n");
821                         user_data_delete(old_data);
822                 }
823
824                 LIST_INITHEAD(&bo->user_data_list); // TODO: remove this. build-break when it is removed.
825         }
826
827         while (bo->lock_cnt > 0) {
828                 TBM_ERR("error lock_cnt:%d\n", bo->lock_cnt);
829                 _bo_unlock(bo);
830                 bo->lock_cnt--;
831         }
832
833         tbm_bo_data_free(bo->bo_data, bo->get_from_surface_data);
834
835         _tbm_bo_deinit(bo);
836
837         free(bo);
838 }
839 /* LCOV_EXCL_STOP */