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