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