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