fix the out-of-bounds access
[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
1241         ret = bufmgr->backend->bo_unmap(bo);
1242         if (!ret) {
1243                 /* LCOV_EXCL_START */
1244                 TBM_LOG_E("error: bo(%p) map_cnt(%d)\n", bo, bo->map_cnt);
1245                 _tbm_set_last_result(TBM_BO_ERROR_UNMAP_FAILED);
1246                 _tbm_bufmgr_mutex_unlock();
1247                 return ret;
1248                 /* LCOV_EXCL_STOP */
1249         }
1250
1251         /* decrease the map_count */
1252         bo->map_cnt--;
1253
1254         TBM_TRACE("bo(%p) map_cnt(%d)\n", bo, bo->map_cnt);
1255
1256         _tbm_bo_unlock(bo);
1257
1258         _tbm_bufmgr_mutex_unlock();
1259
1260         return ret;
1261 }
1262
1263 int
1264 tbm_bo_swap(tbm_bo bo1, tbm_bo bo2)
1265 {
1266         tbm_bufmgr bufmgr = gBufMgr;
1267         void *temp;
1268
1269         _tbm_bufmgr_mutex_lock();
1270
1271         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1272         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo1), 0);
1273         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo2), 0);
1274
1275         TBM_TRACE("before: bo1(%p) bo2(%p)\n", bo1, bo2);
1276
1277         if (bufmgr->backend->bo_size(bo1) != bufmgr->backend->bo_size(bo2)) {
1278                 _tbm_set_last_result(TBM_BO_ERROR_SWAP_FAILED);
1279                 TBM_LOG_E("error: bo1(%p) bo2(%p)\n", bo1, bo2);
1280                 _tbm_bufmgr_mutex_unlock();
1281                 return 0;
1282         }
1283
1284         TBM_TRACE("after: bo1(%p) bo2(%p)\n", bo1, bo2);
1285
1286         temp = bo1->priv;
1287         bo1->priv = bo2->priv;
1288         bo2->priv = temp;
1289
1290         _tbm_bufmgr_mutex_unlock();
1291
1292         return 1;
1293 }
1294
1295 int
1296 tbm_bo_locked(tbm_bo bo)
1297 {
1298         tbm_bufmgr bufmgr = gBufMgr;
1299
1300         _tbm_bufmgr_mutex_lock();
1301
1302         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1303         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1304
1305         if (bufmgr->lock_type == LOCK_TRY_NEVER) {
1306                 TBM_LOG_E("bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
1307                 _tbm_bufmgr_mutex_unlock();
1308                 return 0;
1309         }
1310
1311         if (bo->lock_cnt > 0) {
1312                 TBM_TRACE("error: bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
1313                 _tbm_bufmgr_mutex_unlock();
1314                 return 1;
1315         }
1316
1317         TBM_TRACE("bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
1318         _tbm_bufmgr_mutex_unlock();
1319
1320         return 0;
1321 }
1322
1323 int
1324 tbm_bo_add_user_data(tbm_bo bo, unsigned long key,
1325                      tbm_data_free data_free_func)
1326 {
1327         tbm_user_data *data;
1328
1329         _tbm_bufmgr_mutex_lock();
1330
1331         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1332         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1333
1334         /* check if the data according to the key exist if so, return false. */
1335         data = user_data_lookup(&bo->user_data_list, key);
1336         if (data) {
1337                 TBM_TRACE("warning: user data already exist key(%ld)\n", key);
1338                 _tbm_bufmgr_mutex_unlock();
1339                 return 0;
1340         }
1341
1342         data = user_data_create(key, data_free_func);
1343         if (!data) {
1344                 TBM_LOG_E("error: bo(%p) key(%lu)\n", bo, key);
1345                 _tbm_bufmgr_mutex_unlock();
1346                 return 0;
1347         }
1348
1349         TBM_TRACE("bo(%p) key(%lu) data(%p)\n", bo, key, data->data);
1350
1351         LIST_ADD(&data->item_link, &bo->user_data_list);
1352
1353         _tbm_bufmgr_mutex_unlock();
1354
1355         return 1;
1356 }
1357
1358 int
1359 tbm_bo_set_user_data(tbm_bo bo, unsigned long key, void *data)
1360 {
1361         tbm_user_data *old_data;
1362
1363         _tbm_bufmgr_mutex_lock();
1364
1365         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1366         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1367
1368         if (LIST_IS_EMPTY(&bo->user_data_list)) {
1369                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1370                 _tbm_bufmgr_mutex_unlock();
1371                 return 0;
1372         }
1373
1374         old_data = user_data_lookup(&bo->user_data_list, key);
1375         if (!old_data) {
1376                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1377                 _tbm_bufmgr_mutex_unlock();
1378                 return 0;
1379         }
1380
1381         if (old_data->data && old_data->free_func)
1382                 old_data->free_func(old_data->data);
1383         old_data->data = data;
1384
1385         TBM_TRACE("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
1386
1387         _tbm_bufmgr_mutex_unlock();
1388
1389         return 1;
1390 }
1391
1392 int
1393 tbm_bo_get_user_data(tbm_bo bo, unsigned long key, void **data)
1394 {
1395         tbm_user_data *old_data;
1396
1397         _tbm_bufmgr_mutex_lock();
1398
1399         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1400         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1401
1402         if (!data || LIST_IS_EMPTY(&bo->user_data_list)) {
1403                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1404                 _tbm_bufmgr_mutex_unlock();
1405                 return 0;
1406         }
1407
1408         old_data = user_data_lookup(&bo->user_data_list, key);
1409         if (!old_data) {
1410                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1411                 *data = NULL;
1412                 _tbm_bufmgr_mutex_unlock();
1413                 return 0;
1414         }
1415
1416         *data = old_data->data;
1417
1418         TBM_TRACE("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
1419
1420         _tbm_bufmgr_mutex_unlock();
1421
1422         return 1;
1423 }
1424
1425 int
1426 tbm_bo_delete_user_data(tbm_bo bo, unsigned long key)
1427 {
1428         tbm_user_data *old_data;
1429
1430         _tbm_bufmgr_mutex_lock();
1431
1432         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1433         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1434
1435         if (LIST_IS_EMPTY(&bo->user_data_list)) {
1436                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1437                 _tbm_bufmgr_mutex_unlock();
1438                 return 0;
1439         }
1440
1441         old_data = user_data_lookup(&bo->user_data_list, key);
1442         if (!old_data) {
1443                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1444                 _tbm_bufmgr_mutex_unlock();
1445                 return 0;
1446         }
1447
1448         TBM_TRACE("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
1449
1450         user_data_delete(old_data);
1451
1452         _tbm_bufmgr_mutex_unlock();
1453
1454         return 1;
1455 }
1456
1457 unsigned int
1458 tbm_bufmgr_get_capability(tbm_bufmgr bufmgr)
1459 {
1460         unsigned int capabilities = TBM_BUFMGR_CAPABILITY_NONE;
1461
1462         _tbm_bufmgr_mutex_lock();
1463
1464         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), TBM_BUFMGR_CAPABILITY_NONE);
1465         TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, TBM_BUFMGR_CAPABILITY_NONE);
1466
1467         TBM_TRACE("tbm_bufmgr(%p) capability(%u)\n", bufmgr, bufmgr->capabilities);
1468
1469         capabilities = bufmgr->capabilities;
1470
1471         _tbm_bufmgr_mutex_unlock();
1472
1473         return capabilities;
1474 }
1475
1476 int
1477 tbm_bo_get_flags(tbm_bo bo)
1478 {
1479         int flags;
1480
1481         _tbm_bufmgr_mutex_lock();
1482
1483         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1484         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1485
1486         flags = bo->flags;
1487
1488         TBM_TRACE("bo(%p)\n", bo);
1489
1490         _tbm_bufmgr_mutex_unlock();
1491
1492         return flags;
1493 }
1494
1495 /* LCOV_EXCL_START */
1496 tbm_error_e
1497 tbm_get_last_error(void)
1498 {
1499         return tbm_last_error;
1500 }
1501
1502 char *
1503 tbm_bufmgr_debug_tbm_info_get(tbm_bufmgr bufmgr)
1504 {
1505         char app_name[255] = {0,}, title[512] = {0,};
1506         tbm_surface_debug_data *debug_old_data = NULL;
1507         char *str;
1508         int len = 1024*4;
1509         int c = 0;
1510
1511         pthread_mutex_lock(&gLock);
1512
1513         if (!TBM_BUFMGR_IS_VALID(bufmgr) || (bufmgr != gBufMgr)) {
1514                 TBM_LOG_E("invalid bufmgr\n");
1515                 pthread_mutex_unlock(&gLock);
1516                 return NULL;
1517         }
1518
1519         str = malloc(len);
1520         if (!str) {
1521                 TBM_LOG_E("Fail to allocate the string.\n");
1522                 pthread_mutex_unlock(&gLock);
1523                 return NULL;
1524         }
1525
1526         TBM_SNRPRINTF(str, len, c, "\n");
1527         _tbm_util_get_appname_from_pid(getpid(), app_name);
1528         _tbm_util_get_appname_brief(app_name);
1529         TBM_SNRPRINTF(str, len, c, "============TBM DEBUG: %s(%d)===========================\n",
1530                   app_name, getpid());
1531
1532         snprintf(title, 255, "%s", "no  surface     refcnt  width  height  bpp  size    n_b  n_p  flags  format    app_name       ");
1533
1534         if (!LIST_IS_EMPTY(&bufmgr->debug_key_list)) {
1535                 LIST_FOR_EACH_ENTRY(debug_old_data, &bufmgr->debug_key_list, item_link) {
1536                         strncat(title, "  ", MAX_SIZE_N(title));
1537                         strncat(title, debug_old_data->key, MAX_SIZE_N(title));
1538                 }
1539         }
1540
1541         TBM_SNRPRINTF(str, len, c, "[tbm_surface information]\n");
1542         TBM_SNRPRINTF(str, len, c, "%s\n", title);
1543
1544         /* show the tbm_surface information in surf_list */
1545         if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
1546                 tbm_surface_h surf = NULL;
1547                 int surf_cnt = 0;
1548
1549                 LIST_FOR_EACH_ENTRY(surf, &bufmgr->surf_list, item_link) {
1550                         char data[512] = {0,};
1551                         unsigned int pid;
1552                         int i;
1553
1554                         pid = _tbm_surface_internal_get_debug_pid(surf);
1555                         if (!pid) {
1556                                 /* if pid is null, set the self_pid */
1557                                 pid = getpid();
1558                         }
1559
1560                         memset(app_name, 0x0, 255 * sizeof(char));
1561                         _tbm_util_get_appname_from_pid(pid, app_name);
1562                         _tbm_util_get_appname_brief(app_name);
1563
1564                         snprintf(data, 255, "%-2d  %-9p    %-4d  %-5u  %-6u  %-3u  %-6u   %-2d   %-2d    %-3d  %-8s  %-15s",
1565                                   ++surf_cnt,
1566                                   surf,
1567                                   surf->refcnt,
1568                                   surf->info.width,
1569                                   surf->info.height,
1570                                   surf->info.bpp,
1571                                   surf->info.size / 1024,
1572                                   surf->num_bos,
1573                                   surf->num_planes,
1574                                   surf->flags,
1575                                   _tbm_surface_internal_format_to_str(surf->info.format) + 11,
1576                                   app_name);
1577
1578                         if (!LIST_IS_EMPTY(&bufmgr->debug_key_list)) {
1579                                 LIST_FOR_EACH_ENTRY(debug_old_data, &bufmgr->debug_key_list, item_link) {
1580                                         char *value;
1581
1582                                         strncat(data, "  ", MAX_SIZE_N(title));
1583
1584                                         value = _tbm_surface_internal_get_debug_data(surf, debug_old_data->key);
1585                                         if (value)
1586                                                 strncat(data, value, MAX_SIZE_N(title));
1587                                         else
1588                                                 strncat(data, "none", MAX_SIZE_N(title));
1589                                 }
1590                         }
1591                         TBM_SNRPRINTF(str, len, c, "%s\n", data);
1592
1593                         for (i = 0; i < surf->num_bos; i++) {
1594                                 TBM_SNRPRINTF(str, len, c, " bo:%-12p  %-26d%-10d\n",
1595                                           surf->bos[i],
1596                                           surf->bos[i]->ref_cnt,
1597                                           bufmgr->backend->bo_size(surf->bos[i]) / 1024);
1598                         }
1599                 }
1600         } else
1601                 TBM_SNRPRINTF(str, len, c, " no tbm_surfaces.\n");
1602         TBM_SNRPRINTF(str, len, c, "\n");
1603
1604         TBM_SNRPRINTF(str, len, c, "[tbm_bo information]\n");
1605         TBM_SNRPRINTF(str, len, c, "no  bo          refcnt  size    lock_cnt  map_cnt  flags  surface     name\n");
1606
1607         /* show the tbm_bo information in bo_list */
1608         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
1609                 int bo_cnt = 0;
1610                 tbm_bo bo = NULL;
1611
1612                 LIST_FOR_EACH_ENTRY(bo, &bufmgr->bo_list, item_link) {
1613                         TBM_SNRPRINTF(str, len, c, "%-4d%-11p   %-4d  %-6d     %-5d     %-4u    %-3d  %-11p  %-4d\n",
1614                                   ++bo_cnt,
1615                                   bo,
1616                                   bo->ref_cnt,
1617                                   bufmgr->backend->bo_size(bo) / 1024,
1618                                   bo->lock_cnt,
1619                                   bo->map_cnt,
1620                                   bo->flags,
1621                                   bo->surface,
1622                                   bufmgr->backend->bo_export(bo));
1623                 }
1624         } else
1625                 TBM_SNRPRINTF(str, len, c, "no tbm_bos.\n");
1626         TBM_SNRPRINTF(str, len, c, "\n");
1627
1628         TBM_SNRPRINTF(str, len, c, "===============================================================\n");
1629
1630         pthread_mutex_unlock(&gLock);
1631
1632         return str;
1633 }
1634
1635 void
1636 tbm_bufmgr_debug_show(tbm_bufmgr bufmgr)
1637 {
1638         char * str;
1639         str = tbm_bufmgr_debug_tbm_info_get(bufmgr);
1640         if (str) {
1641                 TBM_DEBUG("     %s", str);
1642                 free(str);
1643         }
1644 }
1645
1646 void
1647 tbm_bufmgr_debug_trace(tbm_bufmgr bufmgr, int onoff)
1648 {
1649         _tbm_bufmgr_mutex_lock();
1650
1651         TBM_BUFMGR_RETURN_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr));
1652         TBM_BUFMGR_RETURN_IF_FAIL(bufmgr == gBufMgr);
1653
1654 #ifdef TRACE
1655         TBM_LOG_D("bufmgr=%p onoff=%d\n", bufmgr, onoff);
1656         bTrace = onoff;
1657 #endif
1658
1659         _tbm_bufmgr_mutex_unlock();
1660 }
1661
1662 void
1663 tbm_bufmgr_debug_dump_set_scale(double scale)
1664 {
1665         pthread_mutex_lock(&gLock);
1666         scale_factor = scale;
1667         pthread_mutex_unlock(&gLock);
1668 }
1669
1670 int
1671 tbm_bufmgr_debug_queue_dump(char *path, int count, int onoff)
1672 {
1673         pthread_mutex_lock(&gLock);
1674
1675         if (onoff == 0) {
1676                 TBM_LOG_D("count=%d onoff=%d\n", count, onoff);
1677                 b_dump_queue = 0;
1678                 tbm_surface_internal_dump_end();
1679         } else {
1680                 int w, h;
1681
1682                 if (path == NULL) {
1683                         TBM_LOG_E("path is null");
1684                         pthread_mutex_unlock(&gLock);
1685                         return 0;
1686                 }
1687                 TBM_LOG_D("path=%s count=%d onoff=%d\n", path, count, onoff);
1688
1689                 if (_tbm_util_get_max_surface_size(&w, &h) == 0) {
1690                         TBM_LOG_E("Fail to get tbm_surface size.\n");
1691                         pthread_mutex_unlock(&gLock);
1692                         return 0;
1693                 }
1694
1695                 tbm_surface_internal_dump_with_scale_start(path, w, h, count, scale_factor);
1696                 scale_factor = 0;
1697
1698                 b_dump_queue = 1;
1699         }
1700
1701         pthread_mutex_unlock(&gLock);
1702         return 1;
1703 }
1704
1705 int
1706 tbm_bufmgr_debug_dump_all(char *path)
1707 {
1708         int w, h, count = 0;
1709         tbm_surface_h surface = NULL;
1710
1711         TBM_RETURN_VAL_IF_FAIL(path != NULL, 0);
1712         TBM_LOG_D("path=%s\n", path);
1713
1714         pthread_mutex_lock(&gLock);
1715
1716         count = _tbm_util_get_max_surface_size(&w, &h);
1717         if (count == 0) {
1718                 TBM_LOG_E("No tbm_surface.\n");
1719                 pthread_mutex_unlock(&gLock);
1720                 return 1;
1721         }
1722
1723         tbm_surface_internal_dump_with_scale_start(path, w, h, count, scale_factor);
1724         scale_factor = 0;
1725
1726         LIST_FOR_EACH_ENTRY(surface, &gBufMgr->surf_list, item_link)
1727                 tbm_surface_internal_dump_buffer(surface, "dump_all");
1728
1729         tbm_surface_internal_dump_end();
1730
1731         pthread_mutex_unlock(&gLock);
1732
1733         return 1;
1734 }
1735
1736 /* internal function */
1737 tbm_bufmgr
1738 _tbm_bufmgr_get_bufmgr(void)
1739 {
1740         return gBufMgr;
1741 }
1742
1743 int
1744 _tbm_bo_set_surface(tbm_bo bo, tbm_surface_h surface)
1745 {
1746         _tbm_bufmgr_mutex_lock();
1747
1748         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1749         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1750
1751         bo->surface = surface;
1752
1753         _tbm_bufmgr_mutex_unlock();
1754
1755         return 1;
1756 }
1757
1758 int
1759 tbm_bufmgr_bind_native_display(tbm_bufmgr bufmgr, void *NativeDisplay)
1760 {
1761         int ret;
1762
1763         _tbm_bufmgr_mutex_lock();
1764
1765         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1766
1767         if (!bufmgr->backend->bufmgr_bind_native_display) {
1768                 TBM_TRACE("skip: tbm_bufmgr(%p) NativeDisplay(%p)\n",
1769                                 bufmgr, NativeDisplay);
1770                 _tbm_bufmgr_mutex_unlock();
1771                 return 1;
1772         }
1773
1774         ret = bufmgr->backend->bufmgr_bind_native_display(bufmgr, NativeDisplay);
1775         if (!ret) {
1776                 TBM_LOG_E("error: tbm_bufmgr(%p) NativeDisplay(%p)\n",
1777                                 bufmgr, NativeDisplay);
1778                 _tbm_bufmgr_mutex_unlock();
1779                 return 0;
1780         }
1781
1782         TBM_TRACE("tbm_bufmgr(%p) NativeDisplay(%p)\n", bufmgr, NativeDisplay);
1783
1784         _tbm_bufmgr_mutex_unlock();
1785
1786         return 1;
1787 }
1788
1789 int tbm_bufmgr_get_fd_limit(void)
1790 {
1791         struct rlimit lim;
1792
1793         if (getrlimit(RLIMIT_NOFILE, &lim))
1794                 return 1024;
1795
1796         return (int)lim.rlim_cur;
1797 }
1798 /* LCOV_EXCL_STOP */