tbm_bufmgr, tbm_surface_internal: clean up LIST relevant 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 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;
255
256         if (!LIST_IS_EMPTY(user_data_list)) {
257                 LIST_FOR_EACH_ENTRY(old_data, 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                 while (bo->lock_cnt > 0) {
828                         TBM_LOG_E("error lock_cnt:%d\n",
829                                 bo->lock_cnt);
830                         _bo_unlock(bo);
831                         bo->lock_cnt--;
832                 }
833
834                 /* call the bo_free */
835                 bufmgr->backend->bo_free(bo);
836                 bo->priv = NULL;
837
838                 LIST_DEL(&bo->item_link);
839                 free(bo);
840
841                 bufmgr->bo_cnt--;
842         }
843
844         _tbm_bufmgr_mutex_unlock();
845 }
846
847 tbm_bo
848 tbm_bo_alloc(tbm_bufmgr bufmgr, int size, int flags)
849 {
850         tbm_bo bo = NULL;
851         void *bo_priv = NULL;
852
853         _tbm_bufmgr_mutex_lock();
854
855         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
856         TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, NULL);
857         TBM_BUFMGR_RETURN_VAL_IF_FAIL(size > 0, NULL);
858
859         bo = calloc(1, sizeof(struct _tbm_bo));
860         if (!bo) {
861                 TBM_TRACE("error: fail to create of tbm_bo size(%d) flag(%s)\n", size, tbm_flag_to_str(flags));
862                 _tbm_set_last_result(TBM_BO_ERROR_HEAP_ALLOC_FAILED);
863                 _tbm_bufmgr_mutex_unlock();
864                 return NULL;
865         }
866
867         _tbm_util_check_bo_cnt(bufmgr);
868         bufmgr->bo_cnt++;
869
870         bo->bufmgr = bufmgr;
871
872         bo_priv = bufmgr->backend->bo_alloc(bo, size, flags);
873         if (!bo_priv) {
874                 TBM_TRACE("error: fail to create of tbm_bo size(%d) flag(%s)\n", size, tbm_flag_to_str(flags));
875                 _tbm_set_last_result(TBM_BO_ERROR_BO_ALLOC_FAILED);
876                 free(bo);
877                 _tbm_bufmgr_mutex_unlock();
878                 return NULL;
879         }
880
881         bo->ref_cnt = 1;
882         bo->flags = flags;
883         bo->priv = bo_priv;
884
885         TBM_TRACE("bo(%p) size(%d) refcnt(%d), flag(%s)\n", bo, size, bo->ref_cnt, tbm_flag_to_str(bo->flags));
886
887         LIST_INITHEAD(&bo->user_data_list);
888
889         LIST_ADD(&bo->item_link, &bufmgr->bo_list);
890
891         _tbm_bufmgr_mutex_unlock();
892
893         return bo;
894 }
895
896 tbm_bo
897 tbm_bo_import(tbm_bufmgr bufmgr, unsigned int key)
898 {
899         tbm_bo bo = NULL;
900         tbm_bo bo2 = NULL;
901         tbm_bo tmp = NULL;
902         void *bo_priv = NULL;
903
904         _tbm_bufmgr_mutex_lock();
905
906         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
907         TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, NULL);
908
909         if (!bufmgr->backend->bo_import) {
910                 _tbm_bufmgr_mutex_unlock();
911                 return NULL;
912         }
913
914         _tbm_util_check_bo_cnt(bufmgr);
915
916         bo = calloc(1, sizeof(struct _tbm_bo));
917         if (!bo) {
918                 TBM_TRACE("error: fail to import of tbm_bo by key(%d)\n", key);
919                 _tbm_bufmgr_mutex_unlock();
920                 return NULL;
921         }
922
923         bo->bufmgr = bufmgr;
924
925         bo_priv = bufmgr->backend->bo_import(bo, key);
926         if (!bo_priv) {
927                 TBM_TRACE("error: fail to import of tbm_bo by key(%d)\n", key);
928                 _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FAILED);
929                 free(bo);
930                 _tbm_bufmgr_mutex_unlock();
931                 return NULL;
932         }
933
934         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
935                 LIST_FOR_EACH_ENTRY_SAFE(bo2, tmp, &bufmgr->bo_list, item_link) {
936                         if (bo2->priv == bo_priv) {
937                                 TBM_TRACE("find bo(%p) ref(%d) key(%d) flag(%s) in list\n",
938                                                         bo2, bo2->ref_cnt, key, tbm_flag_to_str(bo2->flags));
939                                 bo2->ref_cnt++;
940                                 free(bo);
941                                 _tbm_bufmgr_mutex_unlock();
942                                 return bo2;
943                         }
944                 }
945         }
946
947         bufmgr->bo_cnt++;
948
949         bo->ref_cnt = 1;
950         bo->priv = bo_priv;
951
952         if (bufmgr->backend->bo_get_flags)
953                 bo->flags = bufmgr->backend->bo_get_flags(bo);
954         else
955                 bo->flags = TBM_BO_DEFAULT;
956
957         TBM_TRACE("import new bo(%p) ref(%d) key(%d) flag(%s) in list\n",
958                           bo, bo->ref_cnt, key, tbm_flag_to_str(bo->flags));
959
960         LIST_INITHEAD(&bo->user_data_list);
961
962         LIST_ADD(&bo->item_link, &bufmgr->bo_list);
963
964         _tbm_bufmgr_mutex_unlock();
965
966         return bo;
967 }
968
969 tbm_bo
970 tbm_bo_import_fd(tbm_bufmgr bufmgr, tbm_fd fd)
971 {
972         tbm_bo bo = NULL;
973         tbm_bo bo2 = NULL;
974         tbm_bo tmp = NULL;
975         void *bo_priv = NULL;
976
977         _tbm_bufmgr_mutex_lock();
978
979         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
980         TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, NULL);
981
982         if (!bufmgr->backend->bo_import_fd) {
983                 _tbm_bufmgr_mutex_unlock();
984                 return NULL;
985         }
986
987         _tbm_util_check_bo_cnt(bufmgr);
988
989         bo = calloc(1, sizeof(struct _tbm_bo));
990         if (!bo) {
991                 TBM_TRACE("error: fail to import tbm_bo by tbm_fd(%d)\n", fd);
992                 _tbm_bufmgr_mutex_unlock();
993                 return NULL;
994         }
995
996         bo->bufmgr = bufmgr;
997
998         bo_priv = bufmgr->backend->bo_import_fd(bo, fd);
999         if (!bo_priv) {
1000                 TBM_TRACE("error: fail to import tbm_bo by tbm_fd(%d)\n", fd);
1001                 _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FD_FAILED);
1002                 free(bo);
1003                 _tbm_bufmgr_mutex_unlock();
1004                 return NULL;
1005         }
1006
1007         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
1008                 LIST_FOR_EACH_ENTRY_SAFE(bo2, tmp, &bufmgr->bo_list, item_link) {
1009                         if (bo2->priv == bo_priv) {
1010                                 TBM_TRACE("find bo(%p) ref(%d) fd(%d) flag(%s) in list\n",
1011                                                         bo2, bo2->ref_cnt, fd, tbm_flag_to_str(bo2->flags));
1012                                 bo2->ref_cnt++;
1013                                 free(bo);
1014                                 _tbm_bufmgr_mutex_unlock();
1015                                 return bo2;
1016                         }
1017                 }
1018         }
1019
1020         bufmgr->bo_cnt++;
1021
1022         bo->ref_cnt = 1;
1023         bo->priv = bo_priv;
1024
1025         if (bufmgr->backend->bo_get_flags)
1026                 bo->flags = bufmgr->backend->bo_get_flags(bo);
1027         else
1028                 bo->flags = TBM_BO_DEFAULT;
1029
1030         TBM_TRACE("import bo(%p) ref(%d) fd(%d) flag(%s)in list\n",
1031                                 bo, bo->ref_cnt, fd, tbm_flag_to_str(bo->flags));
1032
1033         LIST_INITHEAD(&bo->user_data_list);
1034
1035         LIST_ADD(&bo->item_link, &bufmgr->bo_list);
1036
1037         _tbm_bufmgr_mutex_unlock();
1038
1039         return bo;
1040 }
1041
1042 tbm_key
1043 tbm_bo_export(tbm_bo bo)
1044 {
1045         tbm_bufmgr bufmgr = NULL;
1046         tbm_key ret;
1047
1048         _tbm_bufmgr_mutex_lock();
1049
1050         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1051         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1052
1053         bufmgr = gBufMgr;
1054
1055         if (!bufmgr->backend->bo_export) {
1056                 _tbm_bufmgr_mutex_unlock();
1057                 return 0;
1058         }
1059
1060         ret = bufmgr->backend->bo_export(bo);
1061         if (!ret) {
1062                 _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FAILED);
1063                 TBM_TRACE("error: bo(%p) tbm_key(%d)\n", bo, ret);
1064                 _tbm_bufmgr_mutex_unlock();
1065                 return ret;
1066         }
1067
1068         TBM_TRACE("bo(%p) tbm_key(%d)\n", bo, ret);
1069
1070         _tbm_bufmgr_mutex_unlock();
1071
1072         return ret;
1073 }
1074
1075 tbm_fd
1076 tbm_bo_export_fd(tbm_bo bo)
1077 {
1078         tbm_bufmgr bufmgr = NULL;
1079         int ret;
1080
1081         _tbm_bufmgr_mutex_lock();
1082
1083         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), -1);
1084         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), -1);
1085
1086         bufmgr = gBufMgr;
1087
1088         if (!bufmgr->backend->bo_export_fd) {
1089                 _tbm_bufmgr_mutex_unlock();
1090                 return -1;
1091         }
1092
1093         ret = bufmgr->backend->bo_export_fd(bo);
1094         if (ret < 0) {
1095                 _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FD_FAILED);
1096                 TBM_TRACE("error: bo(%p) tbm_fd(%d)\n", bo, ret);
1097                 _tbm_bufmgr_mutex_unlock();
1098                 return ret;
1099         }
1100
1101         TBM_TRACE("bo(%p) tbm_fd(%d)\n", bo, ret);
1102
1103         _tbm_bufmgr_mutex_unlock();
1104
1105         return ret;
1106 }
1107
1108 tbm_bo_handle
1109 tbm_bo_get_handle(tbm_bo bo, int device)
1110 {
1111         tbm_bufmgr bufmgr = NULL;
1112         tbm_bo_handle bo_handle;
1113
1114         _tbm_bufmgr_mutex_lock();
1115
1116         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), (tbm_bo_handle) NULL);
1117         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) NULL);
1118
1119         bufmgr = gBufMgr;
1120
1121         bo_handle = bufmgr->backend->bo_get_handle(bo, device);
1122         if (bo_handle.ptr == NULL) {
1123                 _tbm_set_last_result(TBM_BO_ERROR_GET_HANDLE_FAILED);
1124                 TBM_TRACE("error: bo(%p) bo_handle(%p)\n", bo, bo_handle.ptr);
1125                 _tbm_bufmgr_mutex_unlock();
1126                 return (tbm_bo_handle) NULL;
1127         }
1128
1129         TBM_TRACE("bo(%p) bo_handle(%p)\n", bo, bo_handle.ptr);
1130
1131         _tbm_bufmgr_mutex_unlock();
1132
1133         return bo_handle;
1134 }
1135
1136 tbm_bo_handle
1137 tbm_bo_map(tbm_bo bo, int device, int opt)
1138 {
1139         tbm_bufmgr bufmgr = NULL;
1140         tbm_bo_handle bo_handle;
1141
1142         _tbm_bufmgr_mutex_lock();
1143
1144         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), (tbm_bo_handle) NULL);
1145         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) NULL);
1146
1147         bufmgr = gBufMgr;
1148
1149         if (!_tbm_bo_lock(bo, device, opt)) {
1150                 _tbm_set_last_result(TBM_BO_ERROR_LOCK_FAILED);
1151                 TBM_TRACE("error: fail to lock bo:%p)\n", bo);
1152                 _tbm_bufmgr_mutex_unlock();
1153                 return (tbm_bo_handle) NULL;
1154         }
1155
1156         bo_handle = bufmgr->backend->bo_map(bo, device, opt);
1157         if (bo_handle.ptr == NULL) {
1158                 _tbm_set_last_result(TBM_BO_ERROR_MAP_FAILED);
1159                 TBM_TRACE("error: fail to map bo:%p\n", bo);
1160                 _tbm_bo_unlock(bo);
1161                 _tbm_bufmgr_mutex_unlock();
1162                 return (tbm_bo_handle) NULL;
1163         }
1164
1165         /* increase the map_count */
1166         bo->map_cnt++;
1167
1168         TBM_TRACE("bo(%p) map_cnt(%d)\n", bo, bo->map_cnt);
1169
1170         _tbm_bufmgr_mutex_unlock();
1171
1172         return bo_handle;
1173 }
1174
1175 int
1176 tbm_bo_unmap(tbm_bo bo)
1177 {
1178         tbm_bufmgr bufmgr = NULL;
1179         int ret;
1180
1181         _tbm_bufmgr_mutex_lock();
1182
1183         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1184         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1185
1186         bufmgr = gBufMgr;
1187
1188         ret = bufmgr->backend->bo_unmap(bo);
1189         if (!ret) {
1190                 TBM_TRACE("error: bo(%p) map_cnt(%d)\n", bo, bo->map_cnt);
1191                 _tbm_set_last_result(TBM_BO_ERROR_UNMAP_FAILED);
1192                 _tbm_bufmgr_mutex_unlock();
1193                 return ret;
1194         }
1195
1196         /* decrease the map_count */
1197         bo->map_cnt--;
1198
1199         TBM_TRACE("bo(%p) map_cnt(%d)\n", bo, bo->map_cnt);
1200
1201         _tbm_bo_unlock(bo);
1202
1203         _tbm_bufmgr_mutex_unlock();
1204
1205         return ret;
1206 }
1207
1208 int
1209 tbm_bo_swap(tbm_bo bo1, tbm_bo bo2)
1210 {
1211         tbm_bufmgr bufmgr = NULL;
1212         void *temp;
1213
1214         _tbm_bufmgr_mutex_lock();
1215
1216         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1217         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo1), 0);
1218         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo2), 0);
1219
1220         bufmgr = gBufMgr;
1221
1222         TBM_TRACE("before: bo1(%p) bo2(%p)\n", bo1, bo2);
1223
1224         if (bufmgr->backend->bo_size(bo1) != bufmgr->backend->bo_size(bo2)) {
1225                 _tbm_set_last_result(TBM_BO_ERROR_SWAP_FAILED);
1226                 TBM_TRACE("error: bo1(%p) bo2(%p)\n", bo1, bo2);
1227                 _tbm_bufmgr_mutex_unlock();
1228                 return 0;
1229         }
1230
1231         TBM_TRACE("after: bo1(%p) bo2(%p)\n", bo1, bo2);
1232
1233         temp = bo1->priv;
1234         bo1->priv = bo2->priv;
1235         bo2->priv = temp;
1236
1237         _tbm_bufmgr_mutex_unlock();
1238
1239         return 1;
1240 }
1241
1242 int
1243 tbm_bo_locked(tbm_bo bo)
1244 {
1245         tbm_bufmgr bufmgr = NULL;
1246
1247         _tbm_bufmgr_mutex_lock();
1248
1249         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1250         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1251
1252         bufmgr = gBufMgr;
1253
1254         if (bufmgr->lock_type == LOCK_TRY_NEVER) {
1255                 TBM_TRACE("bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
1256                 _tbm_bufmgr_mutex_unlock();
1257                 return 0;
1258         }
1259
1260         if (bo->lock_cnt > 0) {
1261                 TBM_TRACE("error: bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
1262                 _tbm_bufmgr_mutex_unlock();
1263                 return 1;
1264         }
1265
1266         TBM_TRACE("bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
1267         _tbm_bufmgr_mutex_unlock();
1268
1269         return 0;
1270 }
1271
1272 int
1273 tbm_bo_add_user_data(tbm_bo bo, unsigned long key,
1274                      tbm_data_free data_free_func)
1275 {
1276         tbm_user_data *data;
1277
1278         _tbm_bufmgr_mutex_lock();
1279
1280         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1281         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1282
1283         /* check if the data according to the key exist if so, return false. */
1284         data = user_data_lookup(&bo->user_data_list, key);
1285         if (data) {
1286                 TBM_TRACE("warning: user data already exist key(%ld)\n", key);
1287                 _tbm_bufmgr_mutex_unlock();
1288                 return 0;
1289         }
1290
1291         data = user_data_create(key, data_free_func);
1292         if (!data) {
1293                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1294                 _tbm_bufmgr_mutex_unlock();
1295                 return 0;
1296         }
1297
1298         TBM_TRACE("bo(%p) key(%lu) data(%p)\n", bo, key, data->data);
1299
1300         LIST_ADD(&data->item_link, &bo->user_data_list);
1301
1302         _tbm_bufmgr_mutex_unlock();
1303
1304         return 1;
1305 }
1306
1307 int
1308 tbm_bo_set_user_data(tbm_bo bo, unsigned long key, void *data)
1309 {
1310         tbm_user_data *old_data;
1311
1312         _tbm_bufmgr_mutex_lock();
1313
1314         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1315         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1316
1317         if (LIST_IS_EMPTY(&bo->user_data_list)) {
1318                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1319                 _tbm_bufmgr_mutex_unlock();
1320                 return 0;
1321         }
1322
1323         old_data = user_data_lookup(&bo->user_data_list, key);
1324         if (!old_data) {
1325                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1326                 _tbm_bufmgr_mutex_unlock();
1327                 return 0;
1328         }
1329
1330         if (old_data->data && old_data->free_func)
1331                 old_data->free_func(old_data->data);
1332
1333         old_data->data = data;
1334
1335         TBM_TRACE("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
1336
1337         _tbm_bufmgr_mutex_unlock();
1338
1339         return 1;
1340 }
1341
1342 int
1343 tbm_bo_get_user_data(tbm_bo bo, unsigned long key, void **data)
1344 {
1345         tbm_user_data *old_data;
1346
1347         _tbm_bufmgr_mutex_lock();
1348
1349         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1350         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1351
1352         if (!data || LIST_IS_EMPTY(&bo->user_data_list)) {
1353                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1354                 _tbm_bufmgr_mutex_unlock();
1355                 return 0;
1356         }
1357
1358         old_data = user_data_lookup(&bo->user_data_list, key);
1359         if (!old_data) {
1360                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1361                 *data = NULL;
1362                 _tbm_bufmgr_mutex_unlock();
1363                 return 0;
1364         }
1365
1366         *data = old_data->data;
1367
1368         TBM_TRACE("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
1369
1370         _tbm_bufmgr_mutex_unlock();
1371
1372         return 1;
1373 }
1374
1375 int
1376 tbm_bo_delete_user_data(tbm_bo bo, unsigned long key)
1377 {
1378         tbm_user_data *old_data = (void *)0;
1379
1380         _tbm_bufmgr_mutex_lock();
1381
1382         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1383         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1384
1385         if (LIST_IS_EMPTY(&bo->user_data_list)) {
1386                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1387                 _tbm_bufmgr_mutex_unlock();
1388                 return 0;
1389         }
1390
1391         old_data = user_data_lookup(&bo->user_data_list, key);
1392         if (!old_data) {
1393                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1394                 _tbm_bufmgr_mutex_unlock();
1395                 return 0;
1396         }
1397
1398         TBM_TRACE("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
1399
1400         user_data_delete(old_data);
1401
1402         _tbm_bufmgr_mutex_unlock();
1403
1404         return 1;
1405 }
1406
1407 unsigned int
1408 tbm_bufmgr_get_capability(tbm_bufmgr bufmgr)
1409 {
1410         int capabilities = TBM_BUFMGR_CAPABILITY_NONE;
1411
1412         _tbm_bufmgr_mutex_lock();
1413
1414         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), TBM_BUFMGR_CAPABILITY_NONE);
1415         TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, TBM_BUFMGR_CAPABILITY_NONE);
1416
1417         TBM_TRACE("tbm_bufmgr(%p) capability(%d)\n", bufmgr, bufmgr->capabilities);
1418
1419         capabilities = bufmgr->capabilities;
1420
1421         _tbm_bufmgr_mutex_unlock();
1422
1423         return capabilities;
1424 }
1425
1426 int
1427 tbm_bo_get_flags(tbm_bo bo)
1428 {
1429         int flags;
1430
1431         _tbm_bufmgr_mutex_lock();
1432
1433         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1434         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1435
1436         flags = bo->flags;
1437
1438         TBM_TRACE("bo(%p)\n", bo);
1439
1440         _tbm_bufmgr_mutex_unlock();
1441
1442         return flags;
1443 }
1444
1445 /* LCOV_EXCL_START */
1446 tbm_error_e
1447 tbm_get_last_error(void)
1448 {
1449         return tbm_last_error;
1450 }
1451
1452 void
1453 tbm_bufmgr_debug_show(tbm_bufmgr bufmgr)
1454 {
1455         tbm_bo bo = NULL, tmp_bo = NULL;
1456         int bo_cnt = 0;
1457         tbm_surface_h surf = NULL, tmp_surf = NULL;
1458         int surf_cnt = 0;
1459         int i;
1460         char app_name[255] = {0,};
1461         unsigned int pid = 0;
1462         char title[255] = {0,};
1463         char data[255] = {0,};
1464         tbm_surface_debug_data *debug_old_data = NULL, *debug_tmp = NULL;
1465
1466         pthread_mutex_lock(&gLock);
1467
1468         if (!TBM_BUFMGR_IS_VALID(bufmgr) || (bufmgr != gBufMgr)) {
1469                 TBM_LOG_E("invalid bufmgr\n");
1470                 pthread_mutex_unlock(&gLock);
1471                 return;
1472         }
1473
1474         TBM_DEBUG("\n");
1475         _tbm_util_get_appname_from_pid(getpid(), app_name);
1476         _tbm_util_get_appname_brief(app_name);
1477         TBM_DEBUG("============TBM DEBUG: %s(%d)===========================\n",
1478                   app_name, getpid());
1479         memset(app_name, 0x0, 255 * sizeof(char));
1480         snprintf(title, 255, "%s", "no  surface     refcnt  width  height  bpp  size    n_b  n_p  flags  format    app_name       ");
1481         if (!LIST_IS_EMPTY(&bufmgr->debug_key_list)) {
1482                 LIST_FOR_EACH_ENTRY_SAFE(debug_old_data, debug_tmp, &bufmgr->debug_key_list, item_link) {
1483                         strncat(title, "  ", 3);
1484                         strncat(title, debug_old_data->key, strlen(debug_old_data->key) + 1);
1485                 }
1486         }
1487
1488         TBM_DEBUG("[tbm_surface information]\n");
1489         TBM_DEBUG("%s\n", title);
1490         /* show the tbm_surface information in surf_list */
1491         if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
1492                 char *value = NULL;
1493
1494                 LIST_FOR_EACH_ENTRY_SAFE(surf, tmp_surf, &bufmgr->surf_list, item_link) {
1495                         pid = _tbm_surface_internal_get_debug_pid(surf);
1496                         if (!pid) {
1497                                 /* if pid is null, set the self_pid */
1498                                 pid = getpid();
1499                         }
1500
1501                         _tbm_util_get_appname_from_pid(pid, app_name);
1502                         _tbm_util_get_appname_brief(app_name);
1503
1504                         snprintf(data, 255, "%-2d  %-9p    %-4d  %-5d  %-6d  %-3d  %-6d   %-2d   %-2d    %-3d  %-8s  %-15s",
1505                                   ++surf_cnt,
1506                                   surf,
1507                                   surf->refcnt,
1508                                   surf->info.width,
1509                                   surf->info.height,
1510                                   surf->info.bpp,
1511                                   surf->info.size / 1024,
1512                                   surf->num_bos,
1513                                   surf->num_planes,
1514                                   surf->flags,
1515                                   _tbm_surface_internal_format_to_str(surf->info.format) + 11,
1516                                   app_name);
1517
1518                         if (!LIST_IS_EMPTY(&bufmgr->debug_key_list)) {
1519                                 LIST_FOR_EACH_ENTRY_SAFE(debug_old_data, debug_tmp, &bufmgr->debug_key_list, item_link) {
1520                                         strncat(data, "  ", 3);
1521
1522                                         value = _tbm_surface_internal_get_debug_data(surf, debug_old_data->key);
1523                                         if (value)
1524                                                 strncat(data, value, strlen(value) + 1);
1525                                         else
1526                                                 strncat(data, "none", 5);
1527                                 }
1528                         }
1529                         TBM_DEBUG("%s\n", data);
1530
1531                         for (i = 0; i < surf->num_bos; i++) {
1532                                 TBM_DEBUG(" bo:%-12p  %-26d%-10d\n",
1533                                           surf->bos[i],
1534                                           surf->bos[i]->ref_cnt,
1535                                           bufmgr->backend->bo_size(surf->bos[i]) / 1024);
1536                         }
1537
1538                         memset(app_name, 0x0, 255 * sizeof(char));
1539                 }
1540         } else {
1541                 TBM_DEBUG("no tbm_surfaces.\n");
1542         }
1543         TBM_DEBUG("\n");
1544
1545         TBM_DEBUG("[tbm_bo information]\n");
1546         TBM_DEBUG("no  bo          refcnt  size    lock_cnt  map_cnt  flags  surface\n");
1547
1548         /* show the tbm_bo information in bo_list */
1549         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
1550                 LIST_FOR_EACH_ENTRY_SAFE(bo, tmp_bo, &bufmgr->bo_list, item_link) {
1551                         TBM_DEBUG("%-4d%-11p   %-4d  %-6d     %-5d     %-4d    %-3d  %-11p\n",
1552                                   ++bo_cnt,
1553                                   bo,
1554                                   bo->ref_cnt,
1555                                   bufmgr->backend->bo_size(bo) / 1024,
1556                                   bo->lock_cnt,
1557                                   bo->map_cnt,
1558                                   bo->flags,
1559                                   bo->surface);
1560                 }
1561         } else {
1562                 TBM_DEBUG("no tbm_bos.\n");
1563         }
1564         TBM_DEBUG("\n");
1565
1566         TBM_DEBUG("===============================================================\n");
1567
1568         pthread_mutex_unlock(&gLock);
1569 }
1570
1571 void
1572 tbm_bufmgr_debug_trace(tbm_bufmgr bufmgr, int onoff)
1573 {
1574         _tbm_bufmgr_mutex_lock();
1575
1576         TBM_BUFMGR_RETURN_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr));
1577         TBM_BUFMGR_RETURN_IF_FAIL(bufmgr == gBufMgr);
1578
1579 #ifdef TRACE
1580         TBM_LOG_D("bufmgr=%p onoff=%d\n", bufmgr, onoff);
1581         bTrace = onoff;
1582 #endif
1583
1584         _tbm_bufmgr_mutex_unlock();
1585 }
1586
1587 int
1588 tbm_bufmgr_debug_queue_dump(char *path, int count, int onoff)
1589 {
1590         int w = 0, h = 0;
1591
1592         TBM_RETURN_VAL_IF_FAIL(path != NULL, 0);
1593         TBM_LOG_D("path=%s count=%d onoff=%d\n", path, count, onoff);
1594
1595         pthread_mutex_lock(&gLock);
1596
1597         if (onoff == 1) {
1598                 if (_tbm_util_get_max_surface_size(&w, &h) == 0) {
1599                         TBM_LOG_I("No tbm_surface.\n");
1600                         pthread_mutex_unlock(&gLock);
1601                         return 0;
1602                 }
1603
1604                 tbm_surface_internal_dump_start(path, w, h, count);
1605                 b_dump_queue = 1;
1606         } else if (onoff == 0) {
1607                 tbm_surface_internal_dump_end();
1608                 b_dump_queue = 0;
1609         } else {
1610                 pthread_mutex_unlock(&gLock);
1611                 return 0;
1612         }
1613
1614         pthread_mutex_unlock(&gLock);
1615         return 1;
1616 }
1617
1618 int
1619 tbm_bufmgr_debug_dump_all(char *path)
1620 {
1621         int w = 0, h = 0, count = 0;
1622         tbm_surface_h surface = NULL, tmp = NULL;
1623
1624         TBM_RETURN_VAL_IF_FAIL(path != NULL, 0);
1625         TBM_LOG_D("path=%s\n", path);
1626
1627         pthread_mutex_lock(&gLock);
1628
1629         count = _tbm_util_get_max_surface_size(&w, &h);
1630         if (count == 0) {
1631                 TBM_LOG_I("No tbm_surface.\n");
1632                 pthread_mutex_unlock(&gLock);
1633                 return 1;
1634         }
1635
1636         tbm_surface_internal_dump_start(path, w, h, count);
1637
1638         LIST_FOR_EACH_ENTRY_SAFE(surface, tmp, &gBufMgr->surf_list, item_link) {
1639                 tbm_surface_internal_dump_buffer(surface, "dump_all");
1640         }
1641
1642         tbm_surface_internal_dump_end();
1643
1644         pthread_mutex_unlock(&gLock);
1645
1646         return 1;
1647 }
1648
1649 /* internal function */
1650 tbm_bufmgr
1651 _tbm_bufmgr_get_bufmgr(void)
1652 {
1653         return gBufMgr;
1654 }
1655
1656 int
1657 _tbm_bo_set_surface(tbm_bo bo, tbm_surface_h surface)
1658 {
1659         _tbm_bufmgr_mutex_lock();
1660
1661         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1662         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1663
1664         bo->surface = surface;
1665
1666         _tbm_bufmgr_mutex_unlock();
1667
1668         return 1;
1669 }
1670
1671 int
1672 tbm_bufmgr_bind_native_display(tbm_bufmgr bufmgr, void *NativeDisplay)
1673 {
1674         int ret;
1675
1676         _tbm_bufmgr_mutex_lock();
1677
1678         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1679
1680         if (!bufmgr->backend->bufmgr_bind_native_display) {
1681                 TBM_TRACE("error: tbm_bufmgr(%p) NativeDisplay(%p)\n", bufmgr, NativeDisplay);
1682                 _tbm_bufmgr_mutex_unlock();
1683                 return 1;
1684         }
1685
1686         ret = bufmgr->backend->bufmgr_bind_native_display(bufmgr, NativeDisplay);
1687         if (!ret) {
1688                 TBM_TRACE("error: tbm_bufmgr(%p) NativeDisplay(%p)\n", bufmgr, NativeDisplay);
1689                 _tbm_bufmgr_mutex_unlock();
1690                 return 0;
1691         }
1692
1693         TBM_TRACE("tbm_bufmgr(%p) NativeDisplay(%p)\n", bufmgr, NativeDisplay);
1694
1695         _tbm_bufmgr_mutex_unlock();
1696
1697         return 1;
1698 }
1699 /* LCOV_EXCL_STOP */