fix segmentation fault
[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     LIST_DEL (&bufmgr->link);
963
964     free (bufmgr);
965     bufmgr = NULL;
966 }
967
968
969 int
970 tbm_bo_size (tbm_bo bo)
971 {
972     TBM_RETURN_VAL_IF_FAIL (TBM_BO_IS_VALID(bo), 0);
973
974     tbm_bufmgr bufmgr = bo->bufmgr;
975     int size;
976
977     pthread_mutex_lock(&bufmgr->lock);
978     size = bufmgr->backend->bo_size(bo);
979     pthread_mutex_unlock(&bufmgr->lock);
980
981     return size;
982 }
983
984 tbm_bo
985 tbm_bo_ref (tbm_bo bo)
986 {
987     TBM_RETURN_VAL_IF_FAIL(TBM_BO_IS_VALID(bo), NULL);
988
989     tbm_bufmgr bufmgr = bo->bufmgr;
990
991     pthread_mutex_lock(&bufmgr->lock);
992
993     _tbm_bo_ref (bo);
994
995     pthread_mutex_unlock(&bufmgr->lock);
996
997     return bo;
998 }
999
1000 void
1001 tbm_bo_unref (tbm_bo bo)
1002 {
1003     TBM_RETURN_IF_FAIL(TBM_BO_IS_VALID(bo));
1004
1005     tbm_bufmgr bufmgr = bo->bufmgr;
1006
1007     pthread_mutex_lock (&bufmgr->lock);
1008
1009     _tbm_bo_unref (bo);
1010
1011     pthread_mutex_unlock(&bufmgr->lock);
1012 }
1013
1014 tbm_bo
1015 tbm_bo_alloc (tbm_bufmgr bufmgr, int size, int flags)
1016 {
1017     TBM_RETURN_VAL_IF_FAIL (TBM_BUFMGR_IS_VALID(bufmgr) && (size > 0), NULL);
1018
1019     tbm_bo bo = NULL;
1020     void * bo_priv = NULL;
1021
1022     bo = calloc (1, sizeof(struct _tbm_bo));
1023     if(!bo)
1024         return NULL;
1025
1026     bo->bufmgr = bufmgr;
1027
1028     pthread_mutex_lock (&bufmgr->lock);
1029
1030     bo_priv = bufmgr->backend->bo_alloc (bo, size, flags);
1031     if (!bo_priv)
1032     {
1033         free (bo);
1034         pthread_mutex_unlock (&bufmgr->lock);
1035         return NULL;
1036     }
1037
1038     bo->ref_cnt = 1;
1039     bo->flags = flags;
1040     bo->tgl_key = INITIAL_KEY;
1041     bo->priv = bo_priv;
1042
1043     /* init bo state */
1044     if (!_tbm_bo_init_state (bo, CACHE_OP_CREATE))
1045     {
1046         _tbm_bo_unref (bo);
1047         pthread_mutex_unlock (&bufmgr->lock);
1048         return NULL;
1049     }
1050
1051     LIST_INITHEAD (&bo->user_data_list);
1052
1053     LIST_ADD (&bo->item_link, &bufmgr->bo_list);
1054
1055     pthread_mutex_unlock(&bufmgr->lock);
1056
1057     return bo;
1058 }
1059
1060 tbm_bo
1061 tbm_bo_import (tbm_bufmgr bufmgr, unsigned int key)
1062 {
1063     TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
1064
1065     tbm_bo bo = NULL;
1066     void * bo_priv = NULL;
1067
1068     bo = calloc (1, sizeof(struct _tbm_bo));
1069     if(!bo)
1070         return NULL;
1071
1072     bo->bufmgr = bufmgr;
1073
1074     pthread_mutex_lock (&bufmgr->lock);
1075
1076     bo_priv = bufmgr->backend->bo_import (bo, key);
1077     if (!bo_priv)
1078     {
1079         free (bo);
1080         pthread_mutex_unlock (&bufmgr->lock);
1081         return NULL;
1082     }
1083
1084     bo->ref_cnt = 1;
1085     bo->tgl_key = INITIAL_KEY;
1086     bo->priv = bo_priv;
1087
1088     /* init bo state */
1089     if (!_tbm_bo_init_state (bo, CACHE_OP_IMPORT))
1090     {
1091         _tbm_bo_unref (bo);
1092         pthread_mutex_unlock (&bufmgr->lock);
1093         return NULL;
1094     }
1095
1096     LIST_INITHEAD (&bo->user_data_list);
1097
1098     LIST_ADD (&bo->item_link, &bufmgr->bo_list);
1099
1100     pthread_mutex_unlock (&bufmgr->lock);
1101
1102     return bo;
1103 }
1104
1105 unsigned int
1106 tbm_bo_export (tbm_bo bo)
1107 {
1108     TBM_RETURN_VAL_IF_FAIL (TBM_BO_IS_VALID(bo), 0);
1109
1110     tbm_bufmgr bufmgr;
1111     int ret;
1112
1113     bufmgr = bo->bufmgr;
1114
1115     pthread_mutex_lock (&bufmgr->lock);
1116     ret = bufmgr->backend->bo_export (bo);
1117     pthread_mutex_unlock (&bufmgr->lock);
1118
1119     return ret;
1120 }
1121
1122 tbm_bo_handle
1123 tbm_bo_get_handle (tbm_bo bo, int device)
1124 {
1125     TBM_RETURN_VAL_IF_FAIL (TBM_BO_IS_VALID(bo), (tbm_bo_handle)0);
1126
1127     tbm_bufmgr bufmgr;
1128     tbm_bo_handle bo_handle;
1129
1130     bufmgr = bo->bufmgr;
1131
1132     pthread_mutex_lock (&bufmgr->lock);
1133     bo_handle = bufmgr->backend->bo_get_handle (bo, device);
1134     pthread_mutex_unlock (&bufmgr->lock);
1135
1136     return bo_handle;
1137 }
1138
1139 tbm_bo_handle
1140 tbm_bo_map (tbm_bo bo, int device, int opt)
1141 {
1142     TBM_RETURN_VAL_IF_FAIL (TBM_BO_IS_VALID(bo), (tbm_bo_handle)0);
1143
1144     tbm_bufmgr bufmgr;
1145     tbm_bo_handle bo_handle;
1146
1147     bufmgr = bo->bufmgr;
1148
1149     pthread_mutex_lock (&bufmgr->lock);
1150
1151     _tbm_bo_lock (bo);
1152     bo_handle = bufmgr->backend->bo_map (bo, device, opt);
1153
1154     /* increase the ref_count */
1155 //    _tbm_bo_ref (bo);
1156
1157     if (bufmgr->use_map_cache == 1 && bo->map_cnt == 0)
1158         _tbm_bo_set_state (bo, device, opt);
1159
1160     /* increase the map_count */
1161     bo->map_cnt++;
1162
1163     pthread_mutex_unlock (&bufmgr->lock);
1164
1165     return bo_handle;
1166 }
1167
1168 int
1169 tbm_bo_unmap (tbm_bo bo)
1170 {
1171     TBM_RETURN_VAL_IF_FAIL (TBM_BO_IS_VALID(bo), 0);
1172
1173     tbm_bufmgr bufmgr;
1174     int ret;
1175
1176     bufmgr = bo->bufmgr;
1177
1178     pthread_mutex_lock (&bufmgr->lock);
1179
1180     ret = bufmgr->backend->bo_unmap (bo);
1181
1182     /* decrease the map_count */
1183     bo->map_cnt--;
1184
1185     if (bo->map_cnt == 0)
1186         _tbm_bo_save_state (bo);
1187
1188      _tbm_bo_unlock (bo);
1189
1190     /* decrease the ref_count */
1191 //    _tbm_bo_unref (bo);
1192
1193     pthread_mutex_unlock (&bufmgr->lock);
1194
1195     return ret;
1196 }
1197
1198 int
1199 tbm_bo_swap (tbm_bo bo1, tbm_bo bo2)
1200 {
1201     TBM_RETURN_VAL_IF_FAIL (TBM_BO_IS_VALID(bo1), 0);
1202     TBM_RETURN_VAL_IF_FAIL (TBM_BO_IS_VALID(bo2), 0);
1203
1204     void* temp;
1205     unsigned int tmp_key;
1206
1207     if (bo1->bufmgr->backend->bo_size (bo1) != bo2->bufmgr->backend->bo_size (bo2))
1208         return 0;
1209
1210     pthread_mutex_lock (&bo1->bufmgr->lock);
1211
1212     tmp_key = bo1->tgl_key;
1213     bo1->tgl_key = bo2->tgl_key;
1214     bo2->tgl_key = tmp_key;
1215
1216     temp = bo1->priv;
1217     bo1->priv = bo2->priv;
1218     bo2->priv = temp;
1219
1220     pthread_mutex_unlock (&bo1->bufmgr->lock);
1221
1222     return 1;
1223 }
1224
1225 int
1226 tbm_bo_locked (tbm_bo bo)
1227 {
1228     TBM_RETURN_VAL_IF_FAIL (TBM_BO_IS_VALID(bo), 0);
1229
1230     tbm_bufmgr bufmgr;
1231
1232     bufmgr = bo->bufmgr;
1233
1234     if (bufmgr->lock_type == LOCK_TRY_NEVER)
1235         return 0;
1236
1237     pthread_mutex_lock (&bufmgr->lock);
1238
1239     if (bo->lock_cnt > 0)
1240     {
1241         pthread_mutex_unlock (&bufmgr->lock);
1242         return 1;
1243     }
1244
1245     pthread_mutex_unlock (&bufmgr->lock);
1246
1247     return 0;
1248 }
1249
1250
1251 int
1252 tbm_bo_add_user_data (tbm_bo bo, unsigned long key, tbm_data_free data_free_func)
1253 {
1254     TBM_RETURN_VAL_IF_FAIL(TBM_BO_IS_VALID(bo), 0);
1255
1256     tbm_user_data *data;
1257
1258     /* check if the data according to the key exist if so, return false.*/
1259     data = _user_data_lookup (&bo->user_data_list, key);
1260     if (data)
1261     {
1262         fprintf (stderr, "[libtbm:%d] "
1263                 "waring: %s:%d user data already exist. key:%ld\n",
1264                 getpid(), __FUNCTION__, __LINE__, key);
1265         return 0;
1266     }
1267
1268     data = _user_data_create (key, data_free_func);
1269     if (!data)
1270         return 0;
1271
1272     LIST_ADD (&data->item_link, &bo->user_data_list);
1273
1274     return 1;
1275 }
1276
1277 int
1278 tbm_bo_set_user_data (tbm_bo bo, unsigned long key, void* data)
1279 {
1280     TBM_RETURN_VAL_IF_FAIL(TBM_BO_IS_VALID(bo), 0);
1281
1282     tbm_user_data *old_data;
1283
1284     if (LIST_IS_EMPTY (&bo->user_data_list))
1285         return 0;
1286
1287     old_data = _user_data_lookup (&bo->user_data_list, key);
1288     if (!old_data)
1289         return 0;
1290
1291     if (old_data->data && old_data->free_func)
1292         old_data->free_func(old_data->data);
1293
1294     old_data->data = data;
1295
1296     return 1;
1297 }
1298
1299 int
1300 tbm_bo_get_user_data (tbm_bo bo, unsigned long key, void** data)
1301 {
1302     TBM_RETURN_VAL_IF_FAIL(TBM_BO_IS_VALID(bo), 0);
1303
1304     tbm_user_data* old_data;
1305
1306     if (!data || LIST_IS_EMPTY (&bo->user_data_list))
1307         return 0;
1308
1309     old_data = _user_data_lookup (&bo->user_data_list, key);
1310     if (!old_data)
1311     {
1312         *data = NULL;
1313         return 0;
1314     }
1315
1316     *data = old_data->data;
1317
1318     return 1;
1319 }
1320
1321 int
1322 tbm_bo_delete_user_data (tbm_bo bo, unsigned long key)
1323 {
1324     TBM_RETURN_VAL_IF_FAIL(TBM_BO_IS_VALID(bo), 0);
1325
1326     tbm_user_data *old_data = (void *)0;
1327
1328     if (LIST_IS_EMPTY (&bo->user_data_list))
1329         return 0;
1330
1331     old_data = _user_data_lookup (&bo->user_data_list, key);
1332     if (!old_data)
1333         return 0;
1334
1335     _user_data_delete (old_data);
1336
1337     return 1;
1338 }
1339
1340