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