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