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