95d74781252347b0a7bc30c1b65d0d9bae89e551
[platform/core/uifw/libtbm.git] / src / tbm_bo.c
1 /**************************************************************************
2
3 libtbm
4
5 Copyright 2012 Samsung Electronics co., Ltd. All Rights Reserved.
6
7 Contact: SooChan Lim <sc1.lim@samsung.com>, Sangjin Lee <lsj119@samsung.com>
8 Boram Park <boram1288.park@samsung.com>, Changyeon Lee <cyeon.lee@samsung.com>
9
10 Permission is hereby granted, free of charge, to any person obtaining a
11 copy of this software and associated documentation files (the
12 "Software"), to deal in the Software without restriction, including
13 without limitation the rights to use, copy, modify, merge, publish,
14 distribute, sub license, and/or sell copies of the Software, and to
15 permit persons to whom the Software is furnished to do so, subject to
16 the following conditions:
17
18 The above copyright notice and this permission notice (including the
19 next paragraph) shall be included in all copies or substantial portions
20 of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
25 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
26 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
27 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
28 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
30 **************************************************************************/
31
32 #include "config.h"
33 #include "tbm_bufmgr.h"
34 #include "tbm_bufmgr_int.h"
35 #include "list.h"
36
37 static pthread_mutex_t tbm_bo_lock = PTHREAD_MUTEX_INITIALIZER;
38 static __thread tbm_error_e tbm_last_error = TBM_ERROR_NONE;
39 static void _tbm_bo_mutex_unlock(void);
40
41 /* check condition */
42 #define TBM_BO_RETURN_IF_FAIL(cond) {\
43         if (!(cond)) {\
44                 TBM_ERR("'%s' failed.\n", #cond);\
45                 _tbm_bo_mutex_unlock();\
46                 return;\
47         } \
48 }
49
50 #define TBM_BO_RETURN_VAL_IF_FAIL(cond, val) {\
51         if (!(cond)) {\
52                 TBM_ERR("'%s' failed.\n", #cond);\
53                 _tbm_bo_mutex_unlock();\
54                 return val;\
55         } \
56 }
57
58 static void
59 _tbm_set_last_result(tbm_error_e err)
60 {
61         tbm_last_error = err;
62 }
63
64 /* LCOV_EXCL_START */
65 static bool
66 _tbm_bo_mutex_init(void)
67 {
68         static bool tbm_bo_mutex_init = false;
69
70         if (tbm_bo_mutex_init)
71                 return true;
72
73         if (pthread_mutex_init(&tbm_bo_lock, NULL)) {
74                 TBM_ERR("fail: Cannot pthread_mutex_init for tbm_bo_lock.\n");
75                 return false;
76         }
77
78         tbm_bo_mutex_init = true;
79
80         return true;
81 }
82
83 static void
84 _tbm_bo_mutex_lock(void)
85 {
86         if (!_tbm_bo_mutex_init()) {
87                 TBM_ERR("fail: _tbm_bo_mutex_init()\n");
88                 return;
89         }
90
91         pthread_mutex_lock(&tbm_bo_lock);
92 }
93
94 static void
95 _tbm_bo_mutex_unlock(void)
96 {
97         pthread_mutex_unlock(&tbm_bo_lock);
98 }
99
100 static char *
101 _tbm_flag_to_str(int f)
102 {
103         static char str[255];
104
105         if (f == TBM_BO_DEFAULT)
106                  snprintf(str, 255, "DEFAULT");
107         else {
108                 int c = 0;
109
110                 if (f & TBM_BO_SCANOUT)
111                         c += snprintf(&str[c], 255-c, "SCANOUT");
112
113                 if (f & TBM_BO_NONCACHABLE) {
114                         if (c >= 0 && c < 255)
115                                 c += snprintf(&str[c], 255-c, ", ");
116
117                         if (c >= 0 && c < 255)
118                                 c += snprintf(&str[c], 255-c, "NONCACHABLE,");
119                 }
120
121                 if (f & TBM_BO_WC) {
122                         if (c >= 0 && c < 255)
123                                 c += snprintf(&str[c], 255-c, ", ");
124
125                         if (c >= 0 && c < 255)
126                                 c += snprintf(&str[c], 255-c, "WC");
127                 }
128         }
129
130         return str;
131 }
132
133 static void
134 _tbm_util_check_bo_cnt(tbm_bufmgr bufmgr)
135 {
136         static int last_chk_bo_cnt = 0;
137
138         if ((bufmgr->bo_cnt >= 500) && ((bufmgr->bo_cnt % 20) == 0) &&
139                 (bufmgr->bo_cnt > last_chk_bo_cnt)) {
140                 TBM_DBG("============TBM BO CNT DEBUG: bo_cnt=%d\n", bufmgr->bo_cnt);
141                 tbm_bufmgr_debug_show(bufmgr);
142                 last_chk_bo_cnt = bufmgr->bo_cnt;
143         }
144 }
145 /* LCOV_EXCL_STOP */
146
147 tbm_user_data
148 *user_data_lookup(struct list_head *user_data_list, unsigned long key)
149 {
150         tbm_user_data *old_data = NULL;
151
152         if (LIST_IS_EMPTY(user_data_list))
153                 return NULL;
154
155         LIST_FOR_EACH_ENTRY(old_data, user_data_list, item_link) {
156                 if (old_data->key == key)
157                         return old_data;
158         }
159
160         return NULL;
161 }
162
163 tbm_user_data
164 *user_data_create(unsigned long key, tbm_data_free data_free_func)
165 {
166         tbm_user_data *user_data;
167
168         user_data = calloc(1, sizeof(tbm_user_data));
169         if (!user_data) {
170                 /* LCOV_EXCL_START */
171                 TBM_ERR("fail to allocate an user_date\n");
172                 return NULL;
173                 /* LCOV_EXCL_STOP */
174         }
175
176         user_data->key = key;
177         user_data->free_func = data_free_func;
178
179         return user_data;
180 }
181
182 void
183 user_data_delete(tbm_user_data *user_data)
184 {
185         if (user_data->data && user_data->free_func)
186                 user_data->free_func(user_data->data);
187
188         LIST_DEL(&user_data->item_link);
189
190         free(user_data);
191 }
192
193 static int
194 _bo_lock(tbm_bo bo, int device, int opt)
195 {
196         int ret = 1;
197
198         if (bo->bufmgr->backend->bo_lock)
199                 ret = bo->bufmgr->backend->bo_lock(bo, device, opt);
200
201         return ret;
202 }
203
204 static void
205 _bo_unlock(tbm_bo bo)
206 {
207         if (bo->bufmgr->backend->bo_unlock)
208                 bo->bufmgr->backend->bo_unlock(bo);
209 }
210
211 static int
212 _tbm_bo_lock(tbm_bo bo, int device, int opt)
213 {
214         int old, ret;
215
216         if (!bo)
217                 return 0;
218
219         /* do not try to lock the bo */
220         if (bo->bufmgr->bo_lock_type == TBM_BUFMGR_BO_LOCK_TYPE_NEVER)
221                 return 1;
222
223         if (bo->lock_cnt < 0) {
224                 TBM_ERR("error bo:%p LOCK_CNT=%d\n",
225                         bo, bo->lock_cnt);
226                 return 0;
227         }
228
229         old = bo->lock_cnt;
230
231         switch (bo->bufmgr->bo_lock_type) {
232         case TBM_BUFMGR_BO_LOCK_TYPE_ONCE:
233                 if (bo->lock_cnt == 0) {
234                         _tbm_bo_mutex_unlock();
235                         ret = _bo_lock(bo, device, opt);
236                         _tbm_bo_mutex_lock();
237                         if (ret)
238                                 bo->lock_cnt++;
239                 } else
240                         ret = 1;
241                 break;
242         case TBM_BUFMGR_BO_LOCK_TYPE_ALWAYS:
243                 _tbm_bo_mutex_unlock();
244                 ret = _bo_lock(bo, device, opt);
245                 _tbm_bo_mutex_lock();
246                 if (ret)
247                         bo->lock_cnt++;
248                 break;
249         default:
250                 TBM_ERR("error bo:%p bo_lock_type[%d] is wrong.\n",
251                                 bo, bo->bufmgr->bo_lock_type);
252                 ret = 0;
253                 break;
254         }
255
256         TBM_DBG(">> LOCK bo:%p(%d->%d)\n", bo, old, bo->lock_cnt);
257
258         return ret;
259 }
260
261 static void
262 _tbm_bo_unlock(tbm_bo bo)
263 {
264         int old;
265
266         /* do not try to unlock the bo */
267         if (bo->bufmgr->bo_lock_type == TBM_BUFMGR_BO_LOCK_TYPE_NEVER)
268                 return;
269
270         old = bo->lock_cnt;
271
272         switch (bo->bufmgr->bo_lock_type) {
273         case TBM_BUFMGR_BO_LOCK_TYPE_ONCE:
274                 if (bo->lock_cnt > 0) {
275                         bo->lock_cnt--;
276                         if (bo->lock_cnt == 0)
277                                 _bo_unlock(bo);
278                 }
279                 break;
280         case TBM_BUFMGR_BO_LOCK_TYPE_ALWAYS:
281                 if (bo->lock_cnt > 0) {
282                         bo->lock_cnt--;
283                         _bo_unlock(bo);
284                 }
285                 break;
286         default:
287                 TBM_ERR("error bo:%p bo_lock_type[%d] is wrong.\n",
288                                 bo, bo->bufmgr->bo_lock_type);
289                 break;
290         }
291
292         if (bo->lock_cnt < 0)
293                 bo->lock_cnt = 0;
294
295         TBM_DBG(">> UNLOCK bo:%p(%d->%d)\n", bo, old, bo->lock_cnt);
296 }
297
298 static int
299 _tbm_bo_is_valid(tbm_bo bo)
300 {
301         tbm_bufmgr bufmgr = NULL;
302         tbm_bo old_data = NULL;
303
304         if (bo == NULL) {
305                 TBM_ERR("error: bo is NULL.\n");
306                 return 0;
307         }
308
309         bufmgr = tbm_bufmgr_get();
310         if (bufmgr == NULL) {
311                 TBM_ERR("error: bufmgr is NULL.\n");
312                 return 0;
313         }
314
315         if (LIST_IS_EMPTY(&bufmgr->bo_list)) {
316                 TBM_ERR("error: bo->bo->bufmgr->bo_list is EMPTY.\n");
317                 return 0;
318         }
319
320         LIST_FOR_EACH_ENTRY(old_data, &bufmgr->bo_list, item_link) {
321                 if (old_data == bo)
322                         return 1;
323         }
324
325         TBM_ERR("error: No valid bo(%p).\n", bo);
326
327         return 0;
328 }
329
330 tbm_bo
331 tbm_bo_alloc(tbm_bufmgr bufmgr, int size, int flags)
332 {
333         void *bo_priv;
334         tbm_bo bo;
335
336         _tbm_bo_mutex_lock();
337
338         TBM_BO_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
339         TBM_BO_RETURN_VAL_IF_FAIL(size > 0, NULL);
340
341         bo = calloc(1, sizeof(struct _tbm_bo));
342         if (!bo) {
343                 /* LCOV_EXCL_START */
344                 TBM_ERR("error: fail to create of tbm_bo size(%d) flag(%s)\n",
345                                 size, _tbm_flag_to_str(flags));
346                 _tbm_set_last_result(TBM_BO_ERROR_HEAP_ALLOC_FAILED);
347                 _tbm_bo_mutex_unlock();
348                 return NULL;
349                 /* LCOV_EXCL_STOP */
350         }
351
352         _tbm_util_check_bo_cnt(bufmgr);
353
354         bo->bufmgr = bufmgr;
355
356         bo_priv = bo->bufmgr->backend->bo_alloc(bo, size, flags);
357         if (!bo_priv) {
358                 /* LCOV_EXCL_START */
359                 TBM_ERR("error: fail to create of tbm_bo size(%d) flag(%s)\n",
360                                 size, _tbm_flag_to_str(flags));
361                 _tbm_set_last_result(TBM_BO_ERROR_BO_ALLOC_FAILED);
362                 free(bo);
363                 _tbm_bo_mutex_unlock();
364                 return NULL;
365                 /* LCOV_EXCL_STOP */
366         }
367
368         bo->bufmgr->bo_cnt++;
369
370         bo->ref_cnt = 1;
371         bo->flags = flags;
372         bo->priv = bo_priv;
373
374         TBM_TRACE_BO("bo(%p) size(%d) refcnt(%d), flag(%s)\n", bo, size, bo->ref_cnt,
375                         _tbm_flag_to_str(bo->flags));
376
377         LIST_INITHEAD(&bo->user_data_list);
378
379         LIST_ADD(&bo->item_link, &bo->bufmgr->bo_list);
380
381         _tbm_bo_mutex_unlock();
382
383         return bo;
384 }
385
386 tbm_bo
387 tbm_bo_ref(tbm_bo bo)
388 {
389         _tbm_bo_mutex_lock();
390
391         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), NULL);
392
393         bo->ref_cnt++;
394
395         TBM_TRACE_BO("bo(%p) ref_cnt(%d)\n", bo, bo->ref_cnt);
396
397         _tbm_bo_mutex_unlock();
398
399         return bo;
400 }
401
402 void
403 tbm_bo_unref(tbm_bo bo)
404 {
405         _tbm_bo_mutex_lock();
406
407         TBM_BO_RETURN_IF_FAIL(_tbm_bo_is_valid(bo));
408
409         TBM_TRACE_BO("bo(%p) ref_cnt(%d)\n", bo, bo->ref_cnt - 1);
410
411         if (bo->ref_cnt <= 0) {
412                 _tbm_bo_mutex_unlock();
413                 return;
414         }
415
416         bo->ref_cnt--;
417         if (bo->ref_cnt == 0)
418                 _tbm_bo_free(bo);
419
420         _tbm_bo_mutex_unlock();
421 }
422
423 tbm_bo_handle
424 tbm_bo_map(tbm_bo bo, int device, int opt)
425 {
426         tbm_bo_handle bo_handle;
427
428         _tbm_bo_mutex_lock();
429
430         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) NULL);
431
432         if (!_tbm_bo_lock(bo, device, opt)) {
433                 _tbm_set_last_result(TBM_BO_ERROR_LOCK_FAILED);
434                 TBM_ERR("error: fail to lock bo:%p)\n", bo);
435                 _tbm_bo_mutex_unlock();
436                 return (tbm_bo_handle) NULL;
437         }
438
439         bo_handle = bo->bufmgr->backend->bo_map(bo, device, opt);
440         if (bo_handle.ptr == NULL) {
441                 /* LCOV_EXCL_START */
442                 _tbm_set_last_result(TBM_BO_ERROR_MAP_FAILED);
443                 TBM_ERR("error: fail to map bo:%p\n", bo);
444                 _tbm_bo_unlock(bo);
445                 _tbm_bo_mutex_unlock();
446                 return (tbm_bo_handle) NULL;
447                 /* LCOV_EXCL_STOP */
448         }
449
450         /* increase the map_count */
451         bo->map_cnt++;
452
453         TBM_TRACE_BO("bo(%p) map_cnt(%d)\n", bo, bo->map_cnt);
454
455         _tbm_bo_mutex_unlock();
456
457         return bo_handle;
458 }
459
460 int
461 tbm_bo_unmap(tbm_bo bo)
462 {
463         int ret;
464
465         _tbm_bo_mutex_lock();
466
467         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
468         TBM_BO_RETURN_VAL_IF_FAIL(bo->map_cnt > 0, 0);
469
470         ret = bo->bufmgr->backend->bo_unmap(bo);
471         if (!ret) {
472                 /* LCOV_EXCL_START */
473                 TBM_ERR("error: bo(%p) map_cnt(%d)\n", bo, bo->map_cnt);
474                 _tbm_set_last_result(TBM_BO_ERROR_UNMAP_FAILED);
475                 _tbm_bo_mutex_unlock();
476                 return ret;
477                 /* LCOV_EXCL_STOP */
478         }
479
480         /* decrease the map_count */
481         bo->map_cnt--;
482
483         TBM_TRACE_BO("bo(%p) map_cnt(%d)\n", bo, bo->map_cnt);
484
485         _tbm_bo_unlock(bo);
486
487         _tbm_bo_mutex_unlock();
488
489         return ret;
490 }
491
492 tbm_bo_handle
493 tbm_bo_get_handle(tbm_bo bo, int device)
494 {
495         tbm_bo_handle bo_handle;
496
497         _tbm_bo_mutex_lock();
498
499         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) NULL);
500
501         bo_handle = bo->bufmgr->backend->bo_get_handle(bo, device);
502         if (bo_handle.ptr == NULL) {
503                 /* LCOV_EXCL_START */
504                 _tbm_set_last_result(TBM_BO_ERROR_GET_HANDLE_FAILED);
505                 TBM_ERR("error: bo(%p) bo_handle(%p)\n", bo, bo_handle.ptr);
506                 _tbm_bo_mutex_unlock();
507                 return (tbm_bo_handle) NULL;
508                 /* LCOV_EXCL_STOP */
509         }
510
511         TBM_TRACE_BO("bo(%p) bo_handle(%p)\n", bo, bo_handle.ptr);
512
513         _tbm_bo_mutex_unlock();
514
515         return bo_handle;
516 }
517
518 tbm_key
519 tbm_bo_export(tbm_bo bo)
520 {
521         tbm_key ret;
522
523         _tbm_bo_mutex_lock();
524
525         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
526
527         if (!bo->bufmgr->backend->bo_export) {
528                 /* LCOV_EXCL_START */
529                 _tbm_bo_mutex_unlock();
530                 return 0;
531                 /* LCOV_EXCL_STOP */
532         }
533
534         ret = bo->bufmgr->backend->bo_export(bo);
535         if (!ret) {
536                 /* LCOV_EXCL_START */
537                 _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FAILED);
538                 TBM_ERR("error: bo(%p) tbm_key(%d)\n", bo, ret);
539                 _tbm_bo_mutex_unlock();
540                 return ret;
541                 /* LCOV_EXCL_STOP */
542         }
543
544         TBM_TRACE_BO("bo(%p) tbm_key(%u)\n", bo, ret);
545
546         _tbm_bo_mutex_unlock();
547
548         return ret;
549 }
550
551 tbm_fd
552 tbm_bo_export_fd(tbm_bo bo)
553 {
554         tbm_fd ret;
555
556         _tbm_bo_mutex_lock();
557
558         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), -1);
559
560         if (!bo->bufmgr->backend->bo_export_fd) {
561                 /* LCOV_EXCL_START */
562                 _tbm_bo_mutex_unlock();
563                 return -1;
564                 /* LCOV_EXCL_STOP */
565         }
566
567         ret = bo->bufmgr->backend->bo_export_fd(bo);
568         if (ret < 0) {
569                 /* LCOV_EXCL_START */
570                 _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FD_FAILED);
571                 TBM_ERR("error: bo(%p) tbm_fd(%d)\n", bo, ret);
572                 _tbm_bo_mutex_unlock();
573                 return ret;
574                 /* LCOV_EXCL_STOP */
575         }
576
577         TBM_TRACE_BO("bo(%p) tbm_fd(%d)\n", bo, ret);
578
579         _tbm_bo_mutex_unlock();
580
581         return ret;
582 }
583
584 tbm_bo
585 tbm_bo_import(tbm_bufmgr bufmgr, unsigned int key)
586 {
587         tbm_bo bo;
588         tbm_bo bo2 = NULL;
589         void *bo_priv;
590
591         _tbm_bo_mutex_lock();
592
593         TBM_BO_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
594
595         if (!bufmgr->backend->bo_import) {
596                 /* LCOV_EXCL_START */
597                 _tbm_bo_mutex_unlock();
598                 return NULL;
599                 /* LCOV_EXCL_STOP */
600         }
601
602         _tbm_util_check_bo_cnt(bufmgr);
603
604         bo = calloc(1, sizeof(struct _tbm_bo));
605         if (!bo) {
606                 /* LCOV_EXCL_START */
607                 TBM_ERR("error: fail to import of tbm_bo by key(%d)\n", key);
608                 _tbm_bo_mutex_unlock();
609                 return NULL;
610                 /* LCOV_EXCL_STOP */
611         }
612
613         bo->bufmgr = bufmgr;
614
615         bo_priv = bo->bufmgr->backend->bo_import(bo, key);
616         if (!bo_priv) {
617                 /* LCOV_EXCL_START */
618                 TBM_ERR("error: fail to import of tbm_bo by key(%d)\n", key);
619                 _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FAILED);
620                 free(bo);
621                 _tbm_bo_mutex_unlock();
622                 return NULL;
623                 /* LCOV_EXCL_STOP */
624         }
625
626         if (!LIST_IS_EMPTY(&bo->bufmgr->bo_list)) {
627                 LIST_FOR_EACH_ENTRY(bo2, &bo->bufmgr->bo_list, item_link) {
628                         if (bo2->priv == bo_priv) {
629                                 TBM_TRACE_BO("find bo(%p) ref(%d) key(%d) flag(%s) in list\n",
630                                                 bo2, bo2->ref_cnt, key,
631                                                 _tbm_flag_to_str(bo2->flags));
632                                 bo2->ref_cnt++;
633                                 free(bo);
634                                 _tbm_bo_mutex_unlock();
635                                 return bo2;
636                         }
637                 }
638         }
639
640         bo->bufmgr->bo_cnt++;
641
642         bo->ref_cnt = 1;
643         bo->priv = bo_priv;
644
645         if (bo->bufmgr->backend->bo_get_flags)
646                 bo->flags = bo->bufmgr->backend->bo_get_flags(bo);
647         else
648                 bo->flags = TBM_BO_DEFAULT;
649
650         TBM_TRACE_BO("import new bo(%p) ref(%d) key(%d) flag(%s) in list\n",
651                           bo, bo->ref_cnt, key, _tbm_flag_to_str(bo->flags));
652
653         LIST_INITHEAD(&bo->user_data_list);
654
655         LIST_ADD(&bo->item_link, &bo->bufmgr->bo_list);
656
657         _tbm_bo_mutex_unlock();
658
659         return bo;
660 }
661
662 tbm_bo
663 tbm_bo_import_fd(tbm_bufmgr bufmgr, tbm_fd fd)
664 {
665         tbm_bo bo;
666         tbm_bo bo2 = NULL;
667         void *bo_priv;
668
669         _tbm_bo_mutex_lock();
670
671         TBM_BO_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
672
673         if (!bufmgr->backend->bo_import_fd) {
674                 /* LCOV_EXCL_START */
675                 _tbm_bo_mutex_unlock();
676                 return NULL;
677                 /* LCOV_EXCL_STOP */
678         }
679
680         _tbm_util_check_bo_cnt(bufmgr);
681
682         bo = calloc(1, sizeof(struct _tbm_bo));
683         if (!bo) {
684                 /* LCOV_EXCL_START */
685                 TBM_ERR("error: fail to import tbm_bo by tbm_fd(%d)\n", fd);
686                 _tbm_bo_mutex_unlock();
687                 return NULL;
688                 /* LCOV_EXCL_STOP */
689         }
690
691         bo->bufmgr = bufmgr;
692
693         bo_priv = bo->bufmgr->backend->bo_import_fd(bo, fd);
694         if (!bo_priv) {
695                 /* LCOV_EXCL_START */
696                 TBM_ERR("error: fail to import tbm_bo by tbm_fd(%d)\n", fd);
697                 _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FD_FAILED);
698                 free(bo);
699                 _tbm_bo_mutex_unlock();
700                 return NULL;
701                 /* LCOV_EXCL_STOP */
702         }
703
704         if (!LIST_IS_EMPTY(&bo->bufmgr->bo_list)) {
705
706                 LIST_FOR_EACH_ENTRY(bo2, &bo->bufmgr->bo_list, item_link) {
707                         if (bo2->priv == bo_priv) {
708                                 TBM_TRACE_BO("find bo(%p) ref(%d) fd(%d) flag(%s) in list\n",
709                                                 bo2, bo2->ref_cnt, fd,
710                                                 _tbm_flag_to_str(bo2->flags));
711                                 bo2->ref_cnt++;
712                                 free(bo);
713                                 _tbm_bo_mutex_unlock();
714                                 return bo2;
715                         }
716                 }
717         }
718
719         bo->bufmgr->bo_cnt++;
720
721         bo->ref_cnt = 1;
722         bo->priv = bo_priv;
723
724         if (bo->bufmgr->backend->bo_get_flags)
725                 bo->flags = bo->bufmgr->backend->bo_get_flags(bo);
726         else
727                 bo->flags = TBM_BO_DEFAULT;
728
729         TBM_TRACE_BO("import bo(%p) ref(%d) fd(%d) flag(%s)\n",
730                         bo, bo->ref_cnt, fd, _tbm_flag_to_str(bo->flags));
731
732         LIST_INITHEAD(&bo->user_data_list);
733
734         LIST_ADD(&bo->item_link, &bo->bufmgr->bo_list);
735
736         _tbm_bo_mutex_unlock();
737
738         return bo;
739 }
740
741 int
742 tbm_bo_size(tbm_bo bo)
743 {
744         int size;
745
746         _tbm_bo_mutex_lock();
747
748         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
749
750         size = bo->bufmgr->backend->bo_size(bo);
751
752         TBM_TRACE_BO("bo(%p) size(%d)\n", bo, size);
753
754         _tbm_bo_mutex_unlock();
755
756         return size;
757 }
758
759 int
760 tbm_bo_locked(tbm_bo bo)
761 {
762         _tbm_bo_mutex_lock();
763
764         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
765
766         if (bo->bufmgr->bo_lock_type == TBM_BUFMGR_BO_LOCK_TYPE_NEVER) {
767                 TBM_ERR("bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
768                 _tbm_bo_mutex_unlock();
769                 return 0;
770         }
771
772         if (bo->lock_cnt > 0) {
773                 TBM_TRACE_BO("error: bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
774                 _tbm_bo_mutex_unlock();
775                 return 1;
776         }
777
778         TBM_TRACE_BO("bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
779         _tbm_bo_mutex_unlock();
780
781         return 0;
782 }
783
784 int
785 tbm_bo_swap(tbm_bo bo1, tbm_bo bo2)
786 {
787         void *temp;
788
789         _tbm_bo_mutex_lock();
790
791         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo1), 0);
792         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo2), 0);
793
794         TBM_TRACE_BO("before: bo1(%p) bo2(%p)\n", bo1, bo2);
795
796         if (bo1->bufmgr->backend->bo_size(bo1) != bo2->bufmgr->backend->bo_size(bo2)) {
797                 _tbm_set_last_result(TBM_BO_ERROR_SWAP_FAILED);
798                 TBM_ERR("error: bo1(%p) bo2(%p)\n", bo1, bo2);
799                 _tbm_bo_mutex_unlock();
800                 return 0;
801         }
802
803         TBM_TRACE_BO("after: bo1(%p) bo2(%p)\n", bo1, bo2);
804
805         temp = bo1->priv;
806         bo1->priv = bo2->priv;
807         bo2->priv = temp;
808
809         _tbm_bo_mutex_unlock();
810
811         return 1;
812 }
813
814 int
815 tbm_bo_add_user_data(tbm_bo bo, unsigned long key,
816                      tbm_data_free data_free_func)
817 {
818         tbm_user_data *data;
819
820         _tbm_bo_mutex_lock();
821
822         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
823
824         /* check if the data according to the key exist if so, return false. */
825         data = user_data_lookup(&bo->user_data_list, key);
826         if (data) {
827                 TBM_TRACE_BO("warning: user data already exist key(%ld)\n", key);
828                 _tbm_bo_mutex_unlock();
829                 return 0;
830         }
831
832         data = user_data_create(key, data_free_func);
833         if (!data) {
834                 TBM_ERR("error: bo(%p) key(%lu)\n", bo, key);
835                 _tbm_bo_mutex_unlock();
836                 return 0;
837         }
838
839         TBM_TRACE_BO("bo(%p) key(%lu) data(%p)\n", bo, key, data->data);
840
841         LIST_ADD(&data->item_link, &bo->user_data_list);
842
843         _tbm_bo_mutex_unlock();
844
845         return 1;
846 }
847
848 int
849 tbm_bo_delete_user_data(tbm_bo bo, unsigned long key)
850 {
851         tbm_user_data *old_data;
852
853         _tbm_bo_mutex_lock();
854
855         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
856
857         if (LIST_IS_EMPTY(&bo->user_data_list)) {
858                 TBM_TRACE_BO("error: bo(%p) key(%lu)\n", bo, key);
859                 _tbm_bo_mutex_unlock();
860                 return 0;
861         }
862
863         old_data = user_data_lookup(&bo->user_data_list, key);
864         if (!old_data) {
865                 TBM_TRACE_BO("error: bo(%p) key(%lu)\n", bo, key);
866                 _tbm_bo_mutex_unlock();
867                 return 0;
868         }
869
870         TBM_TRACE_BO("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
871
872         user_data_delete(old_data);
873
874         _tbm_bo_mutex_unlock();
875
876         return 1;
877 }
878
879 int
880 tbm_bo_set_user_data(tbm_bo bo, unsigned long key, void *data)
881 {
882         tbm_user_data *old_data;
883
884         _tbm_bo_mutex_lock();
885
886         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
887
888         if (LIST_IS_EMPTY(&bo->user_data_list)) {
889                 TBM_TRACE_BO("error: bo(%p) key(%lu)\n", bo, key);
890                 _tbm_bo_mutex_unlock();
891                 return 0;
892         }
893
894         old_data = user_data_lookup(&bo->user_data_list, key);
895         if (!old_data) {
896                 TBM_TRACE_BO("error: bo(%p) key(%lu)\n", bo, key);
897                 _tbm_bo_mutex_unlock();
898                 return 0;
899         }
900
901         if (old_data->data && old_data->free_func)
902                 old_data->free_func(old_data->data);
903         old_data->data = data;
904
905         TBM_TRACE_BO("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
906
907         _tbm_bo_mutex_unlock();
908
909         return 1;
910 }
911
912 int
913 tbm_bo_get_user_data(tbm_bo bo, unsigned long key, void **data)
914 {
915         tbm_user_data *old_data;
916
917         _tbm_bo_mutex_lock();
918
919         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
920
921         if (!data || LIST_IS_EMPTY(&bo->user_data_list)) {
922                 TBM_TRACE_BO("error: bo(%p) key(%lu)\n", bo, key);
923                 _tbm_bo_mutex_unlock();
924                 return 0;
925         }
926
927         old_data = user_data_lookup(&bo->user_data_list, key);
928         if (!old_data) {
929                 TBM_TRACE_BO("error: bo(%p) key(%lu)\n", bo, key);
930                 *data = NULL;
931                 _tbm_bo_mutex_unlock();
932                 return 0;
933         }
934
935         *data = old_data->data;
936
937         TBM_TRACE_BO("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
938
939         _tbm_bo_mutex_unlock();
940
941         return 1;
942 }
943
944 /* LCOV_EXCL_START */
945 tbm_error_e
946 tbm_get_last_error(void)
947 {
948         return tbm_last_error;
949 }
950 /* LCOV_EXCL_STOP */
951
952 int
953 tbm_bo_get_flags(tbm_bo bo)
954 {
955         int flags;
956
957         _tbm_bo_mutex_lock();
958
959         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
960
961         flags = bo->flags;
962
963         TBM_TRACE_BO("bo(%p)\n", bo);
964
965         _tbm_bo_mutex_unlock();
966
967         return flags;
968 }
969
970 /* LCOV_EXCL_START */
971 /* internal function */
972 int
973 _tbm_bo_set_surface(tbm_bo bo, tbm_surface_h surface)
974 {
975         _tbm_bo_mutex_lock();
976
977         TBM_BO_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
978
979         bo->surface = surface;
980
981         _tbm_bo_mutex_unlock();
982
983         return 1;
984 }
985
986 void
987 _tbm_bo_free(tbm_bo bo)
988 {
989         /* destory the user_data_list */
990         if (!LIST_IS_EMPTY(&bo->user_data_list)) {
991                 tbm_user_data *old_data = NULL, *tmp;
992
993                 LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp,
994                                 &bo->user_data_list, item_link) {
995                         TBM_DBG("free user_data\n");
996                         user_data_delete(old_data);
997                 }
998         }
999
1000         while (bo->lock_cnt > 0) {
1001                 TBM_ERR("error lock_cnt:%d\n", bo->lock_cnt);
1002                 _bo_unlock(bo);
1003                 bo->lock_cnt--;
1004         }
1005
1006         /* call the bo_free */
1007         bo->bufmgr->backend->bo_free(bo);
1008         bo->priv = NULL;
1009
1010         bo->bufmgr->bo_cnt--;
1011
1012         LIST_DEL(&bo->item_link);
1013         free(bo);
1014 }
1015 /* LCOV_EXCL_STOP */