bufmgr: add tbm_bufmgr_server_init api
[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         /* set the display_server flag before loading the backend module */
694         if (server) {
695                 TBM_LOG_I("The tbm_bufmgr(%p) is used by display server. Need to bind the native_display.\n", gBufMgr);
696                 gBufMgr->display_server = 1;
697         }
698
699         /* load bufmgr priv from env */
700         if (!_tbm_load_module(gBufMgr, gBufMgr->fd)) {
701                 _tbm_set_last_result(TBM_BO_ERROR_LOAD_MODULE_FAILED);
702                 TBM_LOG_E("error : Fail to load bufmgr backend\n");
703                 free(gBufMgr);
704                 gBufMgr = NULL;
705                 pthread_mutex_unlock(&gLock);
706                 return NULL;
707
708         }
709         /* LCOV_EXCL_STOP */
710
711         /* log for tbm backend_flag */
712         TBM_DBG("backend flag:%x:", gBufMgr->backend->flags);
713         TBM_DBG("\n");
714
715         gBufMgr->ref_count = 1;
716
717         TBM_DBG("create tizen bufmgr:%p ref_count:%d\n",
718             gBufMgr, gBufMgr->ref_count);
719
720         /* setup the lock_type */
721         env = getenv("BUFMGR_LOCK_TYPE");
722         if (env && !strcmp(env, "always"))
723                 gBufMgr->lock_type = LOCK_TRY_ALWAYS;
724         else if (env && !strcmp(env, "none"))
725                 gBufMgr->lock_type = LOCK_TRY_NEVER;
726         else if (env && !strcmp(env, "once"))
727                 gBufMgr->lock_type = LOCK_TRY_ONCE;
728         else
729                 gBufMgr->lock_type = LOCK_TRY_ALWAYS;
730
731         TBM_DBG("BUFMGR_LOCK_TYPE=%s\n", env ? env : "default:once");
732
733         TBM_TRACE("create tbm_bufmgr(%p) ref_count(%d) fd(%d)\n", gBufMgr, gBufMgr->ref_count, fd);
734
735         /* intialize bo_list */
736         LIST_INITHEAD(&gBufMgr->bo_list);
737
738         /* intialize surf_list */
739         LIST_INITHEAD(&gBufMgr->surf_list);
740
741         /* intialize surf_queue_list */
742         LIST_INITHEAD(&gBufMgr->surf_queue_list);
743
744         /* intialize debug_key_list */
745         LIST_INITHEAD(&gBufMgr->debug_key_list);
746
747 #ifdef TBM_BUFMGR_INIT_TIME
748         /* get the end tv */
749         gettimeofday(&end_tv, NULL);
750         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)));
751 #endif
752
753         pthread_mutex_unlock(&gLock);
754
755         return gBufMgr;
756 }
757
758 tbm_bufmgr
759 tbm_bufmgr_init(int fd)
760 {
761         tbm_bufmgr bufmgr;
762
763         bufmgr = _tbm_bufmgr_init(fd, 0);
764
765         return bufmgr;
766 }
767
768 void
769 tbm_bufmgr_deinit(tbm_bufmgr bufmgr)
770 {
771         TBM_RETURN_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr));
772
773         _tbm_bufmgr_mutex_lock();
774         pthread_mutex_lock(&gLock);
775
776         if (!gBufMgr) {
777                 TBM_LOG_E("gBufmgr already destroy: bufmgr:%p\n", bufmgr);
778                 pthread_mutex_unlock(&gLock);
779                 _tbm_bufmgr_mutex_unlock();
780                 return;
781         }
782
783         bufmgr->ref_count--;
784         if (bufmgr->ref_count > 0) {
785                 TBM_TRACE("reduce a ref_count(%d) of tbm_bufmgr(%p)\n", bufmgr->ref_count, bufmgr);
786                 pthread_mutex_unlock(&gLock);
787                 _tbm_bufmgr_mutex_unlock();
788                 return;
789         }
790
791         /* destroy bo_list */
792         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
793                 tbm_bo bo = NULL, tmp;
794
795                 LIST_FOR_EACH_ENTRY_SAFE(bo, tmp, &bufmgr->bo_list, item_link) {
796                         TBM_LOG_E("Un-freed bo(%p, ref:%d)\n", bo, bo->ref_cnt);
797                         _tbm_bo_free(bo);
798                 }
799                 LIST_DELINIT(&bufmgr->bo_list);
800         }
801
802         /* destroy surf_list */
803         if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
804                 tbm_surface_h surf = NULL, tmp;
805
806                 LIST_FOR_EACH_ENTRY_SAFE(surf, tmp, &bufmgr->surf_list, item_link) {
807                         TBM_LOG_E("Un-freed surf(%p, ref:%d)\n", surf, surf->refcnt);
808                         tbm_surface_destroy(surf);
809                 }
810                 LIST_DELINIT(&bufmgr->surf_list);
811         }
812
813         /* destroy bufmgr priv */
814         bufmgr->backend->bufmgr_deinit(bufmgr->backend->priv);
815         bufmgr->backend->priv = NULL;
816         tbm_backend_free(bufmgr->backend);
817         bufmgr->backend = NULL;
818
819         TBM_TRACE("destroy tbm_bufmgr(%p)\n", bufmgr);
820
821         dlclose(bufmgr->module_data);
822
823         if (bufmgr->fd > 0)
824                 close(bufmgr->fd);
825
826         free(bufmgr);
827         gBufMgr = NULL;
828
829         pthread_mutex_unlock(&gLock);
830         _tbm_bufmgr_mutex_unlock();
831 }
832
833 int
834 tbm_bo_size(tbm_bo bo)
835 {
836         tbm_bufmgr bufmgr = gBufMgr;
837         int size;
838
839         _tbm_bufmgr_mutex_lock();
840
841         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
842         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
843
844         size = bufmgr->backend->bo_size(bo);
845
846         TBM_TRACE("bo(%p) size(%d)\n", bo, size);
847
848         _tbm_bufmgr_mutex_unlock();
849
850         return size;
851 }
852
853 tbm_bo
854 tbm_bo_ref(tbm_bo bo)
855 {
856         _tbm_bufmgr_mutex_lock();
857
858         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), NULL);
859         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), NULL);
860
861         bo->ref_cnt++;
862
863         TBM_TRACE("bo(%p) ref_cnt(%d)\n", bo, bo->ref_cnt);
864
865         _tbm_bufmgr_mutex_unlock();
866
867         return bo;
868 }
869
870 void
871 tbm_bo_unref(tbm_bo bo)
872 {
873         _tbm_bufmgr_mutex_lock();
874
875         TBM_BUFMGR_RETURN_IF_FAIL(gBufMgr);
876         TBM_BUFMGR_RETURN_IF_FAIL(_tbm_bo_is_valid(bo));
877
878         TBM_TRACE("bo(%p) ref_cnt(%d)\n", bo, bo->ref_cnt - 1);
879
880         if (bo->ref_cnt <= 0) {
881                 _tbm_bufmgr_mutex_unlock();
882                 return;
883         }
884
885         bo->ref_cnt--;
886         if (bo->ref_cnt == 0)
887                 _tbm_bo_free(bo);
888
889         _tbm_bufmgr_mutex_unlock();
890 }
891
892 tbm_bo
893 tbm_bo_alloc(tbm_bufmgr bufmgr, int size, int flags)
894 {
895         void *bo_priv;
896         tbm_bo bo;
897
898         _tbm_bufmgr_mutex_lock();
899
900         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
901         TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, NULL);
902         TBM_BUFMGR_RETURN_VAL_IF_FAIL(size > 0, NULL);
903
904         bo = calloc(1, sizeof(struct _tbm_bo));
905         if (!bo) {
906                 /* LCOV_EXCL_START */
907                 TBM_LOG_E("error: fail to create of tbm_bo size(%d) flag(%s)\n",
908                                 size, _tbm_flag_to_str(flags));
909                 _tbm_set_last_result(TBM_BO_ERROR_HEAP_ALLOC_FAILED);
910                 _tbm_bufmgr_mutex_unlock();
911                 return NULL;
912                 /* LCOV_EXCL_STOP */
913         }
914
915         _tbm_util_check_bo_cnt(bufmgr);
916
917         bo->bufmgr = bufmgr;
918
919         bo_priv = bufmgr->backend->bo_alloc(bo, size, flags);
920         if (!bo_priv) {
921                 /* LCOV_EXCL_START */
922                 TBM_LOG_E("error: fail to create of tbm_bo size(%d) flag(%s)\n",
923                                 size, _tbm_flag_to_str(flags));
924                 _tbm_set_last_result(TBM_BO_ERROR_BO_ALLOC_FAILED);
925                 free(bo);
926                 _tbm_bufmgr_mutex_unlock();
927                 return NULL;
928                 /* LCOV_EXCL_STOP */
929         }
930
931         bufmgr->bo_cnt++;
932
933         bo->ref_cnt = 1;
934         bo->flags = flags;
935         bo->priv = bo_priv;
936
937         TBM_TRACE("bo(%p) size(%d) refcnt(%d), flag(%s)\n", bo, size, bo->ref_cnt,
938                         _tbm_flag_to_str(bo->flags));
939
940         LIST_INITHEAD(&bo->user_data_list);
941
942         LIST_ADD(&bo->item_link, &bufmgr->bo_list);
943
944         _tbm_bufmgr_mutex_unlock();
945
946         return bo;
947 }
948
949 tbm_bo
950 tbm_bo_import(tbm_bufmgr bufmgr, unsigned int key)
951 {
952         void *bo_priv;
953         tbm_bo bo;
954
955         _tbm_bufmgr_mutex_lock();
956
957         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
958         TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, NULL);
959
960         if (!bufmgr->backend->bo_import) {
961                 /* LCOV_EXCL_START */
962                 _tbm_bufmgr_mutex_unlock();
963                 return NULL;
964                 /* LCOV_EXCL_STOP */
965         }
966
967         _tbm_util_check_bo_cnt(bufmgr);
968
969         bo = calloc(1, sizeof(struct _tbm_bo));
970         if (!bo) {
971                 /* LCOV_EXCL_START */
972                 TBM_LOG_E("error: fail to import of tbm_bo by key(%d)\n", key);
973                 _tbm_bufmgr_mutex_unlock();
974                 return NULL;
975                 /* LCOV_EXCL_STOP */
976         }
977
978         bo->bufmgr = bufmgr;
979
980         bo_priv = bufmgr->backend->bo_import(bo, key);
981         if (!bo_priv) {
982                 /* LCOV_EXCL_START */
983                 TBM_LOG_E("error: fail to import of tbm_bo by key(%d)\n", key);
984                 _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FAILED);
985                 free(bo);
986                 _tbm_bufmgr_mutex_unlock();
987                 return NULL;
988                 /* LCOV_EXCL_STOP */
989         }
990
991         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
992                 tbm_bo bo2 = NULL;
993
994                 LIST_FOR_EACH_ENTRY(bo2, &bufmgr->bo_list, item_link) {
995                         if (bo2->priv == bo_priv) {
996                                 TBM_TRACE("find bo(%p) ref(%d) key(%d) flag(%s) in list\n",
997                                                 bo2, bo2->ref_cnt, key,
998                                                 _tbm_flag_to_str(bo2->flags));
999                                 bo2->ref_cnt++;
1000                                 free(bo);
1001                                 _tbm_bufmgr_mutex_unlock();
1002                                 return bo2;
1003                         }
1004                 }
1005         }
1006
1007         bufmgr->bo_cnt++;
1008
1009         bo->ref_cnt = 1;
1010         bo->priv = bo_priv;
1011
1012         if (bufmgr->backend->bo_get_flags)
1013                 bo->flags = bufmgr->backend->bo_get_flags(bo);
1014         else
1015                 bo->flags = TBM_BO_DEFAULT;
1016
1017         TBM_TRACE("import new bo(%p) ref(%d) key(%d) flag(%s) in list\n",
1018                           bo, bo->ref_cnt, key, _tbm_flag_to_str(bo->flags));
1019
1020         LIST_INITHEAD(&bo->user_data_list);
1021
1022         LIST_ADD(&bo->item_link, &bufmgr->bo_list);
1023
1024         _tbm_bufmgr_mutex_unlock();
1025
1026         return bo;
1027 }
1028
1029 tbm_bo
1030 tbm_bo_import_fd(tbm_bufmgr bufmgr, tbm_fd fd)
1031 {
1032         void *bo_priv;
1033         tbm_bo bo;
1034
1035         _tbm_bufmgr_mutex_lock();
1036
1037         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
1038         TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, NULL);
1039
1040         if (!bufmgr->backend->bo_import_fd) {
1041                 /* LCOV_EXCL_START */
1042                 _tbm_bufmgr_mutex_unlock();
1043                 return NULL;
1044                 /* LCOV_EXCL_STOP */
1045         }
1046
1047         _tbm_util_check_bo_cnt(bufmgr);
1048
1049         bo = calloc(1, sizeof(struct _tbm_bo));
1050         if (!bo) {
1051                 /* LCOV_EXCL_START */
1052                 TBM_LOG_E("error: fail to import tbm_bo by tbm_fd(%d)\n", fd);
1053                 _tbm_bufmgr_mutex_unlock();
1054                 return NULL;
1055                 /* LCOV_EXCL_STOP */
1056         }
1057
1058         bo->bufmgr = bufmgr;
1059
1060         bo_priv = bufmgr->backend->bo_import_fd(bo, fd);
1061         if (!bo_priv) {
1062                 /* LCOV_EXCL_START */
1063                 TBM_LOG_E("error: fail to import tbm_bo by tbm_fd(%d)\n", fd);
1064                 _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FD_FAILED);
1065                 free(bo);
1066                 _tbm_bufmgr_mutex_unlock();
1067                 return NULL;
1068                 /* LCOV_EXCL_STOP */
1069         }
1070
1071         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
1072                 tbm_bo bo2 = NULL;
1073
1074                 LIST_FOR_EACH_ENTRY(bo2, &bufmgr->bo_list, item_link) {
1075                         if (bo2->priv == bo_priv) {
1076                                 TBM_TRACE("find bo(%p) ref(%d) fd(%d) flag(%s) in list\n",
1077                                                 bo2, bo2->ref_cnt, fd,
1078                                                 _tbm_flag_to_str(bo2->flags));
1079                                 bo2->ref_cnt++;
1080                                 free(bo);
1081                                 _tbm_bufmgr_mutex_unlock();
1082                                 return bo2;
1083                         }
1084                 }
1085         }
1086
1087         bufmgr->bo_cnt++;
1088
1089         bo->ref_cnt = 1;
1090         bo->priv = bo_priv;
1091
1092         if (bufmgr->backend->bo_get_flags)
1093                 bo->flags = bufmgr->backend->bo_get_flags(bo);
1094         else
1095                 bo->flags = TBM_BO_DEFAULT;
1096
1097         TBM_TRACE("import bo(%p) ref(%d) fd(%d) flag(%s)\n",
1098                         bo, bo->ref_cnt, fd, _tbm_flag_to_str(bo->flags));
1099
1100         LIST_INITHEAD(&bo->user_data_list);
1101
1102         LIST_ADD(&bo->item_link, &bufmgr->bo_list);
1103
1104         _tbm_bufmgr_mutex_unlock();
1105
1106         return bo;
1107 }
1108
1109 tbm_key
1110 tbm_bo_export(tbm_bo bo)
1111 {
1112         tbm_bufmgr bufmgr = gBufMgr;
1113         tbm_key ret;
1114
1115         _tbm_bufmgr_mutex_lock();
1116
1117         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1118         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1119
1120         if (!bufmgr->backend->bo_export) {
1121                 /* LCOV_EXCL_START */
1122                 _tbm_bufmgr_mutex_unlock();
1123                 return 0;
1124                 /* LCOV_EXCL_STOP */
1125         }
1126
1127         ret = bufmgr->backend->bo_export(bo);
1128         if (!ret) {
1129                 /* LCOV_EXCL_START */
1130                 _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FAILED);
1131                 TBM_LOG_E("error: bo(%p) tbm_key(%d)\n", bo, ret);
1132                 _tbm_bufmgr_mutex_unlock();
1133                 return ret;
1134                 /* LCOV_EXCL_STOP */
1135         }
1136
1137         TBM_TRACE("bo(%p) tbm_key(%u)\n", bo, ret);
1138
1139         _tbm_bufmgr_mutex_unlock();
1140
1141         return ret;
1142 }
1143
1144 tbm_fd
1145 tbm_bo_export_fd(tbm_bo bo)
1146 {
1147         tbm_bufmgr bufmgr = gBufMgr;
1148         tbm_fd ret;
1149
1150         _tbm_bufmgr_mutex_lock();
1151
1152         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), -1);
1153         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), -1);
1154
1155         if (!bufmgr->backend->bo_export_fd) {
1156                 /* LCOV_EXCL_START */
1157                 _tbm_bufmgr_mutex_unlock();
1158                 return -1;
1159                 /* LCOV_EXCL_STOP */
1160         }
1161
1162         ret = bufmgr->backend->bo_export_fd(bo);
1163         if (ret < 0) {
1164                 /* LCOV_EXCL_START */
1165                 _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FD_FAILED);
1166                 TBM_LOG_E("error: bo(%p) tbm_fd(%d)\n", bo, ret);
1167                 _tbm_bufmgr_mutex_unlock();
1168                 return ret;
1169                 /* LCOV_EXCL_STOP */
1170         }
1171
1172         TBM_TRACE("bo(%p) tbm_fd(%d)\n", bo, ret);
1173
1174         _tbm_bufmgr_mutex_unlock();
1175
1176         return ret;
1177 }
1178
1179 tbm_bo_handle
1180 tbm_bo_get_handle(tbm_bo bo, int device)
1181 {
1182         tbm_bufmgr bufmgr = gBufMgr;
1183         tbm_bo_handle bo_handle;
1184
1185         _tbm_bufmgr_mutex_lock();
1186
1187         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), (tbm_bo_handle) NULL);
1188         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) NULL);
1189
1190         bo_handle = bufmgr->backend->bo_get_handle(bo, device);
1191         if (bo_handle.ptr == NULL) {
1192                 /* LCOV_EXCL_START */
1193                 _tbm_set_last_result(TBM_BO_ERROR_GET_HANDLE_FAILED);
1194                 TBM_LOG_E("error: bo(%p) bo_handle(%p)\n", bo, bo_handle.ptr);
1195                 _tbm_bufmgr_mutex_unlock();
1196                 return (tbm_bo_handle) NULL;
1197                 /* LCOV_EXCL_STOP */
1198         }
1199
1200         TBM_TRACE("bo(%p) bo_handle(%p)\n", bo, bo_handle.ptr);
1201
1202         _tbm_bufmgr_mutex_unlock();
1203
1204         return bo_handle;
1205 }
1206
1207 tbm_bo_handle
1208 tbm_bo_map(tbm_bo bo, int device, int opt)
1209 {
1210         tbm_bufmgr bufmgr = gBufMgr;
1211         tbm_bo_handle bo_handle;
1212
1213         _tbm_bufmgr_mutex_lock();
1214
1215         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), (tbm_bo_handle) NULL);
1216         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) NULL);
1217
1218         if (!_tbm_bo_lock(bo, device, opt)) {
1219                 _tbm_set_last_result(TBM_BO_ERROR_LOCK_FAILED);
1220                 TBM_LOG_E("error: fail to lock bo:%p)\n", bo);
1221                 _tbm_bufmgr_mutex_unlock();
1222                 return (tbm_bo_handle) NULL;
1223         }
1224
1225         bo_handle = bufmgr->backend->bo_map(bo, device, opt);
1226         if (bo_handle.ptr == NULL) {
1227                 /* LCOV_EXCL_START */
1228                 _tbm_set_last_result(TBM_BO_ERROR_MAP_FAILED);
1229                 TBM_LOG_E("error: fail to map bo:%p\n", bo);
1230                 _tbm_bo_unlock(bo);
1231                 _tbm_bufmgr_mutex_unlock();
1232                 return (tbm_bo_handle) NULL;
1233                 /* LCOV_EXCL_STOP */
1234         }
1235
1236         /* increase the map_count */
1237         bo->map_cnt++;
1238
1239         TBM_TRACE("bo(%p) map_cnt(%d)\n", bo, bo->map_cnt);
1240
1241         _tbm_bufmgr_mutex_unlock();
1242
1243         return bo_handle;
1244 }
1245
1246 int
1247 tbm_bo_unmap(tbm_bo bo)
1248 {
1249         tbm_bufmgr bufmgr = gBufMgr;
1250         int ret;
1251
1252         _tbm_bufmgr_mutex_lock();
1253
1254         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1255         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1256         TBM_BUFMGR_RETURN_VAL_IF_FAIL(bo->map_cnt > 0, 0);
1257
1258         ret = bufmgr->backend->bo_unmap(bo);
1259         if (!ret) {
1260                 /* LCOV_EXCL_START */
1261                 TBM_LOG_E("error: bo(%p) map_cnt(%d)\n", bo, bo->map_cnt);
1262                 _tbm_set_last_result(TBM_BO_ERROR_UNMAP_FAILED);
1263                 _tbm_bufmgr_mutex_unlock();
1264                 return ret;
1265                 /* LCOV_EXCL_STOP */
1266         }
1267
1268         /* decrease the map_count */
1269         bo->map_cnt--;
1270
1271         TBM_TRACE("bo(%p) map_cnt(%d)\n", bo, bo->map_cnt);
1272
1273         _tbm_bo_unlock(bo);
1274
1275         _tbm_bufmgr_mutex_unlock();
1276
1277         return ret;
1278 }
1279
1280 int
1281 tbm_bo_swap(tbm_bo bo1, tbm_bo bo2)
1282 {
1283         tbm_bufmgr bufmgr = gBufMgr;
1284         void *temp;
1285
1286         _tbm_bufmgr_mutex_lock();
1287
1288         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1289         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo1), 0);
1290         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo2), 0);
1291
1292         TBM_TRACE("before: bo1(%p) bo2(%p)\n", bo1, bo2);
1293
1294         if (bufmgr->backend->bo_size(bo1) != bufmgr->backend->bo_size(bo2)) {
1295                 _tbm_set_last_result(TBM_BO_ERROR_SWAP_FAILED);
1296                 TBM_LOG_E("error: bo1(%p) bo2(%p)\n", bo1, bo2);
1297                 _tbm_bufmgr_mutex_unlock();
1298                 return 0;
1299         }
1300
1301         TBM_TRACE("after: bo1(%p) bo2(%p)\n", bo1, bo2);
1302
1303         temp = bo1->priv;
1304         bo1->priv = bo2->priv;
1305         bo2->priv = temp;
1306
1307         _tbm_bufmgr_mutex_unlock();
1308
1309         return 1;
1310 }
1311
1312 int
1313 tbm_bo_locked(tbm_bo bo)
1314 {
1315         tbm_bufmgr bufmgr = gBufMgr;
1316
1317         _tbm_bufmgr_mutex_lock();
1318
1319         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1320         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1321
1322         if (bufmgr->lock_type == LOCK_TRY_NEVER) {
1323                 TBM_LOG_E("bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
1324                 _tbm_bufmgr_mutex_unlock();
1325                 return 0;
1326         }
1327
1328         if (bo->lock_cnt > 0) {
1329                 TBM_TRACE("error: bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
1330                 _tbm_bufmgr_mutex_unlock();
1331                 return 1;
1332         }
1333
1334         TBM_TRACE("bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
1335         _tbm_bufmgr_mutex_unlock();
1336
1337         return 0;
1338 }
1339
1340 int
1341 tbm_bo_add_user_data(tbm_bo bo, unsigned long key,
1342                      tbm_data_free data_free_func)
1343 {
1344         tbm_user_data *data;
1345
1346         _tbm_bufmgr_mutex_lock();
1347
1348         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1349         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1350
1351         /* check if the data according to the key exist if so, return false. */
1352         data = user_data_lookup(&bo->user_data_list, key);
1353         if (data) {
1354                 TBM_TRACE("warning: user data already exist key(%ld)\n", key);
1355                 _tbm_bufmgr_mutex_unlock();
1356                 return 0;
1357         }
1358
1359         data = user_data_create(key, data_free_func);
1360         if (!data) {
1361                 TBM_LOG_E("error: bo(%p) key(%lu)\n", bo, key);
1362                 _tbm_bufmgr_mutex_unlock();
1363                 return 0;
1364         }
1365
1366         TBM_TRACE("bo(%p) key(%lu) data(%p)\n", bo, key, data->data);
1367
1368         LIST_ADD(&data->item_link, &bo->user_data_list);
1369
1370         _tbm_bufmgr_mutex_unlock();
1371
1372         return 1;
1373 }
1374
1375 int
1376 tbm_bo_set_user_data(tbm_bo bo, unsigned long key, void *data)
1377 {
1378         tbm_user_data *old_data;
1379
1380         _tbm_bufmgr_mutex_lock();
1381
1382         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1383         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1384
1385         if (LIST_IS_EMPTY(&bo->user_data_list)) {
1386                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1387                 _tbm_bufmgr_mutex_unlock();
1388                 return 0;
1389         }
1390
1391         old_data = user_data_lookup(&bo->user_data_list, key);
1392         if (!old_data) {
1393                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1394                 _tbm_bufmgr_mutex_unlock();
1395                 return 0;
1396         }
1397
1398         if (old_data->data && old_data->free_func)
1399                 old_data->free_func(old_data->data);
1400         old_data->data = data;
1401
1402         TBM_TRACE("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
1403
1404         _tbm_bufmgr_mutex_unlock();
1405
1406         return 1;
1407 }
1408
1409 int
1410 tbm_bo_get_user_data(tbm_bo bo, unsigned long key, void **data)
1411 {
1412         tbm_user_data *old_data;
1413
1414         _tbm_bufmgr_mutex_lock();
1415
1416         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1417         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1418
1419         if (!data || LIST_IS_EMPTY(&bo->user_data_list)) {
1420                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1421                 _tbm_bufmgr_mutex_unlock();
1422                 return 0;
1423         }
1424
1425         old_data = user_data_lookup(&bo->user_data_list, key);
1426         if (!old_data) {
1427                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1428                 *data = NULL;
1429                 _tbm_bufmgr_mutex_unlock();
1430                 return 0;
1431         }
1432
1433         *data = old_data->data;
1434
1435         TBM_TRACE("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
1436
1437         _tbm_bufmgr_mutex_unlock();
1438
1439         return 1;
1440 }
1441
1442 int
1443 tbm_bo_delete_user_data(tbm_bo bo, unsigned long key)
1444 {
1445         tbm_user_data *old_data;
1446
1447         _tbm_bufmgr_mutex_lock();
1448
1449         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1450         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1451
1452         if (LIST_IS_EMPTY(&bo->user_data_list)) {
1453                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1454                 _tbm_bufmgr_mutex_unlock();
1455                 return 0;
1456         }
1457
1458         old_data = user_data_lookup(&bo->user_data_list, key);
1459         if (!old_data) {
1460                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1461                 _tbm_bufmgr_mutex_unlock();
1462                 return 0;
1463         }
1464
1465         TBM_TRACE("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
1466
1467         user_data_delete(old_data);
1468
1469         _tbm_bufmgr_mutex_unlock();
1470
1471         return 1;
1472 }
1473
1474 unsigned int
1475 tbm_bufmgr_get_capability(tbm_bufmgr bufmgr)
1476 {
1477         unsigned int capabilities = TBM_BUFMGR_CAPABILITY_NONE;
1478
1479         _tbm_bufmgr_mutex_lock();
1480
1481         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), TBM_BUFMGR_CAPABILITY_NONE);
1482         TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, TBM_BUFMGR_CAPABILITY_NONE);
1483
1484         TBM_TRACE("tbm_bufmgr(%p) capability(%u)\n", bufmgr, bufmgr->capabilities);
1485
1486         capabilities = bufmgr->capabilities;
1487
1488         _tbm_bufmgr_mutex_unlock();
1489
1490         return capabilities;
1491 }
1492
1493 int
1494 tbm_bo_get_flags(tbm_bo bo)
1495 {
1496         int flags;
1497
1498         _tbm_bufmgr_mutex_lock();
1499
1500         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1501         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1502
1503         flags = bo->flags;
1504
1505         TBM_TRACE("bo(%p)\n", bo);
1506
1507         _tbm_bufmgr_mutex_unlock();
1508
1509         return flags;
1510 }
1511
1512 /* LCOV_EXCL_START */
1513 tbm_error_e
1514 tbm_get_last_error(void)
1515 {
1516         return tbm_last_error;
1517 }
1518
1519 char *
1520 tbm_bufmgr_debug_tbm_info_get(tbm_bufmgr bufmgr)
1521 {
1522         char app_name[255] = {0,}, title[512] = {0,};
1523         tbm_surface_debug_data *debug_old_data = NULL;
1524         char *str;
1525         int len = 1024*4;
1526         int c = 0;
1527
1528         pthread_mutex_lock(&gLock);
1529
1530         if (!TBM_BUFMGR_IS_VALID(bufmgr) || (bufmgr != gBufMgr)) {
1531                 TBM_LOG_E("invalid bufmgr\n");
1532                 pthread_mutex_unlock(&gLock);
1533                 return NULL;
1534         }
1535
1536         str = malloc(len);
1537         if (!str) {
1538                 TBM_LOG_E("Fail to allocate the string.\n");
1539                 pthread_mutex_unlock(&gLock);
1540                 return NULL;
1541         }
1542
1543         TBM_SNRPRINTF(str, len, c, "\n");
1544         _tbm_util_get_appname_from_pid(getpid(), app_name);
1545         _tbm_util_get_appname_brief(app_name);
1546         TBM_SNRPRINTF(str, len, c, "============TBM DEBUG: %s(%d)===========================\n",
1547                   app_name, getpid());
1548
1549         snprintf(title, 255, "%s", "no  surface     refcnt  width  height  bpp  size    n_b  n_p  flags  format    app_name       ");
1550
1551         if (!LIST_IS_EMPTY(&bufmgr->debug_key_list)) {
1552                 LIST_FOR_EACH_ENTRY(debug_old_data, &bufmgr->debug_key_list, item_link) {
1553                         strncat(title, "  ", MAX_SIZE_N(title));
1554                         strncat(title, debug_old_data->key, MAX_SIZE_N(title));
1555                 }
1556         }
1557
1558         TBM_SNRPRINTF(str, len, c, "[tbm_surface information]\n");
1559         TBM_SNRPRINTF(str, len, c, "%s\n", title);
1560
1561         /* show the tbm_surface information in surf_list */
1562         if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
1563                 tbm_surface_h surf = NULL;
1564                 int surf_cnt = 0;
1565
1566                 LIST_FOR_EACH_ENTRY(surf, &bufmgr->surf_list, item_link) {
1567                         char data[512] = {0,};
1568                         unsigned int pid;
1569                         int i;
1570
1571                         pid = _tbm_surface_internal_get_debug_pid(surf);
1572                         if (!pid) {
1573                                 /* if pid is null, set the self_pid */
1574                                 pid = getpid();
1575                         }
1576
1577                         memset(app_name, 0x0, 255 * sizeof(char));
1578                         _tbm_util_get_appname_from_pid(pid, app_name);
1579                         _tbm_util_get_appname_brief(app_name);
1580
1581                         snprintf(data, 255, "%-2d  %-9p    %-4d  %-5u  %-6u  %-3u  %-6u   %-2d   %-2d    %-3d  %-8s  %-15s",
1582                                   ++surf_cnt,
1583                                   surf,
1584                                   surf->refcnt,
1585                                   surf->info.width,
1586                                   surf->info.height,
1587                                   surf->info.bpp,
1588                                   surf->info.size / 1024,
1589                                   surf->num_bos,
1590                                   surf->num_planes,
1591                                   surf->flags,
1592                                   _tbm_surface_internal_format_to_str(surf->info.format) + 11,
1593                                   app_name);
1594
1595                         if (!LIST_IS_EMPTY(&bufmgr->debug_key_list)) {
1596                                 LIST_FOR_EACH_ENTRY(debug_old_data, &bufmgr->debug_key_list, item_link) {
1597                                         char *value;
1598
1599                                         strncat(data, "  ", MAX_SIZE_N(title));
1600
1601                                         value = _tbm_surface_internal_get_debug_data(surf, debug_old_data->key);
1602                                         if (value)
1603                                                 strncat(data, value, MAX_SIZE_N(title));
1604                                         else
1605                                                 strncat(data, "none", MAX_SIZE_N(title));
1606                                 }
1607                         }
1608                         TBM_SNRPRINTF(str, len, c, "%s\n", data);
1609
1610                         for (i = 0; i < surf->num_bos; i++) {
1611                                 TBM_SNRPRINTF(str, len, c, " bo:%-12p  %-26d%-10d\n",
1612                                           surf->bos[i],
1613                                           surf->bos[i]->ref_cnt,
1614                                           bufmgr->backend->bo_size(surf->bos[i]) / 1024);
1615                         }
1616                 }
1617         } else
1618                 TBM_SNRPRINTF(str, len, c, " no tbm_surfaces.\n");
1619         TBM_SNRPRINTF(str, len, c, "\n");
1620
1621         TBM_SNRPRINTF(str, len, c, "[tbm_bo information]\n");
1622         TBM_SNRPRINTF(str, len, c, "no  bo          refcnt  size    lock_cnt  map_cnt  flags  surface     name\n");
1623
1624         /* show the tbm_bo information in bo_list */
1625         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
1626                 int bo_cnt = 0;
1627                 tbm_bo bo = NULL;
1628
1629                 LIST_FOR_EACH_ENTRY(bo, &bufmgr->bo_list, item_link) {
1630                         TBM_SNRPRINTF(str, len, c, "%-4d%-11p   %-4d  %-6d     %-5d     %-4u    %-3d  %-11p  %-4d\n",
1631                                   ++bo_cnt,
1632                                   bo,
1633                                   bo->ref_cnt,
1634                                   bufmgr->backend->bo_size(bo) / 1024,
1635                                   bo->lock_cnt,
1636                                   bo->map_cnt,
1637                                   bo->flags,
1638                                   bo->surface,
1639                                   bufmgr->backend->bo_export(bo));
1640                 }
1641         } else
1642                 TBM_SNRPRINTF(str, len, c, "no tbm_bos.\n");
1643         TBM_SNRPRINTF(str, len, c, "\n");
1644
1645         TBM_SNRPRINTF(str, len, c, "===============================================================\n");
1646
1647         pthread_mutex_unlock(&gLock);
1648
1649         return str;
1650 }
1651
1652 void
1653 tbm_bufmgr_debug_show(tbm_bufmgr bufmgr)
1654 {
1655         char * str;
1656         str = tbm_bufmgr_debug_tbm_info_get(bufmgr);
1657         if (str) {
1658                 TBM_DEBUG("     %s", str);
1659                 free(str);
1660         }
1661 }
1662
1663 void
1664 tbm_bufmgr_debug_trace(tbm_bufmgr bufmgr, int onoff)
1665 {
1666         _tbm_bufmgr_mutex_lock();
1667
1668         TBM_BUFMGR_RETURN_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr));
1669         TBM_BUFMGR_RETURN_IF_FAIL(bufmgr == gBufMgr);
1670
1671 #ifdef TRACE
1672         TBM_LOG_D("bufmgr=%p onoff=%d\n", bufmgr, onoff);
1673         bTrace = onoff;
1674 #endif
1675
1676         _tbm_bufmgr_mutex_unlock();
1677 }
1678
1679 void
1680 tbm_bufmgr_debug_dump_set_scale(double scale)
1681 {
1682         pthread_mutex_lock(&gLock);
1683         scale_factor = scale;
1684         pthread_mutex_unlock(&gLock);
1685 }
1686
1687 int
1688 tbm_bufmgr_debug_get_ref_count(void)
1689 {
1690         return (gBufMgr) ? gBufMgr->ref_count : 0;
1691 }
1692
1693 int
1694 tbm_bufmgr_debug_queue_dump(char *path, int count, int onoff)
1695 {
1696         pthread_mutex_lock(&gLock);
1697
1698         if (onoff == 0) {
1699                 TBM_LOG_D("count=%d onoff=%d\n", count, onoff);
1700                 b_dump_queue = 0;
1701                 tbm_surface_internal_dump_end();
1702         } else {
1703                 int w, h;
1704
1705                 if (path == NULL) {
1706                         TBM_LOG_E("path is null");
1707                         pthread_mutex_unlock(&gLock);
1708                         return 0;
1709                 }
1710                 TBM_LOG_D("path=%s count=%d onoff=%d\n", path, count, onoff);
1711
1712                 if (_tbm_util_get_max_surface_size(&w, &h) == 0) {
1713                         TBM_LOG_E("Fail to get tbm_surface size.\n");
1714                         pthread_mutex_unlock(&gLock);
1715                         return 0;
1716                 }
1717
1718                 tbm_surface_internal_dump_with_scale_start(path, w, h, count, scale_factor);
1719                 scale_factor = 0;
1720
1721                 b_dump_queue = 1;
1722         }
1723
1724         pthread_mutex_unlock(&gLock);
1725         return 1;
1726 }
1727
1728 int
1729 tbm_bufmgr_debug_dump_all(char *path)
1730 {
1731         int w, h, count = 0;
1732         tbm_surface_h surface = NULL;
1733
1734         TBM_RETURN_VAL_IF_FAIL(path != NULL, 0);
1735         TBM_LOG_D("path=%s\n", path);
1736
1737         pthread_mutex_lock(&gLock);
1738
1739         count = _tbm_util_get_max_surface_size(&w, &h);
1740         if (count == 0) {
1741                 TBM_LOG_E("No tbm_surface.\n");
1742                 pthread_mutex_unlock(&gLock);
1743                 return 1;
1744         }
1745
1746         tbm_surface_internal_dump_with_scale_start(path, w, h, count, scale_factor);
1747         scale_factor = 0;
1748
1749         LIST_FOR_EACH_ENTRY(surface, &gBufMgr->surf_list, item_link)
1750                 tbm_surface_internal_dump_buffer(surface, "dump_all");
1751
1752         tbm_surface_internal_dump_end();
1753
1754         pthread_mutex_unlock(&gLock);
1755
1756         return 1;
1757 }
1758
1759 /* internal function */
1760 tbm_bufmgr
1761 _tbm_bufmgr_get_bufmgr(void)
1762 {
1763         return gBufMgr;
1764 }
1765
1766 int
1767 _tbm_bo_set_surface(tbm_bo bo, tbm_surface_h surface)
1768 {
1769         _tbm_bufmgr_mutex_lock();
1770
1771         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1772         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1773
1774         bo->surface = surface;
1775
1776         _tbm_bufmgr_mutex_unlock();
1777
1778         return 1;
1779 }
1780
1781 int
1782 tbm_bufmgr_bind_native_display(tbm_bufmgr bufmgr, void *native_display)
1783 {
1784         int ret;
1785
1786         _tbm_bufmgr_mutex_lock();
1787
1788         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1789
1790         if (!bufmgr->backend->bufmgr_bind_native_display) {
1791                 TBM_TRACE("skip: tbm_bufmgr(%p) native_display(%p)\n",
1792                                 bufmgr, native_display);
1793                 _tbm_bufmgr_mutex_unlock();
1794                 return 1;
1795         }
1796
1797         ret = bufmgr->backend->bufmgr_bind_native_display(bufmgr, native_display);
1798         if (!ret) {
1799                 TBM_LOG_E("error: tbm_bufmgr(%p) native_display(%p)\n",
1800                                 bufmgr, native_display);
1801                 _tbm_bufmgr_mutex_unlock();
1802                 return 0;
1803         }
1804
1805         TBM_TRACE("tbm_bufmgr(%p) native_display(%p)\n", bufmgr, native_display);
1806
1807         _tbm_bufmgr_mutex_unlock();
1808
1809         return 1;
1810 }
1811
1812 tbm_bufmgr
1813 tbm_bufmgr_server_init(void)
1814 {
1815         tbm_bufmgr bufmgr;
1816
1817         bufmgr = _tbm_bufmgr_init(-1, 1);
1818
1819         return bufmgr;
1820 }
1821
1822 int tbm_bufmgr_get_fd_limit(void)
1823 {
1824         struct rlimit lim;
1825
1826         if (getrlimit(RLIMIT_NOFILE, &lim))
1827                 return 1024;
1828
1829         return (int)lim.rlim_cur;
1830 }
1831 /* LCOV_EXCL_STOP */