bufmgr: make tbm_bufmgr_bo_lock_type
[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 static void
100 _tbm_set_last_result(tbm_error_e err)
101 {
102         tbm_last_error = err;
103 }
104
105 /* LCOV_EXCL_START */
106 static bool
107 _tbm_bufmgr_mutex_init(void)
108 {
109         static bool tbm_bufmgr_mutex_init = false;
110
111         if (tbm_bufmgr_mutex_init)
112                 return true;
113
114         if (pthread_mutex_init(&tbm_bufmgr_lock, NULL)) {
115                 TBM_LOG_E("fail: Cannot pthread_mutex_init for tbm_bufmgr_lock.\n");
116                 return false;
117         }
118
119         tbm_bufmgr_mutex_init = true;
120
121         return true;
122 }
123
124 static void
125 _tbm_bufmgr_mutex_lock(void)
126 {
127         if (!_tbm_bufmgr_mutex_init()) {
128                 TBM_LOG_E("fail: _tbm_bufmgr_mutex_init()\n");
129                 return;
130         }
131
132         pthread_mutex_lock(&tbm_bufmgr_lock);
133 }
134
135 static void
136 _tbm_bufmgr_mutex_unlock(void)
137 {
138         pthread_mutex_unlock(&tbm_bufmgr_lock);
139 }
140
141 static char *
142 _tbm_flag_to_str(int f)
143 {
144         static char str[255];
145
146         if (f == TBM_BO_DEFAULT)
147                  snprintf(str, 255, "DEFAULT");
148         else {
149                 int c = 0;
150
151                 if (f & TBM_BO_SCANOUT)
152                         c += snprintf(&str[c], 255-c, "SCANOUT");
153
154                 if (f & TBM_BO_NONCACHABLE) {
155                         if (c >= 0 && c < 255)
156                                 c += snprintf(&str[c], 255-c, ", ");
157
158                         if (c >= 0 && c < 255)
159                                 c += snprintf(&str[c], 255-c, "NONCACHABLE,");
160                 }
161
162                 if (f & TBM_BO_WC) {
163                         if (c >= 0 && c < 255)
164                                 c += snprintf(&str[c], 255-c, ", ");
165
166                         if (c >= 0 && c < 255)
167                                 c += snprintf(&str[c], 255-c, "WC");
168                 }
169         }
170
171         return str;
172 }
173
174 static void
175 _tbm_util_check_bo_cnt(tbm_bufmgr bufmgr)
176 {
177         static int last_chk_bo_cnt = 0;
178
179         if ((bufmgr->bo_cnt >= 500) && ((bufmgr->bo_cnt % 20) == 0) &&
180                 (bufmgr->bo_cnt > last_chk_bo_cnt)) {
181                 TBM_DEBUG("============TBM BO CNT DEBUG: bo_cnt=%d\n",
182                                 bufmgr->bo_cnt);
183
184                 tbm_bufmgr_debug_show(bufmgr);
185
186                 last_chk_bo_cnt = bufmgr->bo_cnt;
187         }
188 }
189
190 static int
191 _tbm_util_get_max_surface_size(int *w, int *h)
192 {
193         tbm_surface_info_s info;
194         tbm_surface_h surface = NULL;
195         int count = 0;
196
197         *w = 0;
198         *h = 0;
199
200         if (gBufMgr == NULL || LIST_IS_EMPTY(&gBufMgr->surf_list))
201                 return count;
202
203         LIST_FOR_EACH_ENTRY(surface, &gBufMgr->surf_list, item_link) {
204                 if (tbm_surface_get_info(surface, &info) == TBM_SURFACE_ERROR_NONE) {
205                         count++;
206                         if (*w < info.width)
207                                 *w = info.width;
208                         if (*h < info.height)
209                                 *h = info.height;
210                 }
211         }
212
213         return count;
214 }
215
216 static void
217 _tbm_util_get_appname_brief(char *brief)
218 {
219         char delim[] = "/";
220         char *token = NULL;
221         char temp[255] = {0,};
222         char *saveptr = NULL;
223
224         token = strtok_r(brief, delim, &saveptr);
225
226         while (token != NULL) {
227                 memset(temp, 0x00, 255 * sizeof(char));
228                 strncpy(temp, token, 254 * sizeof(char));
229                 token = strtok_r(NULL, delim, &saveptr);
230         }
231
232         snprintf(brief, sizeof(temp), "%s", temp);
233 }
234
235 static void
236 _tbm_util_get_appname_from_pid(long pid, char *str)
237 {
238         char fn_cmdline[255] = {0, }, cmdline[255];
239         FILE *fp;
240         int len;
241
242         snprintf(fn_cmdline, sizeof(fn_cmdline), "/proc/%ld/cmdline", pid);
243
244         fp = fopen(fn_cmdline, "r");
245         if (fp == 0) {
246                 TBM_LOG_E("cannot file open %s\n", fn_cmdline);
247                 return;
248         }
249
250         if (!fgets(cmdline, 255, fp)) {
251                 TBM_LOG_E("fail to get appname for pid(%ld)\n", pid);
252                 fclose(fp);
253                 return;
254         }
255
256         fclose(fp);
257
258         len = strlen(cmdline);
259         if (len < 1)
260                 memset(cmdline, 0x00, 255);
261         else
262                 cmdline[len] = 0;
263
264         snprintf(str, sizeof(cmdline), "%s", cmdline);
265 }
266 /* LCOV_EXCL_STOP */
267
268 tbm_user_data
269 *user_data_lookup(struct list_head *user_data_list, unsigned long key)
270 {
271         tbm_user_data *old_data = NULL;
272
273         if (LIST_IS_EMPTY(user_data_list))
274                 return NULL;
275
276         LIST_FOR_EACH_ENTRY(old_data, user_data_list, item_link) {
277                 if (old_data->key == key)
278                         return old_data;
279         }
280
281         return NULL;
282 }
283
284 tbm_user_data
285 *user_data_create(unsigned long key, tbm_data_free data_free_func)
286 {
287         tbm_user_data *user_data;
288
289         user_data = calloc(1, sizeof(tbm_user_data));
290         if (!user_data) {
291                 /* LCOV_EXCL_START */
292                 TBM_LOG_E("fail to allocate an user_date\n");
293                 return NULL;
294                 /* LCOV_EXCL_STOP */
295         }
296
297         user_data->key = key;
298         user_data->free_func = data_free_func;
299
300         return user_data;
301 }
302
303 void
304 user_data_delete(tbm_user_data *user_data)
305 {
306         if (user_data->data && user_data->free_func)
307                 user_data->free_func(user_data->data);
308
309         LIST_DEL(&user_data->item_link);
310
311         free(user_data);
312 }
313
314 static int
315 _bo_lock(tbm_bo bo, int device, int opt)
316 {
317         tbm_bufmgr bufmgr = bo->bufmgr;
318         int ret = 1;
319
320         if (bufmgr->backend->bo_lock)
321                 ret = bufmgr->backend->bo_lock(bo, device, opt);
322
323         return ret;
324 }
325
326 static void
327 _bo_unlock(tbm_bo bo)
328 {
329         tbm_bufmgr bufmgr = bo->bufmgr;
330
331         if (bufmgr->backend->bo_unlock)
332                 bufmgr->backend->bo_unlock(bo);
333 }
334
335 static int
336 _tbm_bo_lock(tbm_bo bo, int device, int opt)
337 {
338         tbm_bufmgr bufmgr;
339         int old, ret;
340
341         if (!bo)
342                 return 0;
343
344         bufmgr = bo->bufmgr;
345
346         /* do not try to lock the bo */
347         if (bufmgr->bo_lock_type == TBM_BUFMGR_BO_LOCK_TYPE_NEVER)
348                 return 1;
349
350         if (bo->lock_cnt < 0) {
351                 TBM_LOG_E("error bo:%p LOCK_CNT=%d\n",
352                         bo, bo->lock_cnt);
353                 return 0;
354         }
355
356         old = bo->lock_cnt;
357
358         switch (bufmgr->bo_lock_type) {
359         case TBM_BUFMGR_BO_LOCK_TYPE_ONCE:
360                 if (bo->lock_cnt == 0) {
361                         _tbm_bufmgr_mutex_unlock();
362                         ret = _bo_lock(bo, device, opt);
363                         _tbm_bufmgr_mutex_lock();
364                         if (ret)
365                                 bo->lock_cnt++;
366                 } else
367                         ret = 1;
368                 break;
369         case TBM_BUFMGR_BO_LOCK_TYPE_ALWAYS:
370                 _tbm_bufmgr_mutex_unlock();
371                 ret = _bo_lock(bo, device, opt);
372                 _tbm_bufmgr_mutex_lock();
373                 if (ret)
374                         bo->lock_cnt++;
375                 break;
376         default:
377                 TBM_LOG_E("error bo:%p bo_lock_type[%d] is wrong.\n",
378                                 bo, bufmgr->bo_lock_type);
379                 ret = 0;
380                 break;
381         }
382
383         TBM_DBG_LOCK(">> LOCK bo:%p(%d->%d)\n", bo, old, bo->lock_cnt);
384
385         return ret;
386 }
387
388 static void
389 _tbm_bo_unlock(tbm_bo bo)
390 {
391         tbm_bufmgr bufmgr;
392         int old;
393
394         if (!bo)
395                 return;
396
397         bufmgr = bo->bufmgr;
398
399         /* do not try to unlock the bo */
400         if (bufmgr->bo_lock_type == TBM_BUFMGR_BO_LOCK_TYPE_NEVER)
401                 return;
402
403         old = bo->lock_cnt;
404
405         switch (bufmgr->bo_lock_type) {
406         case TBM_BUFMGR_BO_LOCK_TYPE_ONCE:
407                 if (bo->lock_cnt > 0) {
408                         bo->lock_cnt--;
409                         if (bo->lock_cnt == 0)
410                                 _bo_unlock(bo);
411                 }
412                 break;
413         case TBM_BUFMGR_BO_LOCK_TYPE_ALWAYS:
414                 if (bo->lock_cnt > 0) {
415                         bo->lock_cnt--;
416                         _bo_unlock(bo);
417                 }
418                 break;
419         default:
420                 TBM_LOG_E("error bo:%p bo_lock_type[%d] is wrong.\n",
421                                 bo, bufmgr->bo_lock_type);
422                 break;
423         }
424
425         if (bo->lock_cnt < 0)
426                 bo->lock_cnt = 0;
427
428         TBM_DBG_LOCK(">> UNLOCK bo:%p(%d->%d)\n", bo, old, bo->lock_cnt);
429 }
430
431 static int
432 _tbm_bo_is_valid(tbm_bo bo)
433 {
434         tbm_bo old_data = NULL;
435
436         if (bo == NULL || gBufMgr == NULL) {
437                 TBM_LOG_E("error: bo is NULL or tbm_bufmgr was deinited\n");
438                 return 0;
439         }
440
441         if (LIST_IS_EMPTY(&gBufMgr->bo_list)) {
442                 TBM_LOG_E("error: gBufMgr->bo_list is EMPTY.\n");
443                 return 0;
444         }
445
446         LIST_FOR_EACH_ENTRY(old_data, &gBufMgr->bo_list, item_link) {
447                 if (old_data == bo)
448                         return 1;
449         }
450
451         TBM_LOG_E("error: No valid bo(%p).\n", bo);
452
453         return 0;
454 }
455
456 static void
457 _tbm_bo_free(tbm_bo bo)
458 {
459         tbm_bufmgr bufmgr = bo->bufmgr;
460
461         /* destory the user_data_list */
462         if (!LIST_IS_EMPTY(&bo->user_data_list)) {
463                 tbm_user_data *old_data = NULL, *tmp;
464
465                 LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp,
466                                 &bo->user_data_list, item_link) {
467                         TBM_DBG("free user_data\n");
468                         user_data_delete(old_data);
469                 }
470         }
471
472         while (bo->lock_cnt > 0) {
473                 TBM_LOG_E("error lock_cnt:%d\n", bo->lock_cnt);
474                 _bo_unlock(bo);
475                 bo->lock_cnt--;
476         }
477
478         /* call the bo_free */
479         bufmgr->backend->bo_free(bo);
480         bo->priv = NULL;
481
482         LIST_DEL(&bo->item_link);
483         free(bo);
484
485         bufmgr->bo_cnt--;
486 }
487
488 /* LCOV_EXCL_START */
489 static int
490 _check_version(TBMModuleVersionInfo *data)
491 {
492         int abimaj, abimin;
493         int vermaj, vermin;
494
495         abimaj = GET_ABI_MAJOR(data->abiversion);
496         abimin = GET_ABI_MINOR(data->abiversion);
497
498         TBM_DBG("TBM module %s: vendor=\"%s\" ABI=%d,%d\n",
499             data->modname ? data->modname : "UNKNOWN!",
500             data->vendor ? data->vendor : "UNKNOWN!", abimaj, abimin);
501
502         vermaj = GET_ABI_MAJOR(TBM_ABI_VERSION);
503         vermin = GET_ABI_MINOR(TBM_ABI_VERSION);
504
505         TBM_DBG("TBM ABI version %d.%d\n",
506             vermaj, vermin);
507
508         if (abimaj != vermaj) {
509                 TBM_LOG_E("TBM module ABI major ver(%d) doesn't match the TBM's ver(%d)\n",
510                         abimaj, vermaj);
511                 return 0;
512         } else if (abimin > vermin) {
513                 TBM_LOG_E("TBM module ABI minor ver(%d) is newer than the TBM's ver(%d)\n",
514                         abimin, vermin);
515                 return 0;
516         }
517
518         return 1;
519 }
520
521 static int
522 _tbm_bufmgr_load_module(tbm_bufmgr bufmgr, int fd, const char *file)
523 {
524         char path[PATH_MAX] = {0, };
525         TBMModuleVersionInfo *vers;
526         TBMModuleData *initdata;
527         ModuleInitProc init;
528         void *module_data;
529
530         snprintf(path, sizeof(path), BUFMGR_MODULE_DIR "/%s", file);
531
532         module_data = dlopen(path, RTLD_LAZY);
533         if (!module_data) {
534                 TBM_LOG_E("failed to load module: %s(%s)\n", dlerror(), file);
535                 return 0;
536         }
537
538         initdata = dlsym(module_data, "tbmModuleData");
539         if (!initdata) {
540                 TBM_LOG_E("Error: module does not have data object.\n");
541                 goto err;
542         }
543
544         vers = initdata->vers;
545         if (!vers) {
546                 TBM_LOG_E("Error: module does not supply version information.\n");
547                 goto err;
548         }
549
550         init = initdata->init;
551         if (!init) {
552                 TBM_LOG_E("Error: module does not supply init symbol.\n");
553                 goto err;
554         }
555
556         if (!_check_version(vers)) {
557                 TBM_LOG_E("Fail to check version.\n");
558                 goto err;
559         }
560
561         if (!init(bufmgr, fd)) {
562                 TBM_LOG_E("Fail to init module(%s)\n", file);
563                 goto err;
564         }
565
566         if (!bufmgr->backend || !bufmgr->backend->priv) {
567                 TBM_LOG_E("Error: module(%s) wrong operation. Check backend or backend's priv.\n", file);
568                 goto err;
569         }
570
571         bufmgr->module_data = module_data;
572
573         TBM_DBG("Success to load module(%s)\n", file);
574
575         return 1;
576
577 err:
578         dlclose(module_data);
579         return 0;
580 }
581
582 static int
583 _tbm_load_module(tbm_bufmgr bufmgr, int fd)
584 {
585         struct dirent **namelist;
586         int ret = 0, n;
587
588         /* load bufmgr priv from default lib */
589         if (_tbm_bufmgr_load_module(bufmgr, fd, DEFAULT_LIB))
590                 return 1;
591
592         /* load bufmgr priv from configured path */
593         n = scandir(BUFMGR_MODULE_DIR, &namelist, 0, alphasort);
594         if (n < 0) {
595                 TBM_LOG_E("no files : %s\n", BUFMGR_MODULE_DIR);
596                 return 0;
597         }
598
599         while (n--) {
600                 if (!ret && strstr(namelist[n]->d_name, PREFIX_LIB)) {
601                         const char *p = strstr(namelist[n]->d_name, SUFFIX_LIB);
602
603                         if (p && !strcmp(p, SUFFIX_LIB))
604                                 ret = _tbm_bufmgr_load_module(bufmgr, fd,
605                                                         namelist[n]->d_name);
606                 }
607
608                 free(namelist[n]);
609         }
610
611         free(namelist);
612
613         return ret;
614 }
615 /* LCOV_EXCL_STOP */
616
617 static tbm_bufmgr
618 _tbm_bufmgr_init(int fd, int server)
619 {
620 #ifdef TBM_BUFMGR_INIT_TIME
621         struct timeval start_tv, end_tv;
622 #endif
623         char *env;
624
625 #ifdef TBM_BUFMGR_INIT_TIME
626         /* get the start tv */
627         gettimeofday(&start_tv, NULL);
628 #endif
629
630         /* LCOV_EXCL_START */
631 #ifdef HAVE_DLOG
632         env = getenv("TBM_DLOG");
633         if (env) {
634                 bDlog = atoi(env);
635                 TBM_LOG_D("TBM_DLOG=%s\n", env);
636         } else
637                 bDlog = 1;
638 #endif
639
640 #ifdef DEBUG
641         env = getenv("TBM_DEBUG");
642         if (env) {
643                 bDebug = atoi(env);
644                 TBM_LOG_D("TBM_DEBUG=%s\n", env);
645         } else
646                 bDebug = 0;
647 #endif
648
649 #ifdef TRACE
650         env = getenv("TBM_TRACE");
651         if (env) {
652                 bTrace = atoi(env);
653                 TBM_LOG_D("TBM_TRACE=%s\n", env);
654         } else
655                 bTrace = 0;
656 #endif
657
658         pthread_mutex_lock(&gLock);
659
660         if (fd >= 0) {
661                 TBM_LOG_W("!!!!!WARNING:: The tbm_bufmgr_init DOSE NOT use argument fd ANYMORE.\n");
662                 TBM_LOG_W("!!!!!WARNING:: IT WILL BE CHANGED like tbm_bufmgr_init(int fd) --> tbm_bufmgr_init(void).\n");
663         }
664
665
666         /* initialize buffer manager */
667         if (gBufMgr) {
668                 gBufMgr->ref_count++;
669                 TBM_TRACE("reuse  tbm_bufmgr(%p) ref_count(%d) fd(%d)\n", gBufMgr, gBufMgr->ref_count, gBufMgr->fd);
670                 pthread_mutex_unlock(&gLock);
671                 return gBufMgr;
672         }
673
674         TBM_DBG("bufmgr init\n");
675
676         /* allocate bufmgr */
677         gBufMgr = calloc(1, sizeof(struct _tbm_bufmgr));
678         if (!gBufMgr) {
679                 _tbm_set_last_result(TBM_BO_ERROR_HEAP_ALLOC_FAILED);
680                 TBM_TRACE("error: fail to alloc bufmgr fd(%d)\n", fd);
681                 pthread_mutex_unlock(&gLock);
682                 return NULL;
683         }
684
685         gBufMgr->fd = fd;
686
687         /* set the display_server flag before loading the backend module */
688         if (server) {
689                 TBM_LOG_I("The tbm_bufmgr(%p) is used by display server. Need to bind the native_display.\n", gBufMgr);
690                 gBufMgr->display_server = 1;
691         }
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 bo_lock_type */
715         env = getenv("BUFMGR_LOCK_TYPE");
716         if (env && !strcmp(env, "always"))
717                 gBufMgr->bo_lock_type = TBM_BUFMGR_BO_LOCK_TYPE_ALWAYS;
718         else if (env && !strcmp(env, "none"))
719                 gBufMgr->bo_lock_type = TBM_BUFMGR_BO_LOCK_TYPE_NEVER;
720         else if (env && !strcmp(env, "once"))
721                 gBufMgr->bo_lock_type = TBM_BUFMGR_BO_LOCK_TYPE_ONCE;
722         else
723                 gBufMgr->bo_lock_type = TBM_BUFMGR_BO_LOCK_TYPE_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->bo_lock_type == TBM_BUFMGR_BO_LOCK_TYPE_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 tbm_bufmgr
1807 tbm_bufmgr_server_init(void)
1808 {
1809         tbm_bufmgr bufmgr;
1810
1811         bufmgr = _tbm_bufmgr_init(-1, 1);
1812
1813         return bufmgr;
1814 }
1815
1816 int tbm_bufmgr_get_fd_limit(void)
1817 {
1818         struct rlimit lim;
1819
1820         if (getrlimit(RLIMIT_NOFILE, &lim))
1821                 return 1024;
1822
1823         return (int)lim.rlim_cur;
1824 }
1825 /* LCOV_EXCL_STOP */