fixed deadlock issues
[platform/core/uifw/libtbm.git] / src / tbm_bufmgr.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
34 #include "tbm_bufmgr.h"
35 #include "tbm_bufmgr_int.h"
36 #include "tbm_bufmgr_backend.h"
37 #include "list.h"
38
39 #ifdef DEBUG
40 int bDebug;
41 #endif
42
43 #ifdef TRACE
44 int bTrace;
45 #endif
46
47 #ifdef HAVE_DLOG
48 int bDlog;
49 #endif
50
51 tbm_bufmgr gBufMgr;
52 int b_dump_queue;
53
54 static pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
55 static pthread_mutex_t tbm_bufmgr_lock = PTHREAD_MUTEX_INITIALIZER;
56 static __thread tbm_error_e tbm_last_error = TBM_ERROR_NONE;
57
58 static void _tbm_bufmgr_mutex_unlock(void);
59
60 //#define TBM_BUFMGR_INIT_TIME
61
62 #define PREFIX_LIB    "libtbm_"
63 #define SUFFIX_LIB    ".so"
64 #define DEFAULT_LIB   PREFIX_LIB"default"SUFFIX_LIB
65
66 /* values to indicate unspecified fields in XF86ModReqInfo. */
67 #define MAJOR_UNSPEC        0xFF
68 #define MINOR_UNSPEC        0xFF
69 #define PATCH_UNSPEC        0xFFFF
70 #define ABI_VERS_UNSPEC   0xFFFFFFFF
71
72 #define MODULE_VERSION_NUMERIC(maj, min, patch) \
73                         ((((maj) & 0xFF) << 24) | (((min) & 0xFF) << 16) | (patch & 0xFFFF))
74 #define GET_MODULE_MAJOR_VERSION(vers)    (((vers) >> 24) & 0xFF)
75 #define GET_MODULE_MINOR_VERSION(vers)    (((vers) >> 16) & 0xFF)
76 #define GET_MODULE_PATCHLEVEL(vers)    ((vers) & 0xFFFF)
77
78 /* check condition */
79 #define TBM_BUFMGR_RETURN_IF_FAIL(cond) {\
80         if (!(cond)) {\
81                 TBM_LOG_E("'%s' failed.\n", #cond);\
82                 _tbm_bufmgr_mutex_unlock();\
83                 return;\
84         } \
85 }
86
87 #define TBM_BUFMGR_RETURN_VAL_IF_FAIL(cond, val) {\
88         if (!(cond)) {\
89                 TBM_LOG_E("'%s' failed.\n", #cond);\
90                 _tbm_bufmgr_mutex_unlock();\
91                 return val;\
92         } \
93 }
94
95 enum {
96         LOCK_TRY_ONCE,
97         LOCK_TRY_ALWAYS,
98         LOCK_TRY_NEVER
99 };
100
101 static void
102 _tbm_set_last_result(tbm_error_e err)
103 {
104         tbm_last_error = err;
105 }
106
107 static bool
108 _tbm_bufmgr_mutex_init(void)
109 {
110         static bool tbm_bufmgr_mutex_init = false;
111
112         if (tbm_bufmgr_mutex_init)
113                 return true;
114
115         if (pthread_mutex_init(&tbm_bufmgr_lock, NULL)) {
116                 TBM_LOG_E("fail: tbm_bufmgr mutex init\n");
117                 return false;
118         }
119
120         tbm_bufmgr_mutex_init = true;
121
122         return true;
123 }
124
125 static void
126 _tbm_bufmgr_mutex_lock(void)
127 {
128         if (!_tbm_bufmgr_mutex_init())
129                 return;
130
131         pthread_mutex_lock(&tbm_bufmgr_lock);
132 }
133
134 static void
135 _tbm_bufmgr_mutex_unlock(void)
136 {
137         pthread_mutex_unlock(&tbm_bufmgr_lock);
138 }
139
140 char * tbm_flag_to_str(int f)
141 {
142         static char str[255];
143         int c = 0;
144         if (f == TBM_BO_DEFAULT)
145                  snprintf(str, 255, "DEFAULT\n");
146         else {
147                 if (f & TBM_BO_SCANOUT)
148                         c = snprintf(&str[c], 255, "SCANOUT,");
149                 if (f & TBM_BO_NONCACHABLE)
150                         c = snprintf(&str[c], 255, "NONCACHABLE,");
151                 if (f & TBM_BO_WC)
152                         c = snprintf(&str[c], 255, "WC");
153         }
154         return str;
155 }
156
157 /* LCOV_EXCL_START */
158 static int last_chk_bo_cnt = 0;
159 static void
160 _tbm_util_check_bo_cnt(tbm_bufmgr bufmgr)
161 {
162         if (bufmgr->bo_cnt >= 500 && ((bufmgr->bo_cnt % 20) == 0)) {
163                 if (bufmgr->bo_cnt > last_chk_bo_cnt) {
164                         TBM_DEBUG("============TBM BO CNT DEBUG: bo_cnt=%d\n", bufmgr->bo_cnt);
165                         tbm_bufmgr_debug_show(bufmgr);
166                         last_chk_bo_cnt = bufmgr->bo_cnt;
167                 }
168         }
169 }
170
171 static int
172 _tbm_util_get_max_surface_size(int * w, int * h)
173 {
174         int count = 0;
175         tbm_surface_h surface = NULL, tmp = NULL;
176         tbm_surface_info_s info;
177
178         *w = 0;
179         *h = 0;
180
181         if (gBufMgr == NULL)
182                 return count;
183
184         if (!LIST_IS_EMPTY(&gBufMgr->surf_list)) {
185                 LIST_FOR_EACH_ENTRY_SAFE(surface, tmp, &gBufMgr->surf_list, item_link) {
186                         if (tbm_surface_get_info(surface, &info) == TBM_SURFACE_ERROR_NONE) {
187                                 count++;
188                                 if (*w < info.width) *w = info.width;
189                                 if (*h < info.height) *h = info.height;
190                         }
191                 }
192         }
193
194         return count;
195 }
196
197 static void
198 _tbm_util_get_appname_brief(char *brief)
199 {
200         char delim[] = "/";
201         char *token = NULL;
202         char temp[255] = {0,};
203         char *saveptr = NULL;
204
205         token = strtok_r(brief, delim, &saveptr);
206
207         while (token != NULL) {
208                 memset(temp, 0x00, 255 * sizeof(char));
209                 strncpy(temp, token, 254 * sizeof(char));
210                 token = strtok_r(NULL, delim, &saveptr);
211         }
212
213         snprintf(brief, sizeof(temp), "%s", temp);
214 }
215
216 static void
217 _tbm_util_get_appname_from_pid(long pid, char *str)
218 {
219         FILE *fp;
220         int len;
221         long app_pid = pid;
222         char fn_cmdline[255] = {0,};
223         char cmdline[255] = {0,};
224
225         snprintf(fn_cmdline, sizeof(fn_cmdline), "/proc/%ld/cmdline", app_pid);
226
227         fp = fopen(fn_cmdline, "r");
228         if (fp == 0) {
229                 fprintf(stderr, "cannot file open /proc/%ld/cmdline", app_pid);
230                 return;
231         }
232
233         if (!fgets(cmdline, 255, fp)) {
234                 fprintf(stderr, "fail to get appname for pid(%ld)\n", app_pid);
235                 fclose(fp);
236                 return;
237         }
238         fclose(fp);
239
240         len = strlen(cmdline);
241         if (len < 1)
242                 memset(cmdline, 0x00, 255);
243         else
244                 cmdline[len] = 0;
245
246         snprintf(str, sizeof(cmdline), "%s", cmdline);
247 }
248 /* LCOV_EXCL_STOP */
249
250 tbm_user_data
251 *user_data_lookup(struct list_head *user_data_list, unsigned long key)
252 {
253         tbm_user_data *user_data = NULL;
254         tbm_user_data *old_data = NULL, *tmp = NULL;
255
256         if (!LIST_IS_EMPTY(user_data_list)) {
257                 LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp, user_data_list, item_link) {
258                         if (old_data->key == key) {
259                                 user_data = old_data;
260                                 return user_data;
261                         }
262                 }
263         }
264
265         return user_data;
266 }
267
268 tbm_user_data
269 *user_data_create(unsigned long key, tbm_data_free data_free_func)
270 {
271         tbm_user_data *user_data = NULL;
272
273         user_data = calloc(1, sizeof(tbm_user_data));
274         if (!user_data)
275                 return NULL;
276
277         user_data->key = key;
278         user_data->free_func = data_free_func;
279         user_data->data = (void *)0;
280
281         return user_data;
282 }
283
284 void
285 user_data_delete(tbm_user_data *user_data)
286 {
287         if (user_data->data && user_data->free_func)
288                 user_data->free_func(user_data->data);
289
290         LIST_DEL(&user_data->item_link);
291
292         free(user_data);
293 }
294
295 static int
296 _bo_lock(tbm_bo bo, int device, int opt)
297 {
298         tbm_bufmgr bufmgr = bo->bufmgr;
299         int ret = 0;
300
301         if (bufmgr->backend->bo_lock)
302                 ret = bufmgr->backend->bo_lock(bo, device, opt);
303         else
304                 ret = 1;
305
306         return ret;
307 }
308
309 static void
310 _bo_unlock(tbm_bo bo)
311 {
312         tbm_bufmgr bufmgr = bo->bufmgr;
313
314         if (bufmgr->backend->bo_unlock)
315                 bufmgr->backend->bo_unlock(bo);
316 }
317
318 static int
319 _tbm_bo_lock(tbm_bo bo, int device, int opt)
320 {
321         tbm_bufmgr bufmgr = NULL;
322         int old;
323         int ret = 0;
324
325         if (!bo)
326                 return 0;
327
328         bufmgr = bo->bufmgr;
329
330         /* do not try to lock the bo */
331         if (bufmgr->lock_type == LOCK_TRY_NEVER)
332                 return 1;
333
334         if (bo->lock_cnt < 0) {
335                 TBM_LOG_E("error bo:%p LOCK_CNT=%d\n",
336                         bo, bo->lock_cnt);
337         }
338
339         old = bo->lock_cnt;
340         if (bufmgr->lock_type == LOCK_TRY_ONCE) {
341                 if (bo->lock_cnt == 0) {
342                         _tbm_bufmgr_mutex_unlock();
343                         ret = _bo_lock(bo, device, opt);
344                         _tbm_bufmgr_mutex_lock();
345                         if (ret)
346                                 bo->lock_cnt++;
347                 } else
348                         ret = 1;
349         } else if (bufmgr->lock_type == LOCK_TRY_ALWAYS) {
350                 _tbm_bufmgr_mutex_unlock();
351                 ret = _bo_lock(bo, device, opt);
352                 _tbm_bufmgr_mutex_lock();
353                 if (ret)
354                         bo->lock_cnt++;
355         } else {
356                 TBM_LOG_E("error bo:%p lock_type is wrong.\n",
357                         bo);
358         }
359
360         TBM_DBG_LOCK(">> LOCK bo:%p(%d->%d)\n",
361                  bo, old, bo->lock_cnt);
362
363         return ret;
364 }
365
366 static void
367 _tbm_bo_unlock(tbm_bo bo)
368 {
369         tbm_bufmgr bufmgr = NULL;
370
371         int old;
372
373         if (!bo)
374                 return;
375
376         bufmgr = bo->bufmgr;
377
378         /* do not try to unlock the bo */
379         if (bufmgr->lock_type == LOCK_TRY_NEVER)
380                 return;
381
382         old = bo->lock_cnt;
383         if (bufmgr->lock_type == LOCK_TRY_ONCE) {
384                 if (bo->lock_cnt > 0) {
385                         bo->lock_cnt--;
386                         if (bo->lock_cnt == 0)
387                                 _bo_unlock(bo);
388                 }
389         } else if (bufmgr->lock_type == LOCK_TRY_ALWAYS) {
390                 if (bo->lock_cnt > 0) {
391                         bo->lock_cnt--;
392                         _bo_unlock(bo);
393                 }
394         } else {
395                 TBM_LOG_E("error bo:%p lock_type is wrong.\n",
396                         bo);
397         }
398
399         if (bo->lock_cnt < 0)
400                 bo->lock_cnt = 0;
401
402         TBM_DBG_LOCK(">> UNLOCK bo:%p(%d->%d)\n",
403                  bo, old, bo->lock_cnt);
404 }
405
406 static int
407 _tbm_bo_is_valid(tbm_bo bo)
408 {
409         tbm_bo old_data = NULL, tmp = NULL;
410
411         if (bo == NULL)
412                 return 0;
413
414         if (gBufMgr == NULL) {
415                 TBM_LOG_E("error tbm_bufmgr was deinited\n");
416                 return 0;
417         }
418
419         if (!LIST_IS_EMPTY(&gBufMgr->bo_list)) {
420                 LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp, &gBufMgr->bo_list, item_link) {
421                         if (old_data == bo)
422                                 return 1;
423                 }
424
425         }
426         return 0;
427 }
428
429 /* LCOV_EXCL_START */
430 static int
431 _check_version(TBMModuleVersionInfo *data)
432 {
433         int abimaj, abimin;
434         int vermaj, vermin;
435
436         abimaj = GET_ABI_MAJOR(data->abiversion);
437         abimin = GET_ABI_MINOR(data->abiversion);
438
439         TBM_DBG("TBM module %s: vendor=\"%s\" ABI=%d,%d\n",
440             data->modname ? data->modname : "UNKNOWN!",
441             data->vendor ? data->vendor : "UNKNOWN!", abimaj, abimin);
442
443         vermaj = GET_ABI_MAJOR(TBM_ABI_VERSION);
444         vermin = GET_ABI_MINOR(TBM_ABI_VERSION);
445
446         TBM_DBG("TBM ABI version %d.%d\n",
447             vermaj, vermin);
448
449         if (abimaj != vermaj) {
450                 TBM_LOG_E("TBM module ABI major ver(%d) doesn't match the TBM's ver(%d)\n",
451                         abimaj, vermaj);
452                 return 0;
453         } else if (abimin > vermin) {
454                 TBM_LOG_E("TBM module ABI minor ver(%d) is newer than the TBM's ver(%d)\n",
455                         abimin, vermin);
456                 return 0;
457         }
458         return 1;
459 }
460
461 static int
462 _tbm_bufmgr_load_module(tbm_bufmgr bufmgr, int fd, const char *file)
463 {
464         char path[PATH_MAX] = { 0, };
465         TBMModuleData *initdata = NULL;
466         void *module_data;
467
468         snprintf(path, sizeof(path), BUFMGR_MODULE_DIR "/%s", file);
469
470         module_data = dlopen(path, RTLD_LAZY);
471         if (!module_data) {
472                 TBM_LOG_E("failed to load module: %s(%s)\n",
473                         dlerror(), file);
474                 return 0;
475         }
476
477         initdata = dlsym(module_data, "tbmModuleData");
478         if (initdata) {
479                 ModuleInitProc init;
480                 TBMModuleVersionInfo *vers;
481
482                 vers = initdata->vers;
483                 init = initdata->init;
484
485                 if (vers) {
486                         if (!_check_version(vers)) {
487                                 dlclose(module_data);
488                                 return 0;
489                         }
490                 } else {
491                         TBM_LOG_E("Error: module does not supply version information.\n");
492
493                         dlclose(module_data);
494                         return 0;
495                 }
496
497                 if (init) {
498                         if (!init(bufmgr, fd)) {
499                                 TBM_LOG_E("Fail to init module(%s)\n",
500                                         file);
501                                 dlclose(module_data);
502                                 return 0;
503                         }
504
505                         if (!bufmgr->backend || !bufmgr->backend->priv) {
506                                 TBM_LOG_E("Error: module(%s) wrong operation. Check backend or backend's priv.\n",
507                                         file);
508                                 dlclose(module_data);
509                                 return 0;
510                         }
511                 } else {
512                         TBM_LOG_E("Error: module does not supply init symbol.\n");
513                         dlclose(module_data);
514                         return 0;
515                 }
516         } else {
517                 TBM_LOG_E("Error: module does not have data object.\n");
518                 dlclose(module_data);
519                 return 0;
520         }
521
522         bufmgr->module_data = module_data;
523
524         TBM_DBG("Success to load module(%s)\n",
525             file);
526
527         return 1;
528 }
529
530 static int
531 _tbm_load_module(tbm_bufmgr bufmgr, int fd)
532 {
533         struct dirent **namelist;
534         const char *p = NULL;
535         int n;
536         int ret = 0;
537
538         /* load bufmgr priv from default lib */
539         ret = _tbm_bufmgr_load_module(bufmgr, fd, DEFAULT_LIB);
540
541         /* load bufmgr priv from configured path */
542         if (!ret) {
543                 n = scandir(BUFMGR_MODULE_DIR, &namelist, 0, alphasort);
544                 if (n < 0) {
545                         TBM_LOG_E("no files : %s\n",
546                                 BUFMGR_MODULE_DIR);
547                 } else {
548                         while (n--) {
549                                 if (!ret && strstr(namelist[n]->d_name, PREFIX_LIB)) {
550                                         p = strstr(namelist[n]->d_name, SUFFIX_LIB);
551                                         if (p && !strcmp(p, SUFFIX_LIB))
552                                                 ret = _tbm_bufmgr_load_module(bufmgr, fd, namelist[n]->d_name);
553                                 }
554                                 free(namelist[n]);
555                         }
556                         free(namelist);
557                 }
558         }
559
560         return ret;
561 }
562 /* LCOV_EXCL_STOP */
563
564 tbm_bufmgr
565 tbm_bufmgr_init(int fd)
566 {
567         char *env;
568
569 #ifdef TBM_BUFMGR_INIT_TIME
570         struct timeval start_tv, end_tv;
571 #endif
572
573         pthread_mutex_lock(&gLock);
574
575 #ifdef TBM_BUFMGR_INIT_TIME
576         /* get the start tv */
577         gettimeofday(&start_tv, NULL);
578 #endif
579
580         /* LCOV_EXCL_START */
581 #ifdef HAVE_DLOG
582         env = getenv("TBM_DLOG");
583         if (env) {
584                 bDlog = atoi(env);
585                 TBM_LOG_D("TBM_DLOG=%s\n", env);
586         } else {
587                 bDlog = 1;
588         }
589 #endif
590
591 #ifdef DEBUG
592         env = getenv("TBM_DEBUG");
593         if (env) {
594                 bDebug = atoi(env);
595                 TBM_LOG_D("TBM_DEBUG=%s\n", env);
596         } else {
597                 bDebug = 0;
598         }
599 #endif
600
601 #ifdef TRACE
602         env = getenv("TBM_TRACE");
603         if (env) {
604                 bTrace = atoi(env);
605                 TBM_LOG_D("TBM_TRACE=%s\n", env);
606         } else {
607                 bTrace = 0;
608         }
609 #endif
610         /* LCOV_EXCL_STOP */
611
612         /* initialize buffer manager */
613         if (gBufMgr) {
614                 gBufMgr->ref_count++;
615                 TBM_TRACE("reuse  tbm_bufmgr(%p) ref_count(%d) fd(%d)\n", gBufMgr, gBufMgr->ref_count, gBufMgr->fd);
616                 pthread_mutex_unlock(&gLock);
617                 return gBufMgr;
618         }
619
620         TBM_DBG("bufmgr init\n");
621
622         /* allocate bufmgr */
623         gBufMgr = calloc(1, sizeof(struct _tbm_bufmgr));
624         if (!gBufMgr) {
625                 _tbm_set_last_result(TBM_BO_ERROR_HEAP_ALLOC_FAILED);
626                 TBM_TRACE("error: fail to alloc bufmgr fd(%d)\n", fd);
627                 pthread_mutex_unlock(&gLock);
628                 return NULL;
629         }
630
631         gBufMgr->fd = fd;
632
633         /* load bufmgr priv from env */
634         if (!_tbm_load_module(gBufMgr, gBufMgr->fd)) {
635                 /* LCOV_EXCL_START */
636                 _tbm_set_last_result(TBM_BO_ERROR_LOAD_MODULE_FAILED);
637                 TBM_LOG_E("error : Fail to load bufmgr backend\n");
638                 free(gBufMgr);
639                 gBufMgr = NULL;
640                 pthread_mutex_unlock(&gLock);
641                 return NULL;
642                 /* LCOV_EXCL_STOP */
643         }
644
645         /* log for tbm backend_flag */
646         TBM_DBG("backend flag:%x:", gBufMgr->backend->flags);
647         TBM_DBG("\n");
648
649         gBufMgr->ref_count = 1;
650
651         TBM_DBG("create tizen bufmgr:%p ref_count:%d\n",
652             gBufMgr, gBufMgr->ref_count);
653
654         /* setup the lock_type */
655         env = getenv("BUFMGR_LOCK_TYPE");
656         if (env && !strcmp(env, "always"))
657                 gBufMgr->lock_type = LOCK_TRY_ALWAYS;
658         else if (env && !strcmp(env, "none"))
659                 gBufMgr->lock_type = LOCK_TRY_NEVER;
660         else if (env && !strcmp(env, "once"))
661                 gBufMgr->lock_type = LOCK_TRY_ONCE;
662         else
663                 gBufMgr->lock_type = LOCK_TRY_ALWAYS;
664
665         TBM_DBG("BUFMGR_LOCK_TYPE=%s\n",
666             env ? env : "default:once");
667
668         TBM_TRACE("create tbm_bufmgr(%p) ref_count(%d) fd(%d)\n", gBufMgr, gBufMgr->ref_count, fd);
669
670         /* intialize bo_list */
671         LIST_INITHEAD(&gBufMgr->bo_list);
672
673         /* intialize surf_list */
674         LIST_INITHEAD(&gBufMgr->surf_list);
675
676         /* intialize surf_list */
677         LIST_INITHEAD(&gBufMgr->surf_queue_list);
678
679         /* intialize debug_key_list */
680         LIST_INITHEAD(&gBufMgr->debug_key_list);
681
682 #ifdef TBM_BUFMGR_INIT_TIME
683         /* get the end tv */
684         gettimeofday(&end_tv, NULL);
685         TBM_LOG_I("tbm_bufmgr_init time: %ld ms", ((end_tv.tv_sec * 1000 + end_tv.tv_usec / 1000) - (start_tv.tv_sec * 1000 + start_tv.tv_usec / 1000)));
686 #endif
687
688         pthread_mutex_unlock(&gLock);
689
690         return gBufMgr;
691 }
692
693 void
694 tbm_bufmgr_deinit(tbm_bufmgr bufmgr)
695 {
696         TBM_RETURN_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr));
697
698         tbm_bo bo = NULL;
699         tbm_bo tmp = NULL;
700
701         tbm_surface_h surf = NULL;
702         tbm_surface_h tmp_surf = NULL;
703
704         pthread_mutex_lock(&gLock);
705
706         if (!gBufMgr) {
707                 TBM_LOG_E("gBufmgr already destroy: bufmgr:%p\n", bufmgr);
708                 pthread_mutex_unlock(&gLock);
709                 return;
710         }
711
712         bufmgr->ref_count--;
713         if (bufmgr->ref_count > 0) {
714                 TBM_TRACE("reduce a ref_count(%d) of tbm_bufmgr(%p)\n", bufmgr->ref_count, bufmgr);
715                 pthread_mutex_unlock(&gLock);
716                 return;
717         }
718
719         /* destroy bo_list */
720         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
721                 LIST_FOR_EACH_ENTRY_SAFE(bo, tmp, &bufmgr->bo_list, item_link) {
722                         TBM_LOG_E("Un-freed bo(%p, ref:%d)\n",
723                                 bo, bo->ref_cnt);
724                         bo->ref_cnt = 1;
725                         tbm_bo_unref(bo);
726                 }
727         }
728
729         /* destroy surf_list */
730         if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
731                 LIST_FOR_EACH_ENTRY_SAFE(surf, tmp_surf, &bufmgr->surf_list, item_link) {
732                         TBM_LOG_E("Un-freed surf(%p, ref:%d)\n",
733                                 surf, surf->refcnt);
734                         tbm_surface_destroy(surf);
735                 }
736         }
737
738         /* destroy bufmgr priv */
739         bufmgr->backend->bufmgr_deinit(bufmgr->backend->priv);
740         bufmgr->backend->priv = NULL;
741         tbm_backend_free(bufmgr->backend);
742         bufmgr->backend = NULL;
743
744         TBM_TRACE("destroy tbm_bufmgr(%p)\n", bufmgr);
745
746         dlclose(bufmgr->module_data);
747
748         if (bufmgr->fd > 0)
749                 close(bufmgr->fd);
750
751         free(bufmgr);
752         bufmgr = NULL;
753         gBufMgr = NULL;
754
755         pthread_mutex_unlock(&gLock);
756 }
757
758 int
759 tbm_bo_size(tbm_bo bo)
760 {
761         tbm_bufmgr bufmgr = NULL;
762         int size;
763
764         _tbm_bufmgr_mutex_lock();
765
766         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
767         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
768
769         bufmgr = gBufMgr;
770
771         size = bufmgr->backend->bo_size(bo);
772
773         TBM_TRACE("bo(%p) size(%d)\n", bo, size);
774
775         _tbm_bufmgr_mutex_unlock();
776
777         return size;
778 }
779
780 tbm_bo
781 tbm_bo_ref(tbm_bo bo)
782 {
783         _tbm_bufmgr_mutex_lock();
784
785         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), NULL);
786         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), NULL);
787
788         bo->ref_cnt++;
789
790         TBM_TRACE("bo(%p) ref_cnt(%d)\n", bo, bo->ref_cnt);
791
792         _tbm_bufmgr_mutex_unlock();
793
794         return bo;
795 }
796
797 void
798 tbm_bo_unref(tbm_bo bo)
799 {
800         tbm_bufmgr bufmgr = NULL;
801         tbm_user_data *old_data = NULL, *tmp = NULL;
802
803         _tbm_bufmgr_mutex_lock();
804
805         TBM_BUFMGR_RETURN_IF_FAIL(gBufMgr);
806         TBM_BUFMGR_RETURN_IF_FAIL(_tbm_bo_is_valid(bo));
807
808         bufmgr = gBufMgr;
809
810         TBM_TRACE("bo(%p) ref_cnt(%d)\n", bo, bo->ref_cnt - 1);
811
812         if (bo->ref_cnt <= 0) {
813                 _tbm_bufmgr_mutex_unlock();
814                 return;
815         }
816
817         bo->ref_cnt--;
818         if (bo->ref_cnt == 0) {
819                 /* destory the user_data_list */
820                 if (!LIST_IS_EMPTY(&bo->user_data_list)) {
821                         LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp, &bo->user_data_list, item_link) {
822                                 TBM_DBG("free user_data\n");
823                                 user_data_delete(old_data);
824                         }
825                 }
826
827                 if (bo->lock_cnt > 0) {
828                         TBM_LOG_E("error lock_cnt:%d\n",
829                                 bo->lock_cnt);
830                         _bo_unlock(bo);
831                 }
832
833                 /* call the bo_free */
834                 bufmgr->backend->bo_free(bo);
835                 bo->priv = NULL;
836
837                 LIST_DEL(&bo->item_link);
838                 free(bo);
839
840                 bufmgr->bo_cnt--;
841         }
842
843         _tbm_bufmgr_mutex_unlock();
844 }
845
846 tbm_bo
847 tbm_bo_alloc(tbm_bufmgr bufmgr, int size, int flags)
848 {
849         tbm_bo bo = NULL;
850         void *bo_priv = NULL;
851
852         _tbm_bufmgr_mutex_lock();
853
854         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
855         TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, NULL);
856         TBM_BUFMGR_RETURN_VAL_IF_FAIL(size > 0, NULL);
857
858         bo = calloc(1, sizeof(struct _tbm_bo));
859         if (!bo) {
860                 TBM_TRACE("error: fail to create of tbm_bo size(%d) flag(%s)\n", size, tbm_flag_to_str(flags));
861                 _tbm_set_last_result(TBM_BO_ERROR_HEAP_ALLOC_FAILED);
862                 _tbm_bufmgr_mutex_unlock();
863                 return NULL;
864         }
865
866         _tbm_util_check_bo_cnt(bufmgr);
867         bufmgr->bo_cnt++;
868
869         bo->bufmgr = bufmgr;
870
871         bo_priv = bufmgr->backend->bo_alloc(bo, size, flags);
872         if (!bo_priv) {
873                 TBM_TRACE("error: fail to create of tbm_bo size(%d) flag(%s)\n", size, tbm_flag_to_str(flags));
874                 _tbm_set_last_result(TBM_BO_ERROR_BO_ALLOC_FAILED);
875                 free(bo);
876                 _tbm_bufmgr_mutex_unlock();
877                 return NULL;
878         }
879
880         bo->ref_cnt = 1;
881         bo->flags = flags;
882         bo->priv = bo_priv;
883
884         TBM_TRACE("bo(%p) size(%d) refcnt(%d), flag(%s)\n", bo, size, bo->ref_cnt, tbm_flag_to_str(bo->flags));
885
886         LIST_INITHEAD(&bo->user_data_list);
887
888         LIST_ADD(&bo->item_link, &bufmgr->bo_list);
889
890         _tbm_bufmgr_mutex_unlock();
891
892         return bo;
893 }
894
895 tbm_bo
896 tbm_bo_import(tbm_bufmgr bufmgr, unsigned int key)
897 {
898         tbm_bo bo = NULL;
899         tbm_bo bo2 = NULL;
900         tbm_bo tmp = NULL;
901         void *bo_priv = NULL;
902
903         _tbm_bufmgr_mutex_lock();
904
905         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
906         TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, NULL);
907
908         if (!bufmgr->backend->bo_import) {
909                 _tbm_bufmgr_mutex_unlock();
910                 return NULL;
911         }
912
913         _tbm_util_check_bo_cnt(bufmgr);
914
915         bo = calloc(1, sizeof(struct _tbm_bo));
916         if (!bo) {
917                 TBM_TRACE("error: fail to import of tbm_bo by key(%d)\n", key);
918                 _tbm_bufmgr_mutex_unlock();
919                 return NULL;
920         }
921
922         bufmgr->bo_cnt++;
923
924         bo->bufmgr = bufmgr;
925
926         bo_priv = bufmgr->backend->bo_import(bo, key);
927         if (!bo_priv) {
928                 TBM_TRACE("error: fail to import of tbm_bo by key(%d)\n", key);
929                 _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FAILED);
930                 free(bo);
931                 _tbm_bufmgr_mutex_unlock();
932                 return NULL;
933         }
934
935         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
936                 LIST_FOR_EACH_ENTRY_SAFE(bo2, tmp, &bufmgr->bo_list, item_link) {
937                         if (bo2->priv == bo_priv) {
938                                 TBM_TRACE("find bo(%p) ref(%d) key(%d) flag(%s) in list\n",
939                                                         bo2, bo2->ref_cnt, key, tbm_flag_to_str(bo2->flags));
940                                 bo2->ref_cnt++;
941                                 free(bo);
942                                 _tbm_bufmgr_mutex_unlock();
943                                 return bo2;
944                         }
945                 }
946         }
947
948         bo->ref_cnt = 1;
949         bo->priv = bo_priv;
950
951         if (bufmgr->backend->bo_get_flags)
952                 bo->flags = bufmgr->backend->bo_get_flags(bo);
953         else
954                 bo->flags = TBM_BO_DEFAULT;
955
956         TBM_TRACE("import new bo(%p) ref(%d) key(%d) flag(%s) in list\n",
957                           bo, bo->ref_cnt, key, tbm_flag_to_str(bo->flags));
958
959         LIST_INITHEAD(&bo->user_data_list);
960
961         LIST_ADD(&bo->item_link, &bufmgr->bo_list);
962
963         _tbm_bufmgr_mutex_unlock();
964
965         return bo;
966 }
967
968 tbm_bo
969 tbm_bo_import_fd(tbm_bufmgr bufmgr, tbm_fd fd)
970 {
971         tbm_bo bo = NULL;
972         tbm_bo bo2 = NULL;
973         tbm_bo tmp = NULL;
974         void *bo_priv = NULL;
975
976         _tbm_bufmgr_mutex_lock();
977
978         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
979         TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, NULL);
980
981         if (!bufmgr->backend->bo_import_fd) {
982                 _tbm_bufmgr_mutex_unlock();
983                 return NULL;
984         }
985
986         _tbm_util_check_bo_cnt(bufmgr);
987
988         bo = calloc(1, sizeof(struct _tbm_bo));
989         if (!bo) {
990                 TBM_TRACE("error: fail to import tbm_bo by tbm_fd(%d)\n", fd);
991                 _tbm_bufmgr_mutex_unlock();
992                 return NULL;
993         }
994
995         bufmgr->bo_cnt++;
996
997         bo->bufmgr = bufmgr;
998
999         bo_priv = bufmgr->backend->bo_import_fd(bo, fd);
1000         if (!bo_priv) {
1001                 TBM_TRACE("error: fail to import tbm_bo by tbm_fd(%d)\n", fd);
1002                 _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FD_FAILED);
1003                 free(bo);
1004                 _tbm_bufmgr_mutex_unlock();
1005                 return NULL;
1006         }
1007
1008         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
1009                 LIST_FOR_EACH_ENTRY_SAFE(bo2, tmp, &bufmgr->bo_list, item_link) {
1010                         if (bo2->priv == bo_priv) {
1011                                 TBM_TRACE("find bo(%p) ref(%d) fd(%d) flag(%s) in list\n",
1012                                                         bo2, bo2->ref_cnt, fd, tbm_flag_to_str(bo2->flags));
1013                                 bo2->ref_cnt++;
1014                                 free(bo);
1015                                 _tbm_bufmgr_mutex_unlock();
1016                                 return bo2;
1017                         }
1018                 }
1019         }
1020
1021         bo->ref_cnt = 1;
1022         bo->priv = bo_priv;
1023
1024         if (bufmgr->backend->bo_get_flags)
1025                 bo->flags = bufmgr->backend->bo_get_flags(bo);
1026         else
1027                 bo->flags = TBM_BO_DEFAULT;
1028
1029         TBM_TRACE("import bo(%p) ref(%d) fd(%d) flag(%s)in list\n",
1030                                 bo, bo->ref_cnt, fd, tbm_flag_to_str(bo->flags));
1031
1032         LIST_INITHEAD(&bo->user_data_list);
1033
1034         LIST_ADD(&bo->item_link, &bufmgr->bo_list);
1035
1036         _tbm_bufmgr_mutex_unlock();
1037
1038         return bo;
1039 }
1040
1041 tbm_key
1042 tbm_bo_export(tbm_bo bo)
1043 {
1044         tbm_bufmgr bufmgr = NULL;
1045         tbm_key ret;
1046
1047         _tbm_bufmgr_mutex_lock();
1048
1049         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1050         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1051
1052         bufmgr = gBufMgr;
1053
1054         if (!bufmgr->backend->bo_export) {
1055                 _tbm_bufmgr_mutex_unlock();
1056                 return 0;
1057         }
1058
1059         ret = bufmgr->backend->bo_export(bo);
1060         if (!ret) {
1061                 _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FAILED);
1062                 TBM_TRACE("error: bo(%p) tbm_key(%d)\n", bo, ret);
1063                 _tbm_bufmgr_mutex_unlock();
1064                 return ret;
1065         }
1066
1067         TBM_TRACE("bo(%p) tbm_key(%d)\n", bo, ret);
1068
1069         _tbm_bufmgr_mutex_unlock();
1070
1071         return ret;
1072 }
1073
1074 tbm_fd
1075 tbm_bo_export_fd(tbm_bo bo)
1076 {
1077         tbm_bufmgr bufmgr = NULL;
1078         int ret;
1079
1080         _tbm_bufmgr_mutex_lock();
1081
1082         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), -1);
1083         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), -1);
1084
1085         bufmgr = gBufMgr;
1086
1087         if (!bufmgr->backend->bo_export_fd) {
1088                 _tbm_bufmgr_mutex_unlock();
1089                 return -1;
1090         }
1091
1092         ret = bufmgr->backend->bo_export_fd(bo);
1093         if (ret < 0) {
1094                 _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FD_FAILED);
1095                 TBM_TRACE("error: bo(%p) tbm_fd(%d)\n", bo, ret);
1096                 _tbm_bufmgr_mutex_unlock();
1097                 return ret;
1098         }
1099
1100         TBM_TRACE("bo(%p) tbm_fd(%d)\n", bo, ret);
1101
1102         _tbm_bufmgr_mutex_unlock();
1103
1104         return ret;
1105 }
1106
1107 tbm_bo_handle
1108 tbm_bo_get_handle(tbm_bo bo, int device)
1109 {
1110         tbm_bufmgr bufmgr = NULL;
1111         tbm_bo_handle bo_handle;
1112
1113         _tbm_bufmgr_mutex_lock();
1114
1115         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), (tbm_bo_handle) NULL);
1116         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) NULL);
1117
1118         bufmgr = gBufMgr;
1119
1120         bo_handle = bufmgr->backend->bo_get_handle(bo, device);
1121         if (bo_handle.ptr == NULL) {
1122                 _tbm_set_last_result(TBM_BO_ERROR_GET_HANDLE_FAILED);
1123                 TBM_TRACE("error: bo(%p) bo_handle(%p)\n", bo, bo_handle.ptr);
1124                 _tbm_bufmgr_mutex_unlock();
1125                 return (tbm_bo_handle) NULL;
1126         }
1127
1128         TBM_TRACE("bo(%p) bo_handle(%p)\n", bo, bo_handle.ptr);
1129
1130         _tbm_bufmgr_mutex_unlock();
1131
1132         return bo_handle;
1133 }
1134
1135 tbm_bo_handle
1136 tbm_bo_map(tbm_bo bo, int device, int opt)
1137 {
1138         tbm_bufmgr bufmgr = NULL;
1139         tbm_bo_handle bo_handle;
1140
1141         _tbm_bufmgr_mutex_lock();
1142
1143         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), (tbm_bo_handle) NULL);
1144         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) NULL);
1145
1146         bufmgr = gBufMgr;
1147
1148         if (!_tbm_bo_lock(bo, device, opt)) {
1149                 _tbm_set_last_result(TBM_BO_ERROR_LOCK_FAILED);
1150                 TBM_TRACE("error: fail to lock bo:%p)\n", bo);
1151                 _tbm_bufmgr_mutex_unlock();
1152                 return (tbm_bo_handle) NULL;
1153         }
1154
1155         bo_handle = bufmgr->backend->bo_map(bo, device, opt);
1156         if (bo_handle.ptr == NULL) {
1157                 _tbm_set_last_result(TBM_BO_ERROR_MAP_FAILED);
1158                 TBM_TRACE("error: fail to map bo:%p\n", bo);
1159                 _tbm_bo_unlock(bo);
1160                 _tbm_bufmgr_mutex_unlock();
1161                 return (tbm_bo_handle) NULL;
1162         }
1163
1164         /* increase the map_count */
1165         bo->map_cnt++;
1166
1167         TBM_TRACE("bo(%p) map_cnt(%d)\n", bo, bo->map_cnt);
1168
1169         _tbm_bufmgr_mutex_unlock();
1170
1171         return bo_handle;
1172 }
1173
1174 int
1175 tbm_bo_unmap(tbm_bo bo)
1176 {
1177         tbm_bufmgr bufmgr = NULL;
1178         int ret;
1179
1180         _tbm_bufmgr_mutex_lock();
1181
1182         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1183         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1184
1185         bufmgr = gBufMgr;
1186
1187         ret = bufmgr->backend->bo_unmap(bo);
1188         if (!ret) {
1189                 TBM_TRACE("error: bo(%p) map_cnt(%d)\n", bo, bo->map_cnt);
1190                 _tbm_set_last_result(TBM_BO_ERROR_UNMAP_FAILED);
1191                 _tbm_bufmgr_mutex_unlock();
1192                 return ret;
1193         }
1194
1195         /* decrease the map_count */
1196         bo->map_cnt--;
1197
1198         TBM_TRACE("bo(%p) map_cnt(%d)\n", bo, bo->map_cnt);
1199
1200         _tbm_bo_unlock(bo);
1201
1202         _tbm_bufmgr_mutex_unlock();
1203
1204         return ret;
1205 }
1206
1207 int
1208 tbm_bo_swap(tbm_bo bo1, tbm_bo bo2)
1209 {
1210         tbm_bufmgr bufmgr = NULL;
1211         void *temp;
1212
1213         _tbm_bufmgr_mutex_lock();
1214
1215         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1216         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo1), 0);
1217         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo2), 0);
1218
1219         bufmgr = gBufMgr;
1220
1221         TBM_TRACE("before: bo1(%p) bo2(%p)\n", bo1, bo2);
1222
1223         if (bufmgr->backend->bo_size(bo1) != bufmgr->backend->bo_size(bo2)) {
1224                 _tbm_set_last_result(TBM_BO_ERROR_SWAP_FAILED);
1225                 TBM_TRACE("error: bo1(%p) bo2(%p)\n", bo1, bo2);
1226                 _tbm_bufmgr_mutex_unlock();
1227                 return 0;
1228         }
1229
1230         TBM_TRACE("after: bo1(%p) bo2(%p)\n", bo1, bo2);
1231
1232         temp = bo1->priv;
1233         bo1->priv = bo2->priv;
1234         bo2->priv = temp;
1235
1236         _tbm_bufmgr_mutex_unlock();
1237
1238         return 1;
1239 }
1240
1241 int
1242 tbm_bo_locked(tbm_bo bo)
1243 {
1244         tbm_bufmgr bufmgr = NULL;
1245
1246         _tbm_bufmgr_mutex_lock();
1247
1248         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1249         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1250
1251         bufmgr = gBufMgr;
1252
1253         if (bufmgr->lock_type == LOCK_TRY_NEVER) {
1254                 TBM_TRACE("bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
1255                 _tbm_bufmgr_mutex_unlock();
1256                 return 0;
1257         }
1258
1259         if (bo->lock_cnt > 0) {
1260                 TBM_TRACE("error: bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
1261                 _tbm_bufmgr_mutex_unlock();
1262                 return 1;
1263         }
1264
1265         TBM_TRACE("bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
1266         _tbm_bufmgr_mutex_unlock();
1267
1268         return 0;
1269 }
1270
1271 int
1272 tbm_bo_add_user_data(tbm_bo bo, unsigned long key,
1273                      tbm_data_free data_free_func)
1274 {
1275         tbm_user_data *data;
1276
1277         _tbm_bufmgr_mutex_lock();
1278
1279         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1280         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1281
1282         /* check if the data according to the key exist if so, return false. */
1283         data = user_data_lookup(&bo->user_data_list, key);
1284         if (data) {
1285                 TBM_TRACE("warning: user data already exist key(%ld)\n", key);
1286                 _tbm_bufmgr_mutex_unlock();
1287                 return 0;
1288         }
1289
1290         data = user_data_create(key, data_free_func);
1291         if (!data) {
1292                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1293                 _tbm_bufmgr_mutex_unlock();
1294                 return 0;
1295         }
1296
1297         TBM_TRACE("bo(%p) key(%lu) data(%p)\n", bo, key, data->data);
1298
1299         LIST_ADD(&data->item_link, &bo->user_data_list);
1300
1301         _tbm_bufmgr_mutex_unlock();
1302
1303         return 1;
1304 }
1305
1306 int
1307 tbm_bo_set_user_data(tbm_bo bo, unsigned long key, void *data)
1308 {
1309         tbm_user_data *old_data;
1310
1311         _tbm_bufmgr_mutex_lock();
1312
1313         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1314         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1315
1316         if (LIST_IS_EMPTY(&bo->user_data_list)) {
1317                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1318                 _tbm_bufmgr_mutex_unlock();
1319                 return 0;
1320         }
1321
1322         old_data = user_data_lookup(&bo->user_data_list, key);
1323         if (!old_data) {
1324                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1325                 _tbm_bufmgr_mutex_unlock();
1326                 return 0;
1327         }
1328
1329         if (old_data->data && old_data->free_func)
1330                 old_data->free_func(old_data->data);
1331
1332         old_data->data = data;
1333
1334         TBM_TRACE("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
1335
1336         _tbm_bufmgr_mutex_unlock();
1337
1338         return 1;
1339 }
1340
1341 int
1342 tbm_bo_get_user_data(tbm_bo bo, unsigned long key, void **data)
1343 {
1344         tbm_user_data *old_data;
1345
1346         _tbm_bufmgr_mutex_lock();
1347
1348         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1349         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1350
1351         if (!data || LIST_IS_EMPTY(&bo->user_data_list)) {
1352                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1353                 _tbm_bufmgr_mutex_unlock();
1354                 return 0;
1355         }
1356
1357         old_data = user_data_lookup(&bo->user_data_list, key);
1358         if (!old_data) {
1359                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1360                 *data = NULL;
1361                 _tbm_bufmgr_mutex_unlock();
1362                 return 0;
1363         }
1364
1365         *data = old_data->data;
1366
1367         TBM_TRACE("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
1368
1369         _tbm_bufmgr_mutex_unlock();
1370
1371         return 1;
1372 }
1373
1374 int
1375 tbm_bo_delete_user_data(tbm_bo bo, unsigned long key)
1376 {
1377         tbm_user_data *old_data = (void *)0;
1378
1379         _tbm_bufmgr_mutex_lock();
1380
1381         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1382         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1383
1384         if (LIST_IS_EMPTY(&bo->user_data_list)) {
1385                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1386                 _tbm_bufmgr_mutex_unlock();
1387                 return 0;
1388         }
1389
1390         old_data = user_data_lookup(&bo->user_data_list, key);
1391         if (!old_data) {
1392                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1393                 _tbm_bufmgr_mutex_unlock();
1394                 return 0;
1395         }
1396
1397         TBM_TRACE("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
1398
1399         user_data_delete(old_data);
1400
1401         _tbm_bufmgr_mutex_unlock();
1402
1403         return 1;
1404 }
1405
1406 unsigned int
1407 tbm_bufmgr_get_capability(tbm_bufmgr bufmgr)
1408 {
1409         int capabilities = TBM_BUFMGR_CAPABILITY_NONE;
1410
1411         _tbm_bufmgr_mutex_lock();
1412
1413         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), TBM_BUFMGR_CAPABILITY_NONE);
1414         TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, TBM_BUFMGR_CAPABILITY_NONE);
1415
1416         TBM_TRACE("tbm_bufmgr(%p) capability(%d)\n", bufmgr, bufmgr->capabilities);
1417
1418         capabilities = bufmgr->capabilities;
1419
1420         _tbm_bufmgr_mutex_unlock();
1421
1422         return capabilities;
1423 }
1424
1425 int
1426 tbm_bo_get_flags(tbm_bo bo)
1427 {
1428         int flags;
1429
1430         _tbm_bufmgr_mutex_lock();
1431
1432         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1433         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1434
1435         flags = bo->flags;
1436
1437         TBM_TRACE("bo(%p)\n", bo);
1438
1439         _tbm_bufmgr_mutex_unlock();
1440
1441         return flags;
1442 }
1443
1444 /* LCOV_EXCL_START */
1445 tbm_error_e
1446 tbm_get_last_error(void)
1447 {
1448         return tbm_last_error;
1449 }
1450
1451 void
1452 tbm_bufmgr_debug_show(tbm_bufmgr bufmgr)
1453 {
1454         tbm_bo bo = NULL, tmp_bo = NULL;
1455         int bo_cnt = 0;
1456         tbm_surface_h surf = NULL, tmp_surf = NULL;
1457         int surf_cnt = 0;
1458         int i;
1459         char app_name[255] = {0,};
1460         unsigned int pid = 0;
1461         char title[255] = {0,};
1462         char data[255] = {0,};
1463         tbm_surface_debug_data *debug_old_data = NULL, *debug_tmp = NULL;
1464
1465         pthread_mutex_lock(&gLock);
1466
1467         if (!TBM_BUFMGR_IS_VALID(bufmgr) || (bufmgr != gBufMgr)) {
1468                 TBM_LOG_E("invalid bufmgr\n");
1469                 pthread_mutex_unlock(&gLock);
1470                 return;
1471         }
1472
1473         TBM_DEBUG("\n");
1474         _tbm_util_get_appname_from_pid(getpid(), app_name);
1475         _tbm_util_get_appname_brief(app_name);
1476         TBM_DEBUG("============TBM DEBUG: %s(%d)===========================\n",
1477                   app_name, getpid());
1478         memset(app_name, 0x0, 255 * sizeof(char));
1479         snprintf(title, 255, "%s", "no  surface     refcnt  width  height  bpp  size    n_b  n_p  flags  format    app_name       ");
1480         if (!LIST_IS_EMPTY(&bufmgr->debug_key_list)) {
1481                 LIST_FOR_EACH_ENTRY_SAFE(debug_old_data, debug_tmp, &bufmgr->debug_key_list, item_link) {
1482                         strncat(title, "  ", 3);
1483                         strncat(title, debug_old_data->key, strlen(debug_old_data->key) + 1);
1484                 }
1485         }
1486
1487         TBM_DEBUG("[tbm_surface information]\n");
1488         TBM_DEBUG("%s\n", title);
1489         /* show the tbm_surface information in surf_list */
1490         if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
1491                 char *value = NULL;
1492
1493                 LIST_FOR_EACH_ENTRY_SAFE(surf, tmp_surf, &bufmgr->surf_list, item_link) {
1494                         pid = _tbm_surface_internal_get_debug_pid(surf);
1495                         if (!pid) {
1496                                 /* if pid is null, set the self_pid */
1497                                 pid = getpid();
1498                         }
1499
1500                         _tbm_util_get_appname_from_pid(pid, app_name);
1501                         _tbm_util_get_appname_brief(app_name);
1502
1503                         snprintf(data, 255, "%-2d  %-9p    %-4d  %-5d  %-6d  %-3d  %-6d   %-2d   %-2d    %-3d  %-8s  %-15s",
1504                                   ++surf_cnt,
1505                                   surf,
1506                                   surf->refcnt,
1507                                   surf->info.width,
1508                                   surf->info.height,
1509                                   surf->info.bpp,
1510                                   surf->info.size / 1024,
1511                                   surf->num_bos,
1512                                   surf->num_planes,
1513                                   surf->flags,
1514                                   _tbm_surface_internal_format_to_str(surf->info.format) + 11,
1515                                   app_name);
1516
1517                         if (!LIST_IS_EMPTY(&bufmgr->debug_key_list)) {
1518                                 LIST_FOR_EACH_ENTRY_SAFE(debug_old_data, debug_tmp, &bufmgr->debug_key_list, item_link) {
1519                                         strncat(data, "  ", 3);
1520
1521                                         value = _tbm_surface_internal_get_debug_data(surf, debug_old_data->key);
1522                                         if (value)
1523                                                 strncat(data, value, strlen(value) + 1);
1524                                         else
1525                                                 strncat(data, "none", 5);
1526                                 }
1527                         }
1528                         TBM_DEBUG("%s\n", data);
1529
1530                         for (i = 0; i < surf->num_bos; i++) {
1531                                 TBM_DEBUG(" bo:%-12p  %-26d%-10d\n",
1532                                           surf->bos[i],
1533                                           surf->bos[i]->ref_cnt,
1534                                           bufmgr->backend->bo_size(bo) / 1024);
1535                         }
1536
1537                         memset(app_name, 0x0, 255 * sizeof(char));
1538                 }
1539         } else {
1540                 TBM_DEBUG("no tbm_surfaces.\n");
1541         }
1542         TBM_DEBUG("\n");
1543
1544         TBM_DEBUG("[tbm_bo information]\n");
1545         TBM_DEBUG("no  bo          refcnt  size    lock_cnt  map_cnt  flags  surface\n");
1546
1547         /* show the tbm_bo information in bo_list */
1548         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
1549                 LIST_FOR_EACH_ENTRY_SAFE(bo, tmp_bo, &bufmgr->bo_list, item_link) {
1550                         TBM_DEBUG("%-4d%-11p   %-4d  %-6d     %-5d     %-4d    %-3d  %-11p\n",
1551                                   ++bo_cnt,
1552                                   bo,
1553                                   bo->ref_cnt,
1554                                   bufmgr->backend->bo_size(bo) / 1024,
1555                                   bo->lock_cnt,
1556                                   bo->map_cnt,
1557                                   bo->flags,
1558                                   bo->surface);
1559                 }
1560         } else {
1561                 TBM_DEBUG("no tbm_bos.\n");
1562         }
1563         TBM_DEBUG("\n");
1564
1565         TBM_DEBUG("===============================================================\n");
1566
1567         pthread_mutex_unlock(&gLock);
1568 }
1569
1570 void
1571 tbm_bufmgr_debug_trace(tbm_bufmgr bufmgr, int onoff)
1572 {
1573         _tbm_bufmgr_mutex_lock();
1574
1575         TBM_BUFMGR_RETURN_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr));
1576         TBM_BUFMGR_RETURN_IF_FAIL(bufmgr == gBufMgr);
1577
1578 #ifdef TRACE
1579         TBM_LOG_D("bufmgr=%p onoff=%d\n", bufmgr, onoff);
1580         bTrace = onoff;
1581 #endif
1582
1583         _tbm_bufmgr_mutex_unlock();
1584 }
1585
1586 int
1587 tbm_bufmgr_debug_queue_dump(char *path, int count, int onoff)
1588 {
1589         int w = 0, h = 0;
1590
1591         TBM_RETURN_VAL_IF_FAIL(path != NULL, 0);
1592         TBM_LOG_D("path=%s count=%d onoff=%d\n", path, count, onoff);
1593
1594         pthread_mutex_lock(&gLock);
1595
1596         if (onoff == 1) {
1597                 if (_tbm_util_get_max_surface_size(&w, &h) == 0) {
1598                         TBM_LOG_I("No tbm_surface.\n");
1599                         pthread_mutex_unlock(&gLock);
1600                         return 0;
1601                 }
1602
1603                 tbm_surface_internal_dump_start(path, w, h, count);
1604                 b_dump_queue = 1;
1605         } else if (onoff == 0) {
1606                 tbm_surface_internal_dump_end();
1607                 b_dump_queue = 0;
1608         } else {
1609                 pthread_mutex_unlock(&gLock);
1610                 return 0;
1611         }
1612
1613         pthread_mutex_unlock(&gLock);
1614         return 1;
1615 }
1616
1617 int
1618 tbm_bufmgr_debug_dump_all(char *path)
1619 {
1620         int w = 0, h = 0, count = 0;
1621         tbm_surface_h surface = NULL, tmp = NULL;
1622
1623         TBM_RETURN_VAL_IF_FAIL(path != NULL, 0);
1624         TBM_LOG_D("path=%s\n", path);
1625
1626         pthread_mutex_lock(&gLock);
1627
1628         count = _tbm_util_get_max_surface_size(&w, &h);
1629         if (count == 0) {
1630                 TBM_LOG_I("No tbm_surface.\n");
1631                 pthread_mutex_unlock(&gLock);
1632                 return 1;
1633         }
1634
1635         tbm_surface_internal_dump_start(path, w, h, count);
1636
1637         LIST_FOR_EACH_ENTRY_SAFE(surface, tmp, &gBufMgr->surf_list, item_link) {
1638                 tbm_surface_internal_dump_buffer(surface, "dump_all");
1639         }
1640
1641         tbm_surface_internal_dump_end();
1642
1643         pthread_mutex_unlock(&gLock);
1644
1645         return 1;
1646 }
1647
1648 /* internal function */
1649 tbm_bufmgr
1650 _tbm_bufmgr_get_bufmgr(void)
1651 {
1652         return gBufMgr;
1653 }
1654
1655 int
1656 _tbm_bo_set_surface(tbm_bo bo, tbm_surface_h surface)
1657 {
1658         _tbm_bufmgr_mutex_lock();
1659
1660         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1661         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1662
1663         bo->surface = surface;
1664
1665         _tbm_bufmgr_mutex_unlock();
1666
1667         return 1;
1668 }
1669
1670 int
1671 tbm_bufmgr_bind_native_display(tbm_bufmgr bufmgr, void *NativeDisplay)
1672 {
1673         int ret;
1674
1675         _tbm_bufmgr_mutex_lock();
1676
1677         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1678
1679         if (!bufmgr->backend->bufmgr_bind_native_display) {
1680                 TBM_TRACE("error: tbm_bufmgr(%p) NativeDisplay(%p)\n", bufmgr, NativeDisplay);
1681                 _tbm_bufmgr_mutex_unlock();
1682                 return 1;
1683         }
1684
1685         ret = bufmgr->backend->bufmgr_bind_native_display(bufmgr, NativeDisplay);
1686         if (!ret) {
1687                 TBM_TRACE("error: tbm_bufmgr(%p) NativeDisplay(%p)\n", bufmgr, NativeDisplay);
1688                 _tbm_bufmgr_mutex_unlock();
1689                 return 0;
1690         }
1691
1692         TBM_TRACE("tbm_bufmgr(%p) NativeDisplay(%p)\n", bufmgr, NativeDisplay);
1693
1694         _tbm_bufmgr_mutex_unlock();
1695
1696         return 1;
1697 }
1698 /* LCOV_EXCL_STOP */