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