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