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