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