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