Add check for locking and mapping and unmapping fail
[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 ret;
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 static int
555 _tbm_bo_is_valid(tbm_bo bo)
556 {
557     tbm_bo old_data=NULL, tmp = NULL;;
558
559     if( bo == NULL )
560         return 0;
561
562     if(!LIST_IS_EMPTY (&gBufMgr->bo_list))
563     {
564                 LIST_FOR_EACH_ENTRY_SAFE (old_data, tmp, &gBufMgr->bo_list, item_link)
565                 {
566                         if(old_data == bo)
567                         {
568                                 return 1;
569                         }
570                 }
571
572     }
573     return 0;
574 }
575
576 static void
577 _tbm_bo_ref (tbm_bo bo)
578 {
579     bo->ref_cnt++;
580 }
581
582 static void
583 _tbm_bo_unref (tbm_bo bo)
584 {
585     tbm_bufmgr bufmgr = bo->bufmgr;
586     tbm_user_data *old_data = NULL, *tmp = NULL;
587
588     if (bo->ref_cnt <= 0)
589         return;
590
591     bo->ref_cnt--;
592     if (bo->ref_cnt == 0)
593     {
594         /* destory the user_data_list */
595         if (!LIST_IS_EMPTY (&bo->user_data_list))
596         {
597             LIST_FOR_EACH_ENTRY_SAFE (old_data, tmp, &bo->user_data_list, item_link)
598             {
599                 DBG ("[libtbm:%d] free user_data \n", getpid());
600                 _user_data_delete (old_data);
601             }
602         }
603
604         if (bo->lock_cnt > 0)
605         {
606             TBM_LOG ("[libtbm:%d] "
607                     "error %s:%d lock_cnt:%d\n",
608                     getpid(), __FUNCTION__, __LINE__, bo->lock_cnt);
609             _bo_unlock (bo);
610         }
611
612         /* Destroy Global Lock */
613         _tbm_bo_destroy_state (bo);
614
615         /* call the bo_free */
616         bufmgr->backend->bo_free (bo);
617         bo->priv = NULL;
618
619         LIST_DEL (&bo->item_link);
620         free(bo);
621         bo = NULL;
622     }
623
624 }
625
626 static int
627 _tbm_bufmgr_init_state (tbm_bufmgr bufmgr)
628 {
629     RETURN_VAL_CHECK_FLAG (TBM_ALL_CTRL_BACKEND_VALID(bufmgr->backend->flags), 1);
630
631     bufmgr->lock_fd = open (tgl_devfile, O_RDWR);
632
633     if(bufmgr->lock_fd < 0)
634     {
635         bufmgr->lock_fd = open (tgl_devfile1, O_RDWR);
636         if(bufmgr->lock_fd < 0)
637         {
638
639             TBM_LOG ("[libtbm:%d] "
640                     "error: Fail to open global_lock:%s\n",
641                     getpid(), tgl_devfile);
642             return 0;
643         }
644     }
645
646    if (!_tgl_init(bufmgr->lock_fd, GLOBAL_KEY))
647    {
648         TBM_LOG ("[libtbm:%d] "
649                 "error: Fail to initialize the tgl\n",
650                 getpid());
651         return 0;
652    }
653
654    return 1;
655 }
656
657 static void
658 _tbm_bufmgr_destroy_state (tbm_bufmgr bufmgr)
659 {
660     RETURN_CHECK_FLAG (TBM_ALL_CTRL_BACKEND_VALID(bufmgr->backend->flags));
661
662     close (bufmgr->lock_fd);
663 }
664
665 static int
666 _check_version (TBMModuleVersionInfo *data)
667 {
668     int abimaj, abimin;
669     int vermaj, vermin;
670
671     abimaj = GET_ABI_MAJOR (data->abiversion);
672     abimin = GET_ABI_MINOR (data->abiversion);
673
674     TBM_LOG ("[libtbm:%d] "
675             "TBM module %s: vendor=\"%s\" ABI=%d,%d\n",
676             getpid(), data->modname ? data->modname : "UNKNOWN!",
677             data->vendor ? data->vendor : "UNKNOWN!", abimaj, abimin);
678
679     vermaj = GET_ABI_MAJOR (TBM_ABI_VERSION);
680     vermin = GET_ABI_MINOR (TBM_ABI_VERSION);
681
682     DBG ("[libtbm:%d] " "TBM ABI version %d.%d\n", getpid(), vermaj, vermin);
683
684     if (abimaj != vermaj)
685     {
686         TBM_LOG ("[libtbm:%d] "
687                 "TBM module ABI major ver(%d) doesn't match the TBM's ver(%d)\n",
688                 getpid(), abimaj, vermaj);
689         return 0;
690     }
691     else if (abimin > vermin)
692     {
693         TBM_LOG ("[libtbm:%d] "
694                 "TBM module ABI minor ver(%d) is newer than the TBM's ver(%d)\n",
695                 getpid(), abimin, vermin);
696         return 0;
697     }
698     return 1;
699 }
700
701 static int
702 _tbm_bufmgr_load_module (tbm_bufmgr bufmgr, int fd, const char *file)
703 {
704     char path[PATH_MAX] = {0,};
705     TBMModuleData *initdata = NULL;
706     void * module_data;
707
708     snprintf(path, sizeof(path), BUFMGR_MODULE_DIR "/%s", file);
709
710     module_data = dlopen (path, RTLD_LAZY);
711     if (!module_data)
712     {
713         TBM_LOG ("[libtbm:%d] "
714                 "failed to load module: %s(%s)\n",
715                 getpid(), dlerror(), file);
716         return 0;
717     }
718
719     initdata = dlsym (module_data, "tbmModuleData");
720     if (initdata)
721     {
722         ModuleInitProc init;
723         TBMModuleVersionInfo *vers;
724
725         vers = initdata->vers;
726         init = initdata->init;
727
728         if (vers)
729         {
730             if (!_check_version (vers))
731             {
732                 dlclose (module_data);
733                 return 0;
734             }
735         }
736         else
737         {
738             TBM_LOG ("[libtbm:%d] "
739                     "Error: module does not supply version information.\n",
740                     getpid());
741
742             dlclose (module_data);
743             return 0;
744         }
745
746         if (init)
747         {
748             if(!init (bufmgr, fd))
749             {
750                 TBM_LOG ("[libtbm:%d] "
751                         "Fail to init module(%s)\n",
752                         getpid(), file);
753                 dlclose (module_data);
754                 return 0;
755             }
756
757             if (!bufmgr->backend || !bufmgr->backend->priv)
758             {
759                 TBM_LOG ("[libtbm:%d] "
760                         "Error: module(%s) wrong operation. Check backend or backend's priv.\n",
761                         getpid(), file);
762                 dlclose (module_data);
763                 return 0;
764             }
765         }
766         else
767         {
768             TBM_LOG ("[libtbm:%d] "
769                     "Error: module does not supply init symbol.\n", getpid());
770             dlclose (module_data);
771             return 0;
772         }
773     }
774     else
775     {
776         TBM_LOG ("[libtbm:%d] "
777                 "Error: module does not have data object.\n", getpid());
778         dlclose (module_data);
779         return 0;
780     }
781
782     bufmgr->module_data = module_data;
783
784     TBM_LOG ("[libtbm:%d] "
785             "Success to load module(%s)\n", getpid(), file);
786
787     return 1;
788 }
789
790 static int _tbm_load_module (tbm_bufmgr bufmgr, int fd)
791 {
792     struct dirent **namelist;
793     const char *p = NULL;
794     int n;
795     int ret = 0;
796
797     /* load bufmgr priv from default lib */
798     ret = _tbm_bufmgr_load_module (bufmgr, fd, DEFAULT_LIB);
799
800     /* load bufmgr priv from configured path */
801     if (!ret)
802     {
803         n = scandir (BUFMGR_MODULE_DIR, &namelist, 0, alphasort);
804         if (n < 0)
805             TBM_LOG ("[libtbm:%d] "
806                     "no files : %s\n", getpid(), BUFMGR_MODULE_DIR);
807         else
808         {
809             while(n--)
810             {
811                 if (!ret && strstr (namelist[n]->d_name, PREFIX_LIB))
812                 {
813                     p = strstr (namelist[n]->d_name, SUFFIX_LIB);
814                     if (p != NULL)
815                     {
816                         if (!strcmp (p, SUFFIX_LIB))
817                         {
818                             ret = _tbm_bufmgr_load_module (bufmgr, fd, namelist[n]->d_name);
819                         }
820                     }
821                 }
822                 free(namelist[n]);
823             }
824             free(namelist);
825         }
826     }
827
828     return ret;
829 }
830
831 tbm_bufmgr
832 tbm_bufmgr_init (int fd)
833 {
834     char *env;
835     int fd_flag = 0;
836
837     pthread_mutex_lock (&gLock);
838
839 #ifdef DEBUG
840     env = getenv("GEM_DEBUG");
841     if(env)
842     {
843         bDebug = atoi(env);
844         TBM_LOG ("GEM_DEBUG=%s\n", env);
845     }
846     else
847         bDebug = 0;
848 #endif
849
850     /* initialize buffer manager */
851     if (gBufMgr)
852     {
853         TBM_LOG ("[libtbm:%d] use previous gBufMgr\n", getpid());
854         gBufMgr->ref_count++;
855         TBM_LOG ("[libtbm:%d] bufmgr ref: fd=%d, ref_count:%d\n",
856                     getpid(), gBufMgr->fd, gBufMgr->ref_count);
857         pthread_mutex_unlock (&gLock);
858         return gBufMgr;
859     }
860
861     if (fd < 0)
862     {
863 #ifdef HAVE_X11
864         fd = tbm_bufmgr_get_drm_fd_x11();
865 #elif HAVE_WAYLAND
866         fd = tbm_bufmgr_get_drm_fd_wayland();
867 #endif
868         if (fd < 0)
869         {
870             TBM_LOG ("[libtbm:%d] Fail get drm fd\n", getpid());
871             pthread_mutex_unlock (&gLock);
872             return NULL;
873         }
874         fd_flag = 1;
875     }
876
877     TBM_LOG ("[libtbm:%d] bufmgr init: fd=%d\n", getpid(), fd);
878
879     /* allocate bufmgr */
880     gBufMgr = calloc (1, sizeof(struct _tbm_bufmgr));
881     if (!gBufMgr)
882     {
883         pthread_mutex_unlock (&gLock);
884         return NULL;
885     }
886
887     /* load bufmgr priv from env */
888     if (!_tbm_load_module(gBufMgr, fd))
889     {
890         TBM_LOG ("[libtbm:%d] "
891                 "error : Fail to load bufmgr backend\n",
892                 getpid());
893         free (gBufMgr);
894         gBufMgr = NULL;
895         pthread_mutex_unlock (&gLock);
896         return NULL;
897     }
898
899     gBufMgr->fd_flag = fd_flag;
900     gBufMgr->fd = fd;
901     gBufMgr->ref_count = 1;
902
903     TBM_LOG ("[libtbm:%d] create tizen bufmgr: ref_count:%d\n", getpid(), gBufMgr->ref_count);
904
905     if (pthread_mutex_init (&gBufMgr->lock, NULL) != 0)
906     {
907         gBufMgr->backend->bufmgr_deinit (gBufMgr->backend->priv);
908         tbm_backend_free (gBufMgr->backend);
909         dlclose (gBufMgr->module_data);
910         free (gBufMgr);
911         gBufMgr = NULL;
912         pthread_mutex_unlock (&gLock);
913         return NULL;
914     }
915
916     /* intialize the tizen global status */
917     if (!_tbm_bufmgr_init_state (gBufMgr))
918     {
919         TBM_LOG ("[libtbm:%d] "
920                 "error: Fail to init state\n",
921                 getpid());
922         gBufMgr->backend->bufmgr_deinit (gBufMgr->backend->priv);
923         tbm_backend_free (gBufMgr->backend);
924         pthread_mutex_destroy (&gBufMgr->lock);
925         dlclose (gBufMgr->module_data);
926         free (gBufMgr);
927         gBufMgr = NULL;
928         pthread_mutex_unlock (&gLock);
929         return NULL;
930     }
931
932     /* setup the lock_type */
933     env = getenv ("BUFMGR_LOCK_TYPE");
934     if (env && !strcmp (env, "always"))
935         gBufMgr->lock_type = LOCK_TRY_ALWAYS;
936     else if(env && !strcmp(env, "none"))
937         gBufMgr->lock_type = LOCK_TRY_NEVER;
938     else if(env && !strcmp(env, "once"))
939          gBufMgr->lock_type = LOCK_TRY_ONCE;
940     else
941         gBufMgr->lock_type = LOCK_TRY_ALWAYS;
942
943     DBG ("[libtbm:%d] BUFMGR_LOCK_TYPE=%s\n", getpid(), env?env:"default:once");
944
945     /* setup the map_cache */
946     env = getenv ("BUFMGR_MAP_CACHE");
947     if (env && !strcmp (env, "false"))
948         gBufMgr->use_map_cache = 0;
949     else
950         gBufMgr->use_map_cache = 1;
951     DBG ("[libtbm:%d] BUFMGR_MAP_CACHE=%s\n", getpid(), env?env:"default:true");
952
953     /* intialize bo_list */
954     LIST_INITHEAD (&gBufMgr->bo_list);
955
956     /* intialize surf_list */
957     LIST_INITHEAD (&gBufMgr->surf_list);
958
959     pthread_mutex_unlock (&gLock);
960     return gBufMgr;
961 }
962
963 void
964 tbm_bufmgr_deinit (tbm_bufmgr bufmgr)
965 {
966     TBM_RETURN_IF_FAIL (TBM_BUFMGR_IS_VALID(bufmgr));
967
968     tbm_bo bo = NULL;
969     tbm_bo tmp = NULL;
970
971     tbm_surface_h surf = NULL;
972     tbm_surface_h tmp_surf = NULL;
973
974     pthread_mutex_lock (&gLock);
975
976     bufmgr->ref_count--;
977     if (bufmgr->ref_count > 0)
978     {
979         TBM_LOG ("[libtbm:%d] "
980                 "tizen bufmgr destroy: bufmgr:%p, ref_count:%d\n",
981                 getpid(), bufmgr, bufmgr->ref_count);
982         pthread_mutex_unlock (&gLock);
983         return;
984     }
985
986     /* destroy bo_list */
987     if(!LIST_IS_EMPTY (&bufmgr->bo_list))
988     {
989         LIST_FOR_EACH_ENTRY_SAFE (bo, tmp, &bufmgr->bo_list, item_link)
990         {
991             TBM_LOG ("[libtbm:%d] "
992                     "Un-freed bo(%p, ref:%d) \n",
993                     getpid(), bo, bo->ref_cnt);
994             bo->ref_cnt = 1;
995             tbm_bo_unref(bo);
996         }
997     }
998
999     /* destroy surf_list */
1000     if(!LIST_IS_EMPTY (&bufmgr->surf_list))
1001     {
1002         LIST_FOR_EACH_ENTRY_SAFE (surf, tmp_surf, &bufmgr->surf_list, item_link)
1003         {
1004             TBM_LOG ("[libtbm:%d] "
1005                     "Destroy surf(%p) \n",
1006                     getpid(), surf);
1007             tbm_surface_destroy(surf);
1008         }
1009     }
1010
1011     /* destroy the tizen global status */
1012     _tbm_bufmgr_destroy_state (bufmgr);
1013
1014     /* destroy bufmgr priv */
1015     bufmgr->backend->bufmgr_deinit (bufmgr->backend->priv);
1016     bufmgr->backend->priv = NULL;
1017     tbm_backend_free (bufmgr->backend);
1018     bufmgr->backend = NULL;
1019
1020     pthread_mutex_destroy (&bufmgr->lock);
1021
1022     TBM_LOG ("[libtbm:%d] "
1023             "tizen bufmgr destroy: bufmgr:%p\n",
1024             getpid(), bufmgr);
1025
1026     dlclose (bufmgr->module_data);
1027
1028     if(bufmgr->fd_flag)
1029         close(bufmgr->fd);
1030
1031     free (bufmgr);
1032     bufmgr = NULL;
1033     gBufMgr = NULL;
1034
1035     pthread_mutex_unlock (&gLock);
1036 }
1037
1038 int
1039 tbm_bo_size (tbm_bo bo)
1040 {
1041     TBM_RETURN_VAL_IF_FAIL (_tbm_bo_is_valid(bo), 0);
1042
1043     tbm_bufmgr bufmgr = bo->bufmgr;
1044     int size;
1045
1046     pthread_mutex_lock(&bufmgr->lock);
1047
1048     size = bufmgr->backend->bo_size(bo);
1049
1050     pthread_mutex_unlock(&bufmgr->lock);
1051
1052     return size;
1053 }
1054
1055 tbm_bo
1056 tbm_bo_ref (tbm_bo bo)
1057 {
1058     TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), NULL);
1059
1060     tbm_bufmgr bufmgr = bo->bufmgr;
1061
1062     pthread_mutex_lock(&bufmgr->lock);
1063
1064     _tbm_bo_ref (bo);
1065
1066     pthread_mutex_unlock(&bufmgr->lock);
1067
1068     return bo;
1069 }
1070
1071 void
1072 tbm_bo_unref (tbm_bo bo)
1073 {
1074     TBM_RETURN_IF_FAIL(_tbm_bo_is_valid(bo));
1075
1076     tbm_bufmgr bufmgr = bo->bufmgr;
1077
1078     pthread_mutex_lock (&bufmgr->lock);
1079
1080     _tbm_bo_unref (bo);
1081
1082     pthread_mutex_unlock(&bufmgr->lock);
1083 }
1084
1085 tbm_bo
1086 tbm_bo_alloc (tbm_bufmgr bufmgr, int size, int flags)
1087 {
1088     TBM_RETURN_VAL_IF_FAIL (TBM_BUFMGR_IS_VALID(bufmgr) && (size > 0), NULL);
1089
1090     tbm_bo bo = NULL;
1091     void * bo_priv = NULL;
1092
1093     bo = calloc (1, sizeof(struct _tbm_bo));
1094     if(!bo)
1095         return NULL;
1096
1097     bo->bufmgr = bufmgr;
1098
1099     pthread_mutex_lock (&bufmgr->lock);
1100
1101     bo_priv = bufmgr->backend->bo_alloc (bo, size, flags);
1102     if (!bo_priv)
1103     {
1104         free (bo);
1105         pthread_mutex_unlock (&bufmgr->lock);
1106         return NULL;
1107     }
1108
1109     bo->ref_cnt = 1;
1110     bo->flags = flags;
1111     bo->tgl_key = INITIAL_KEY;
1112     bo->priv = bo_priv;
1113
1114     /* init bo state */
1115     if (!_tbm_bo_init_state (bo, CACHE_OP_CREATE))
1116     {
1117         _tbm_bo_unref (bo);
1118         pthread_mutex_unlock (&bufmgr->lock);
1119         return NULL;
1120     }
1121
1122     LIST_INITHEAD (&bo->user_data_list);
1123
1124     LIST_ADD (&bo->item_link, &bufmgr->bo_list);
1125
1126     pthread_mutex_unlock(&bufmgr->lock);
1127
1128     return bo;
1129 }
1130
1131 tbm_bo
1132 tbm_bo_import (tbm_bufmgr bufmgr, unsigned int key)
1133 {
1134     TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
1135
1136     tbm_bo bo = NULL;
1137     void * bo_priv = NULL;
1138
1139     bo = calloc (1, sizeof(struct _tbm_bo));
1140     if(!bo)
1141         return NULL;
1142
1143     bo->bufmgr = bufmgr;
1144
1145     pthread_mutex_lock (&bufmgr->lock);
1146
1147     bo_priv = bufmgr->backend->bo_import (bo, key);
1148     if (!bo_priv)
1149     {
1150         free (bo);
1151         pthread_mutex_unlock (&bufmgr->lock);
1152         return NULL;
1153     }
1154
1155     bo->ref_cnt = 1;
1156     bo->tgl_key = INITIAL_KEY;
1157     bo->priv = bo_priv;
1158
1159     /* init bo state */
1160     if (!_tbm_bo_init_state (bo, CACHE_OP_IMPORT))
1161     {
1162         _tbm_bo_unref (bo);
1163         pthread_mutex_unlock (&bufmgr->lock);
1164         return NULL;
1165     }
1166
1167     LIST_INITHEAD (&bo->user_data_list);
1168
1169     LIST_ADD (&bo->item_link, &bufmgr->bo_list);
1170
1171     pthread_mutex_unlock (&bufmgr->lock);
1172
1173     return bo;
1174 }
1175
1176 tbm_bo
1177 tbm_bo_import_fd  (tbm_bufmgr bufmgr, tbm_fd fd)
1178 {
1179     tbm_bo bo = NULL;
1180
1181     return bo;
1182 }
1183
1184 unsigned int
1185 tbm_bo_export (tbm_bo bo)
1186 {
1187     TBM_RETURN_VAL_IF_FAIL (_tbm_bo_is_valid(bo), 0);
1188
1189     tbm_bufmgr bufmgr;
1190     int ret;
1191
1192     bufmgr = bo->bufmgr;
1193
1194     pthread_mutex_lock (&bufmgr->lock);
1195     ret = bufmgr->backend->bo_export (bo);
1196     pthread_mutex_unlock (&bufmgr->lock);
1197
1198     return ret;
1199 }
1200
1201 tbm_fd
1202 tbm_bo_export_fd (tbm_bo bo)
1203 {
1204     tbm_fd fd = 0;
1205
1206     return fd;
1207 }
1208
1209
1210 tbm_bo_handle
1211 tbm_bo_get_handle (tbm_bo bo, int device)
1212 {
1213     TBM_RETURN_VAL_IF_FAIL (_tbm_bo_is_valid(bo), (tbm_bo_handle)0);
1214
1215     tbm_bufmgr bufmgr;
1216     tbm_bo_handle bo_handle;
1217
1218     bufmgr = bo->bufmgr;
1219
1220     pthread_mutex_lock (&bufmgr->lock);
1221     bo_handle = bufmgr->backend->bo_get_handle (bo, device);
1222     pthread_mutex_unlock (&bufmgr->lock);
1223
1224     return bo_handle;
1225 }
1226
1227 tbm_bo_handle
1228 tbm_bo_map (tbm_bo bo, int device, int opt)
1229 {
1230     TBM_RETURN_VAL_IF_FAIL (_tbm_bo_is_valid(bo), (tbm_bo_handle)0);
1231
1232     tbm_bufmgr bufmgr;
1233     tbm_bo_handle bo_handle;
1234
1235     bufmgr = bo->bufmgr;
1236
1237     pthread_mutex_lock (&bufmgr->lock);
1238
1239     bo_handle = bufmgr->backend->bo_get_handle (bo, device);
1240
1241     if (!_tbm_bo_lock (bo, device, opt))
1242     {
1243         TBM_LOG ("[libtbm:%d] "
1244                         "error %s:%d fail to lock bo:%p)\n",
1245                         getpid(), __FUNCTION__, __LINE__, bo);
1246
1247         pthread_mutex_unlock (&bufmgr->lock);
1248         return (tbm_bo_handle)NULL;
1249     }
1250
1251     bo_handle = bufmgr->backend->bo_map (bo, device, opt);
1252     if (bo_handle.ptr == NULL)
1253     {
1254         TBM_LOG ("[libtbm:%d] "
1255                         "error %s:%d fail to map bo:%p\n",
1256                         getpid(), __FUNCTION__, __LINE__, bo);
1257
1258         _tbm_bo_unlock(bo);
1259         pthread_mutex_unlock (&bufmgr->lock);
1260         return (tbm_bo_handle)NULL;
1261     }
1262
1263     if (bufmgr->use_map_cache == 1 && bo->map_cnt == 0)
1264         _tbm_bo_set_state (bo, device, opt);
1265
1266     /* increase the map_count */
1267     bo->map_cnt++;
1268
1269     pthread_mutex_unlock (&bufmgr->lock);
1270
1271     return bo_handle;
1272 }
1273
1274 int
1275 tbm_bo_unmap (tbm_bo bo)
1276 {
1277     TBM_RETURN_VAL_IF_FAIL (_tbm_bo_is_valid(bo), 0);
1278
1279     tbm_bufmgr bufmgr;
1280     int ret;
1281
1282     bufmgr = bo->bufmgr;
1283
1284     pthread_mutex_lock (&bufmgr->lock);
1285
1286     ret = bufmgr->backend->bo_unmap (bo);
1287     if (!ret)
1288     {
1289         pthread_mutex_unlock (&bufmgr->lock);
1290         return ret;
1291     }
1292
1293     /* decrease the map_count */
1294     bo->map_cnt--;
1295
1296     if (bo->map_cnt == 0)
1297         _tbm_bo_save_state (bo);
1298
1299      _tbm_bo_unlock (bo);
1300
1301     pthread_mutex_unlock (&bufmgr->lock);
1302
1303     return ret;
1304 }
1305
1306 int
1307 tbm_bo_swap (tbm_bo bo1, tbm_bo bo2)
1308 {
1309     TBM_RETURN_VAL_IF_FAIL (_tbm_bo_is_valid(bo1), 0);
1310     TBM_RETURN_VAL_IF_FAIL (_tbm_bo_is_valid(bo2), 0);
1311
1312     void* temp;
1313     unsigned int tmp_key;
1314
1315     if (bo1->bufmgr->backend->bo_size (bo1) != bo2->bufmgr->backend->bo_size (bo2))
1316         return 0;
1317
1318     pthread_mutex_lock (&bo1->bufmgr->lock);
1319
1320     tmp_key = bo1->tgl_key;
1321     bo1->tgl_key = bo2->tgl_key;
1322     bo2->tgl_key = tmp_key;
1323
1324     temp = bo1->priv;
1325     bo1->priv = bo2->priv;
1326     bo2->priv = temp;
1327
1328     pthread_mutex_unlock (&bo1->bufmgr->lock);
1329
1330     return 1;
1331 }
1332
1333 int
1334 tbm_bo_locked (tbm_bo bo)
1335 {
1336     TBM_RETURN_VAL_IF_FAIL (_tbm_bo_is_valid(bo), 0);
1337
1338     tbm_bufmgr bufmgr;
1339
1340     bufmgr = bo->bufmgr;
1341
1342     if (bufmgr->lock_type == LOCK_TRY_NEVER)
1343         return 0;
1344
1345     pthread_mutex_lock (&bufmgr->lock);
1346
1347     if (bo->lock_cnt > 0)
1348     {
1349         pthread_mutex_unlock (&bufmgr->lock);
1350         return 1;
1351     }
1352
1353     pthread_mutex_unlock (&bufmgr->lock);
1354
1355     return 0;
1356 }
1357
1358
1359 int
1360 tbm_bo_add_user_data (tbm_bo bo, unsigned long key, tbm_data_free data_free_func)
1361 {
1362     TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1363
1364     tbm_user_data *data;
1365
1366     /* check if the data according to the key exist if so, return false.*/
1367     data = _user_data_lookup (&bo->user_data_list, key);
1368     if (data)
1369     {
1370         TBM_LOG ("[libtbm:%d] "
1371                 "waring: %s:%d user data already exist. key:%ld\n",
1372                 getpid(), __FUNCTION__, __LINE__, key);
1373         return 0;
1374     }
1375
1376     data = _user_data_create (key, data_free_func);
1377     if (!data)
1378         return 0;
1379
1380     LIST_ADD (&data->item_link, &bo->user_data_list);
1381
1382     return 1;
1383 }
1384
1385 int
1386 tbm_bo_set_user_data (tbm_bo bo, unsigned long key, void* data)
1387 {
1388     TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1389
1390     tbm_user_data *old_data;
1391
1392     if (LIST_IS_EMPTY (&bo->user_data_list))
1393         return 0;
1394
1395     old_data = _user_data_lookup (&bo->user_data_list, key);
1396     if (!old_data)
1397         return 0;
1398
1399     if (old_data->data && old_data->free_func)
1400         old_data->free_func(old_data->data);
1401
1402     old_data->data = data;
1403
1404     return 1;
1405 }
1406
1407 int
1408 tbm_bo_get_user_data (tbm_bo bo, unsigned long key, void** data)
1409 {
1410     TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1411
1412     tbm_user_data* old_data;
1413
1414     if (!data || LIST_IS_EMPTY (&bo->user_data_list))
1415         return 0;
1416
1417     old_data = _user_data_lookup (&bo->user_data_list, key);
1418     if (!old_data)
1419     {
1420         *data = NULL;
1421         return 0;
1422     }
1423
1424     *data = old_data->data;
1425
1426     return 1;
1427 }
1428
1429 int
1430 tbm_bo_delete_user_data (tbm_bo bo, unsigned long key)
1431 {
1432     TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1433
1434     tbm_user_data *old_data = (void *)0;
1435
1436     if (LIST_IS_EMPTY (&bo->user_data_list))
1437         return 0;
1438
1439     old_data = _user_data_lookup (&bo->user_data_list, key);
1440     if (!old_data)
1441         return 0;
1442
1443     _user_data_delete (old_data);
1444
1445     return 1;
1446 }
1447