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