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