Support logging dlog
[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 "list.h"
38
39 #ifdef DEBUG
40 int bDebug;
41 #endif
42
43 #ifdef HAVE_DLOG
44 int bDlog;
45 #endif
46
47 #define PREFIX_LIB    "libtbm_"
48 #define SUFFIX_LIB    ".so"
49 #define DEFAULT_LIB   PREFIX_LIB"default"SUFFIX_LIB
50
51 /* values to indicate unspecified fields in XF86ModReqInfo. */
52 #define MAJOR_UNSPEC        0xFF
53 #define MINOR_UNSPEC        0xFF
54 #define PATCH_UNSPEC        0xFFFF
55 #define ABI_VERS_UNSPEC   0xFFFFFFFF
56
57 #define MODULE_VERSION_NUMERIC(maj, min, patch) \
58                         ((((maj) & 0xFF) << 24) | (((min) & 0xFF) << 16) | (patch & 0xFFFF))
59 #define GET_MODULE_MAJOR_VERSION(vers)    (((vers) >> 24) & 0xFF)
60 #define GET_MODULE_MINOR_VERSION(vers)    (((vers) >> 16) & 0xFF)
61 #define GET_MODULE_PATCHLEVEL(vers)    ((vers) & 0xFFFF)
62
63 enum {
64         LOCK_TRY_ONCE,
65         LOCK_TRY_ALWAYS,
66         LOCK_TRY_NEVER
67 };
68
69 pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
70 tbm_bufmgr gBufMgr;
71
72 static __thread tbm_error_e tbm_last_error = TBM_ERROR_NONE;
73
74 static void
75 _tbm_set_last_result(tbm_error_e err)
76 {
77         tbm_last_error = err;
78 }
79
80 static void
81 _tbm_util_get_appname_brief(char *brief)
82 {
83         char delim[] = "/";
84         char *token = NULL;
85         char temp[255] = {0,};
86         char *saveptr = NULL;
87
88         token = strtok_r(brief, delim, &saveptr);
89
90         while (token != NULL) {
91                 memset(temp, 0x00, 255 * sizeof(char));
92                 strncpy(temp, token, 254 * sizeof(char));
93                 token = strtok_r(NULL, delim, &saveptr);
94         }
95
96         snprintf(brief, sizeof(temp), "%s", temp);
97 }
98
99 static void
100 _tbm_util_get_appname_from_pid(long pid, char *str)
101 {
102         FILE *fp;
103         int len;
104         long app_pid = pid;
105         char fn_cmdline[255] = {0,};
106         char cmdline[255] = {0,};
107
108         snprintf(fn_cmdline, sizeof(fn_cmdline), "/proc/%ld/cmdline", app_pid);
109
110         fp = fopen(fn_cmdline, "r");
111         if (fp == 0) {
112                 fprintf(stderr, "cannot file open /proc/%ld/cmdline", app_pid);
113                 return;
114         }
115
116         if (!fgets(cmdline, 255, fp)) {
117                 fprintf(stderr, "fail to get appname for pid(%ld)\n", app_pid);
118                 fclose(fp);
119                 return;
120         }
121         fclose(fp);
122
123         len = strlen(cmdline);
124         if (len < 1)
125                 memset(cmdline, 0x00, 255);
126         else
127                 cmdline[len] = 0;
128
129         snprintf(str, sizeof(cmdline), "%s", cmdline);
130 }
131
132 tbm_user_data
133 *user_data_lookup(struct list_head *user_data_list, unsigned long key)
134 {
135         tbm_user_data *user_data = NULL;
136         tbm_user_data *old_data = NULL, *tmp = NULL;
137
138         if (!LIST_IS_EMPTY(user_data_list)) {
139                 LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp, user_data_list, item_link) {
140                         if (old_data->key == key) {
141                                 user_data = old_data;
142                                 return user_data;
143                         }
144                 }
145         }
146
147         return user_data;
148 }
149
150 tbm_user_data
151 *user_data_create(unsigned long key, tbm_data_free data_free_func)
152 {
153         tbm_user_data *user_data = NULL;
154
155         user_data = calloc(1, sizeof(tbm_user_data));
156         if (!user_data)
157                 return NULL;
158
159         user_data->key = key;
160         user_data->free_func = data_free_func;
161         user_data->data = (void *)0;
162
163         return user_data;
164 }
165
166 void
167 user_data_delete(tbm_user_data *user_data)
168 {
169         if (user_data->data && user_data->free_func)
170                 user_data->free_func(user_data->data);
171
172         LIST_DEL(&user_data->item_link);
173
174         free(user_data);
175 }
176
177 static int
178 _bo_lock(tbm_bo bo, int device, int opt)
179 {
180         tbm_bufmgr bufmgr = bo->bufmgr;
181         int ret = 0;
182
183         if (bufmgr->backend->bo_lock) {
184                 ret = bufmgr->backend->bo_lock(bo, device, opt);
185         } else {
186                 ret = 1;
187         }
188
189         return ret;
190 }
191
192 static void
193 _bo_unlock(tbm_bo bo)
194 {
195         tbm_bufmgr bufmgr = bo->bufmgr;
196
197         if (bufmgr->backend->bo_unlock) {
198                 bufmgr->backend->bo_unlock(bo);
199         }
200 }
201
202 static int
203 _tbm_bo_lock(tbm_bo bo, int device, int opt)
204 {
205         tbm_bufmgr bufmgr = NULL;
206         int old;
207         int ret = 0;
208
209         if (!bo)
210                 return 0;
211
212         bufmgr = bo->bufmgr;
213
214         /* do not try to lock the bo */
215         if (bufmgr->lock_type == LOCK_TRY_NEVER)
216                 return 1;
217
218         if (bo->lock_cnt < 0) {
219                 TBM_LOG_E("error bo:%p LOCK_CNT=%d\n",
220                         bo, bo->lock_cnt);
221         }
222
223         old = bo->lock_cnt;
224         if (bufmgr->lock_type == LOCK_TRY_ONCE) {
225                 if (bo->lock_cnt == 0) {
226                         pthread_mutex_unlock(&bufmgr->lock);
227                         ret = _bo_lock(bo, device, opt);
228                         pthread_mutex_lock(&bufmgr->lock);
229                         if (ret)
230                                 bo->lock_cnt++;
231                 } else
232                         ret = 1;
233         } else if (bufmgr->lock_type == LOCK_TRY_ALWAYS) {
234                 pthread_mutex_unlock(&bufmgr->lock);
235                 ret = _bo_lock(bo, device, opt);
236                 pthread_mutex_lock(&bufmgr->lock);
237                 if (ret)
238                         bo->lock_cnt++;
239         } else {
240                 TBM_LOG_E("error bo:%p lock_type is wrong.\n",
241                         bo);
242         }
243
244         DBG_LOCK(">> LOCK bo:%p(%d->%d)\n",
245                  bo, old, bo->lock_cnt);
246
247         return ret;
248 }
249
250 static void
251 _tbm_bo_unlock(tbm_bo bo)
252 {
253         tbm_bufmgr bufmgr = NULL;
254
255         int old;
256
257         if (!bo)
258                 return;
259
260         bufmgr = bo->bufmgr;
261
262         /* do not try to unlock the bo */
263         if (bufmgr->lock_type == LOCK_TRY_NEVER)
264                 return;
265
266         old = bo->lock_cnt;
267         if (bufmgr->lock_type == LOCK_TRY_ONCE) {
268                 if (bo->lock_cnt > 0) {
269                         bo->lock_cnt--;
270                         if (bo->lock_cnt == 0)
271                                 _bo_unlock(bo);
272                 }
273         } else if (bufmgr->lock_type == LOCK_TRY_ALWAYS) {
274                 if (bo->lock_cnt > 0) {
275                         bo->lock_cnt--;
276                         _bo_unlock(bo);
277                 }
278         } else {
279                 TBM_LOG_E("error bo:%p lock_type is wrong.\n",
280                         bo);
281         }
282
283         if (bo->lock_cnt < 0)
284                 bo->lock_cnt = 0;
285
286         DBG_LOCK(">> UNLOCK bo:%p(%d->%d)\n",
287                  bo, old, bo->lock_cnt);
288 }
289
290 static int
291 _tbm_bo_is_valid(tbm_bo bo)
292 {
293         tbm_bo old_data = NULL, tmp = NULL;
294
295         if (bo == NULL)
296                 return 0;
297
298         if (!LIST_IS_EMPTY(&gBufMgr->bo_list)) {
299                 LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp, &gBufMgr->bo_list, item_link) {
300                         if (old_data == bo)
301                                 return 1;
302                 }
303
304         }
305         return 0;
306 }
307
308 static void
309 _tbm_bo_ref(tbm_bo bo)
310 {
311         bo->ref_cnt++;
312 }
313
314 static void
315 _tbm_bo_unref(tbm_bo bo)
316 {
317         tbm_bufmgr bufmgr = bo->bufmgr;
318         tbm_user_data *old_data = NULL, *tmp = NULL;
319
320         if (bo->ref_cnt <= 0)
321                 return;
322
323         bo->ref_cnt--;
324         if (bo->ref_cnt == 0) {
325                 /* destory the user_data_list */
326                 if (!LIST_IS_EMPTY(&bo->user_data_list)) {
327                         LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp, &bo->user_data_list, item_link) {
328                                 DBG("free user_data\n");
329                                 user_data_delete(old_data);
330                         }
331                 }
332
333                 if (bo->lock_cnt > 0) {
334                         TBM_LOG_E("error lock_cnt:%d\n",
335                                 bo->lock_cnt);
336                         _bo_unlock(bo);
337                 }
338
339                 /* call the bo_free */
340                 bufmgr->backend->bo_free(bo);
341                 bo->priv = NULL;
342
343                 LIST_DEL(&bo->item_link);
344                 free(bo);
345                 bo = NULL;
346         }
347
348 }
349
350 static int
351 _check_version(TBMModuleVersionInfo *data)
352 {
353         int abimaj, abimin;
354         int vermaj, vermin;
355
356         abimaj = GET_ABI_MAJOR(data->abiversion);
357         abimin = GET_ABI_MINOR(data->abiversion);
358
359         DBG("TBM module %s: vendor=\"%s\" ABI=%d,%d\n",
360             data->modname ? data->modname : "UNKNOWN!",
361             data->vendor ? data->vendor : "UNKNOWN!", abimaj, abimin);
362
363         vermaj = GET_ABI_MAJOR(TBM_ABI_VERSION);
364         vermin = GET_ABI_MINOR(TBM_ABI_VERSION);
365
366         DBG("TBM ABI version %d.%d\n",
367             vermaj, vermin);
368
369         if (abimaj != vermaj) {
370                 TBM_LOG_E("TBM module ABI major ver(%d) doesn't match the TBM's ver(%d)\n",
371                         abimaj, vermaj);
372                 return 0;
373         } else if (abimin > vermin) {
374                 TBM_LOG_E("TBM module ABI minor ver(%d) is newer than the TBM's ver(%d)\n",
375                         abimin, vermin);
376                 return 0;
377         }
378         return 1;
379 }
380
381 static int
382 _tbm_bufmgr_load_module(tbm_bufmgr bufmgr, int fd, const char *file)
383 {
384         char path[PATH_MAX] = { 0, };
385         TBMModuleData *initdata = NULL;
386         void *module_data;
387
388         snprintf(path, sizeof(path), BUFMGR_MODULE_DIR "/%s", file);
389
390         module_data = dlopen(path, RTLD_LAZY);
391         if (!module_data) {
392                 TBM_LOG_E("failed to load module: %s(%s)\n",
393                         dlerror(), file);
394                 return 0;
395         }
396
397         initdata = dlsym(module_data, "tbmModuleData");
398         if (initdata) {
399                 ModuleInitProc init;
400                 TBMModuleVersionInfo *vers;
401
402                 vers = initdata->vers;
403                 init = initdata->init;
404
405                 if (vers) {
406                         if (!_check_version(vers)) {
407                                 dlclose(module_data);
408                                 return 0;
409                         }
410                 } else {
411                         TBM_LOG_E("Error: module does not supply version information.\n");
412
413                         dlclose(module_data);
414                         return 0;
415                 }
416
417                 if (init) {
418                         if (!init(bufmgr, fd)) {
419                                 TBM_LOG_E("Fail to init module(%s)\n",
420                                         file);
421                                 dlclose(module_data);
422                                 return 0;
423                         }
424
425                         if (!bufmgr->backend || !bufmgr->backend->priv) {
426                                 TBM_LOG_E("Error: module(%s) wrong operation. Check backend or backend's priv.\n",
427                                         file);
428                                 dlclose(module_data);
429                                 return 0;
430                         }
431                 } else {
432                         TBM_LOG_E("Error: module does not supply init symbol.\n");
433                         dlclose(module_data);
434                         return 0;
435                 }
436         } else {
437                 TBM_LOG_E("Error: module does not have data object.\n");
438                 dlclose(module_data);
439                 return 0;
440         }
441
442         bufmgr->module_data = module_data;
443
444         DBG("Success to load module(%s)\n",
445             file);
446
447         return 1;
448 }
449
450 static int
451 _tbm_load_module(tbm_bufmgr bufmgr, int fd)
452 {
453         struct dirent **namelist;
454         const char *p = NULL;
455         int n;
456         int ret = 0;
457
458         /* load bufmgr priv from default lib */
459         ret = _tbm_bufmgr_load_module(bufmgr, fd, DEFAULT_LIB);
460
461         /* load bufmgr priv from configured path */
462         if (!ret) {
463                 n = scandir(BUFMGR_MODULE_DIR, &namelist, 0, alphasort);
464                 if (n < 0) {
465                         TBM_LOG_E("no files : %s\n",
466                                 BUFMGR_MODULE_DIR);
467                 } else {
468                         while (n--) {
469                                 if (!ret && strstr(namelist[n]->d_name, PREFIX_LIB)) {
470                                         p = strstr(namelist[n]->d_name, SUFFIX_LIB);
471                                         if (p && !strcmp(p, SUFFIX_LIB))
472                                                 ret = _tbm_bufmgr_load_module(bufmgr, fd, namelist[n]->d_name);
473                                 }
474                                 free(namelist[n]);
475                         }
476                         free(namelist);
477                 }
478         }
479
480         return ret;
481 }
482
483 tbm_bufmgr
484 tbm_bufmgr_init(int fd)
485 {
486         char *env;
487
488         pthread_mutex_lock(&gLock);
489
490 #ifdef HAVE_DLOG
491         env = getenv("TBM_DLOG");
492         if (env) {
493                 bDlog = atoi(env);
494                 TBM_LOG_D("TBM_DLOG=%s\n", env);
495         } else {
496                 bDlog = 0;
497         }
498 #endif
499
500 #ifdef DEBUG
501         env = getenv("TBM_DEBUG");
502         if (env) {
503                 bDebug = atoi(env);
504                 TBM_LOG_D("TBM_DEBUG=%s\n", env);
505         } else {
506                 bDebug = 0;
507         }
508 #endif
509
510         /* initialize buffer manager */
511         if (gBufMgr) {
512                 gBufMgr->ref_count++;
513
514                 DBG("bufmgr:%p ref: fd=%d, ref_count:%d\n",
515                     gBufMgr, gBufMgr->fd, gBufMgr->ref_count);
516                 pthread_mutex_unlock(&gLock);
517                 return gBufMgr;
518         }
519
520         DBG("bufmgr init\n");
521
522         /* allocate bufmgr */
523         gBufMgr = calloc(1, sizeof(struct _tbm_bufmgr));
524         if (!gBufMgr) {
525                 _tbm_set_last_result(TBM_BO_ERROR_HEAP_ALLOC_FAILED);
526                 pthread_mutex_unlock(&gLock);
527                 return NULL;
528         }
529
530         gBufMgr->fd = fd;
531
532         /* load bufmgr priv from env */
533         if (!_tbm_load_module(gBufMgr, gBufMgr->fd)) {
534                 _tbm_set_last_result(TBM_BO_ERROR_LOAD_MODULE_FAILED);
535                 TBM_LOG_E("error : Fail to load bufmgr backend\n");
536
537                 free(gBufMgr);
538                 gBufMgr = NULL;
539                 pthread_mutex_unlock(&gLock);
540                 return NULL;
541         }
542
543         /* log for tbm backend_flag */
544         DBG("backend flag:%x:", gBufMgr->backend->flags);
545         DBG("\n");
546
547         gBufMgr->ref_count = 1;
548
549         DBG("create tizen bufmgr:%p ref_count:%d\n",
550             gBufMgr, gBufMgr->ref_count);
551
552         if (pthread_mutex_init(&gBufMgr->lock, NULL) != 0) {
553                 _tbm_set_last_result(TBM_BO_ERROR_THREAD_INIT_FAILED);
554                 gBufMgr->backend->bufmgr_deinit(gBufMgr->backend->priv);
555                 tbm_backend_free(gBufMgr->backend);
556                 dlclose(gBufMgr->module_data);
557                 free(gBufMgr);
558                 gBufMgr = NULL;
559                 pthread_mutex_unlock(&gLock);
560                 return NULL;
561         }
562
563         /* setup the lock_type */
564         env = getenv("BUFMGR_LOCK_TYPE");
565         if (env && !strcmp(env, "always"))
566                 gBufMgr->lock_type = LOCK_TRY_ALWAYS;
567         else if (env && !strcmp(env, "none"))
568                 gBufMgr->lock_type = LOCK_TRY_NEVER;
569         else if (env && !strcmp(env, "once"))
570                 gBufMgr->lock_type = LOCK_TRY_ONCE;
571         else
572                 gBufMgr->lock_type = LOCK_TRY_ALWAYS;
573
574         DBG("BUFMGR_LOCK_TYPE=%s\n",
575             env ? env : "default:once");
576
577         /* intialize bo_list */
578         LIST_INITHEAD(&gBufMgr->bo_list);
579
580         /* intialize surf_list */
581         LIST_INITHEAD(&gBufMgr->surf_list);
582
583         pthread_mutex_unlock(&gLock);
584         return gBufMgr;
585 }
586
587 void
588 tbm_bufmgr_deinit(tbm_bufmgr bufmgr)
589 {
590         TBM_RETURN_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr));
591
592         tbm_bo bo = NULL;
593         tbm_bo tmp = NULL;
594
595         tbm_surface_h surf = NULL;
596         tbm_surface_h tmp_surf = NULL;
597
598         pthread_mutex_lock(&gLock);
599
600         bufmgr->ref_count--;
601         if (bufmgr->ref_count > 0) {
602                 DBG("tizen bufmgr destroy: bufmgr:%p, ref_count:%d\n",
603                         bufmgr, bufmgr->ref_count);
604                 pthread_mutex_unlock(&gLock);
605                 return;
606         }
607
608         /* destroy bo_list */
609         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
610                 LIST_FOR_EACH_ENTRY_SAFE(bo, tmp, &bufmgr->bo_list, item_link) {
611                         TBM_LOG_E("Un-freed bo(%p, ref:%d)\n",
612                                 bo, bo->ref_cnt);
613                         bo->ref_cnt = 1;
614                         tbm_bo_unref(bo);
615                 }
616         }
617
618         /* destroy surf_list */
619         if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
620                 LIST_FOR_EACH_ENTRY_SAFE(surf, tmp_surf, &bufmgr->surf_list, item_link) {
621                         TBM_LOG_E("Un-freed surf(%p, ref:%d)\n",
622                                 surf, surf->refcnt);
623                         tbm_surface_destroy(surf);
624                 }
625         }
626
627         /* destroy bufmgr priv */
628         bufmgr->backend->bufmgr_deinit(bufmgr->backend->priv);
629         bufmgr->backend->priv = NULL;
630         tbm_backend_free(bufmgr->backend);
631         bufmgr->backend = NULL;
632
633         pthread_mutex_destroy(&bufmgr->lock);
634
635         DBG("tizen bufmgr destroy: bufmgr:%p\n",
636             bufmgr);
637
638         dlclose(bufmgr->module_data);
639
640         if (bufmgr->fd > 0)
641                 close(bufmgr->fd);
642
643         free(bufmgr);
644         bufmgr = NULL;
645         gBufMgr = NULL;
646
647         pthread_mutex_unlock(&gLock);
648 }
649
650 int
651 tbm_bo_size(tbm_bo bo)
652 {
653         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
654
655         tbm_bufmgr bufmgr = bo->bufmgr;
656         int size;
657
658         pthread_mutex_lock(&bufmgr->lock);
659
660         size = bufmgr->backend->bo_size(bo);
661
662         pthread_mutex_unlock(&bufmgr->lock);
663
664         return size;
665 }
666
667 tbm_bo
668 tbm_bo_ref(tbm_bo bo)
669 {
670         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), NULL);
671
672         tbm_bufmgr bufmgr = bo->bufmgr;
673
674         pthread_mutex_lock(&bufmgr->lock);
675
676         _tbm_bo_ref(bo);
677
678         pthread_mutex_unlock(&bufmgr->lock);
679
680         return bo;
681 }
682
683 void
684 tbm_bo_unref(tbm_bo bo)
685 {
686         TBM_RETURN_IF_FAIL(_tbm_bo_is_valid(bo));
687
688         tbm_bufmgr bufmgr = bo->bufmgr;
689
690         pthread_mutex_lock(&bufmgr->lock);
691
692         _tbm_bo_unref(bo);
693
694         pthread_mutex_unlock(&bufmgr->lock);
695 }
696
697 tbm_bo
698 tbm_bo_alloc(tbm_bufmgr bufmgr, int size, int flags)
699 {
700         TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr) && (size > 0), NULL);
701
702         tbm_bo bo = NULL;
703         void *bo_priv = NULL;
704
705         bo = calloc(1, sizeof(struct _tbm_bo));
706         if (!bo) {
707                 _tbm_set_last_result(TBM_BO_ERROR_HEAP_ALLOC_FAILED);
708                 return NULL;
709         }
710
711         bo->bufmgr = bufmgr;
712
713         pthread_mutex_lock(&bufmgr->lock);
714
715         bo_priv = bufmgr->backend->bo_alloc(bo, size, flags);
716         if (!bo_priv) {
717                 _tbm_set_last_result(TBM_BO_ERROR_BO_ALLOC_FAILED);
718                 free(bo);
719                 pthread_mutex_unlock(&bufmgr->lock);
720                 return NULL;
721         }
722
723         bo->ref_cnt = 1;
724         bo->flags = flags;
725         bo->priv = bo_priv;
726
727         LIST_INITHEAD(&bo->user_data_list);
728
729         LIST_ADD(&bo->item_link, &bufmgr->bo_list);
730
731         pthread_mutex_unlock(&bufmgr->lock);
732
733         return bo;
734 }
735
736 tbm_bo
737 tbm_bo_import(tbm_bufmgr bufmgr, unsigned int key)
738 {
739         TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
740
741         tbm_bo bo = NULL;
742         tbm_bo bo2 = NULL;
743         tbm_bo tmp = NULL;
744         void *bo_priv = NULL;
745
746         pthread_mutex_lock(&bufmgr->lock);
747
748         bo = calloc(1, sizeof(struct _tbm_bo));
749         if (!bo) {
750                 pthread_mutex_unlock(&bufmgr->lock);
751                 return NULL;
752         }
753
754         bo->bufmgr = bufmgr;
755
756         bo_priv = bufmgr->backend->bo_import(bo, key);
757         if (!bo_priv) {
758                 _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FAILED);
759                 free(bo);
760                 pthread_mutex_unlock(&bufmgr->lock);
761                 return NULL;
762         }
763
764         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
765                 LIST_FOR_EACH_ENTRY_SAFE(bo2, tmp, &bufmgr->bo_list, item_link) {
766                         if (bo2->priv == bo_priv) {
767                                 DBG("find bo(%p, ref:%d key:%d) in list\n",
768                                     bo2, bo2->ref_cnt, key);
769
770                                 bo2->ref_cnt++;
771                                 free(bo);
772                                 pthread_mutex_unlock(&bufmgr->lock);
773                                 return bo2;
774                         }
775                 }
776         }
777
778         bo->ref_cnt = 1;
779         bo->priv = bo_priv;
780
781         if (bufmgr->backend->bo_get_flags)
782                 bo->flags = bufmgr->backend->bo_get_flags(bo);
783         else
784                 bo->flags = TBM_BO_DEFAULT;
785
786         LIST_INITHEAD(&bo->user_data_list);
787
788         LIST_ADD(&bo->item_link, &bufmgr->bo_list);
789
790         pthread_mutex_unlock(&bufmgr->lock);
791
792         return bo;
793 }
794
795 tbm_bo
796 tbm_bo_import_fd(tbm_bufmgr bufmgr, tbm_fd fd)
797 {
798         TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
799
800         tbm_bo bo = NULL;
801         tbm_bo bo2 = NULL;
802         tbm_bo tmp = NULL;
803         void *bo_priv = NULL;
804
805         pthread_mutex_lock(&bufmgr->lock);
806
807         bo = calloc(1, sizeof(struct _tbm_bo));
808         if (!bo) {
809                 pthread_mutex_unlock(&bufmgr->lock);
810                 return NULL;
811         }
812
813         bo->bufmgr = bufmgr;
814
815         bo_priv = bufmgr->backend->bo_import_fd(bo, fd);
816         if (!bo_priv) {
817                 _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FD_FAILED);
818                 free(bo);
819                 pthread_mutex_unlock(&bufmgr->lock);
820                 return NULL;
821         }
822
823         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
824                 LIST_FOR_EACH_ENTRY_SAFE(bo2, tmp, &bufmgr->bo_list, item_link) {
825                         if (bo2->priv == bo_priv) {
826                                 DBG("find bo(%p, ref:%d, fd:%d) in list\n",
827                                     bo2, bo2->ref_cnt, fd);
828
829                                 bo2->ref_cnt++;
830                                 free(bo);
831                                 pthread_mutex_unlock(&bufmgr->lock);
832                                 return bo2;
833                         }
834                 }
835         }
836
837         bo->ref_cnt = 1;
838         bo->priv = bo_priv;
839
840         if (bufmgr->backend->bo_get_flags)
841                 bo->flags = bufmgr->backend->bo_get_flags(bo);
842         else
843                 bo->flags = TBM_BO_DEFAULT;
844
845         LIST_INITHEAD(&bo->user_data_list);
846
847         LIST_ADD(&bo->item_link, &bufmgr->bo_list);
848
849         pthread_mutex_unlock(&bufmgr->lock);
850
851         return bo;
852 }
853
854 tbm_key
855 tbm_bo_export(tbm_bo bo)
856 {
857         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
858
859         tbm_bufmgr bufmgr;
860         tbm_key ret;
861
862         bufmgr = bo->bufmgr;
863
864         pthread_mutex_lock(&bufmgr->lock);
865         ret = bufmgr->backend->bo_export(bo);
866         if (!ret) {
867                 _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FAILED);
868                 pthread_mutex_unlock(&bufmgr->lock);
869                 return ret;
870         }
871         pthread_mutex_unlock(&bufmgr->lock);
872
873         return ret;
874 }
875
876 tbm_fd
877 tbm_bo_export_fd(tbm_bo bo)
878 {
879         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), -1);
880
881         tbm_bufmgr bufmgr;
882         int ret;
883
884         bufmgr = bo->bufmgr;
885
886         pthread_mutex_lock(&bufmgr->lock);
887         ret = bufmgr->backend->bo_export_fd(bo);
888         if (ret < 0) {
889                 _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FD_FAILED);
890                 pthread_mutex_unlock(&bufmgr->lock);
891                 return ret;
892         }
893         pthread_mutex_unlock(&bufmgr->lock);
894
895         return ret;
896 }
897
898 tbm_bo_handle
899 tbm_bo_get_handle(tbm_bo bo, int device)
900 {
901         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) 0);
902
903         tbm_bufmgr bufmgr;
904         tbm_bo_handle bo_handle;
905
906         bufmgr = bo->bufmgr;
907
908         pthread_mutex_lock(&bufmgr->lock);
909         bo_handle = bufmgr->backend->bo_get_handle(bo, device);
910         if (bo_handle.ptr == NULL) {
911                 _tbm_set_last_result(TBM_BO_ERROR_GET_HANDLE_FAILED);
912                 pthread_mutex_unlock(&bufmgr->lock);
913                 return (tbm_bo_handle) NULL;
914         }
915         pthread_mutex_unlock(&bufmgr->lock);
916
917         return bo_handle;
918 }
919
920 tbm_bo_handle
921 tbm_bo_map(tbm_bo bo, int device, int opt)
922 {
923         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) 0);
924
925         tbm_bufmgr bufmgr;
926         tbm_bo_handle bo_handle;
927
928         bufmgr = bo->bufmgr;
929
930         pthread_mutex_lock(&bufmgr->lock);
931
932         if (!_tbm_bo_lock(bo, device, opt)) {
933                 _tbm_set_last_result(TBM_BO_ERROR_LOCK_FAILED);
934                 TBM_LOG_E("error fail to lock bo:%p)\n",
935                         bo);
936                 pthread_mutex_unlock(&bufmgr->lock);
937                 return (tbm_bo_handle) NULL;
938         }
939
940         bo_handle = bufmgr->backend->bo_map(bo, device, opt);
941         if (bo_handle.ptr == NULL) {
942                 _tbm_set_last_result(TBM_BO_ERROR_MAP_FAILED);
943                 TBM_LOG_E("error fail to map bo:%p\n",
944                         bo);
945
946                 _tbm_bo_unlock(bo);
947                 pthread_mutex_unlock(&bufmgr->lock);
948                 return (tbm_bo_handle) NULL;
949         }
950
951         /* increase the map_count */
952         bo->map_cnt++;
953
954         pthread_mutex_unlock(&bufmgr->lock);
955
956         return bo_handle;
957 }
958
959 int
960 tbm_bo_unmap(tbm_bo bo)
961 {
962         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
963
964         tbm_bufmgr bufmgr;
965         int ret;
966
967         bufmgr = bo->bufmgr;
968
969         pthread_mutex_lock(&bufmgr->lock);
970
971         ret = bufmgr->backend->bo_unmap(bo);
972         if (!ret) {
973
974                 _tbm_set_last_result(TBM_BO_ERROR_UNMAP_FAILED);
975                 pthread_mutex_unlock(&bufmgr->lock);
976                 return ret;
977         }
978
979         /* decrease the map_count */
980         bo->map_cnt--;
981
982         _tbm_bo_unlock(bo);
983
984         pthread_mutex_unlock(&bufmgr->lock);
985
986         return ret;
987 }
988
989 int
990 tbm_bo_swap(tbm_bo bo1, tbm_bo bo2)
991 {
992         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo1), 0);
993         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo2), 0);
994
995         void *temp;
996
997         pthread_mutex_lock(&bo1->bufmgr->lock);
998
999         if (bo1->bufmgr->backend->bo_size(bo1) != bo2->bufmgr->backend->bo_size(bo2)) {
1000                 _tbm_set_last_result(TBM_BO_ERROR_SWAP_FAILED);
1001                 pthread_mutex_unlock(&bo1->bufmgr->lock);
1002                 return 0;
1003         }
1004
1005         temp = bo1->priv;
1006         bo1->priv = bo2->priv;
1007         bo2->priv = temp;
1008
1009         pthread_mutex_unlock(&bo1->bufmgr->lock);
1010
1011         return 1;
1012 }
1013
1014 int
1015 tbm_bo_locked(tbm_bo bo)
1016 {
1017         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1018
1019         tbm_bufmgr bufmgr;
1020
1021         bufmgr = bo->bufmgr;
1022
1023         if (bufmgr->lock_type == LOCK_TRY_NEVER)
1024                 return 0;
1025
1026         pthread_mutex_lock(&bufmgr->lock);
1027
1028         if (bo->lock_cnt > 0) {
1029                 pthread_mutex_unlock(&bufmgr->lock);
1030                 return 1;
1031         }
1032
1033         pthread_mutex_unlock(&bufmgr->lock);
1034
1035         return 0;
1036 }
1037
1038 int
1039 tbm_bo_add_user_data(tbm_bo bo, unsigned long key,
1040                      tbm_data_free data_free_func)
1041 {
1042         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1043
1044         tbm_user_data *data;
1045
1046         /* check if the data according to the key exist if so, return false. */
1047         data = user_data_lookup(&bo->user_data_list, key);
1048         if (data) {
1049                 TBM_LOG_W("waring user data already exist. key:%ld\n",
1050                         key);
1051                 return 0;
1052         }
1053
1054         data = user_data_create(key, data_free_func);
1055         if (!data)
1056                 return 0;
1057
1058         LIST_ADD(&data->item_link, &bo->user_data_list);
1059
1060         return 1;
1061 }
1062
1063 int
1064 tbm_bo_set_user_data(tbm_bo bo, unsigned long key, void *data)
1065 {
1066         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1067
1068         tbm_user_data *old_data;
1069
1070         if (LIST_IS_EMPTY(&bo->user_data_list))
1071                 return 0;
1072
1073         old_data = user_data_lookup(&bo->user_data_list, key);
1074         if (!old_data)
1075                 return 0;
1076
1077         if (old_data->data && old_data->free_func)
1078                 old_data->free_func(old_data->data);
1079
1080         old_data->data = data;
1081
1082         return 1;
1083 }
1084
1085 int
1086 tbm_bo_get_user_data(tbm_bo bo, unsigned long key, void **data)
1087 {
1088         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1089
1090         tbm_user_data *old_data;
1091
1092         if (!data || LIST_IS_EMPTY(&bo->user_data_list))
1093                 return 0;
1094
1095         old_data = user_data_lookup(&bo->user_data_list, key);
1096         if (!old_data) {
1097                 *data = NULL;
1098                 return 0;
1099         }
1100
1101         *data = old_data->data;
1102
1103         return 1;
1104 }
1105
1106 int
1107 tbm_bo_delete_user_data(tbm_bo bo, unsigned long key)
1108 {
1109         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1110
1111         tbm_user_data *old_data = (void *)0;
1112
1113         if (LIST_IS_EMPTY(&bo->user_data_list))
1114                 return 0;
1115
1116         old_data = user_data_lookup(&bo->user_data_list, key);
1117         if (!old_data)
1118                 return 0;
1119
1120         user_data_delete(old_data);
1121
1122         return 1;
1123 }
1124
1125 tbm_error_e
1126 tbm_get_last_error(void)
1127 {
1128         return tbm_last_error;
1129 }
1130
1131 unsigned int
1132 tbm_bufmgr_get_capability(tbm_bufmgr bufmgr)
1133 {
1134         TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), 0);
1135
1136         unsigned int capability = TBM_BUFMGR_CAPABILITY_NONE;
1137
1138         if (bufmgr->backend->bo_import && bufmgr->backend->bo_export)
1139                 capability |= TBM_BUFMGR_CAPABILITY_SHARE_KEY;
1140
1141         if (bufmgr->backend->bo_import_fd && bufmgr->backend->bo_export_fd)
1142                 capability |= TBM_BUFMGR_CAPABILITY_SHARE_FD;
1143
1144         return capability;
1145 }
1146
1147 int
1148 tbm_bo_get_flags(tbm_bo bo)
1149 {
1150         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1151
1152         return bo->flags;
1153 }
1154
1155 void
1156 tbm_bufmgr_debug_show(tbm_bufmgr bufmgr)
1157 {
1158         TBM_RETURN_IF_FAIL(bufmgr != NULL);
1159         tbm_bo bo = NULL, tmp_bo = NULL;
1160         int bo_cnt = 0;
1161
1162         tbm_surface_h surf = NULL, tmp_surf = NULL;
1163         int surf_cnt = 0;
1164         int i;
1165         char app_name[255] = {0,};
1166         unsigned int pid = 0;
1167
1168         pthread_mutex_lock(&gLock);
1169
1170         TBM_DEBUG("\n");
1171         _tbm_util_get_appname_from_pid(getpid(), app_name);
1172         _tbm_util_get_appname_brief(app_name);
1173         TBM_DEBUG("============TBM DEBUG: %s(%d)===========================\n",
1174                   app_name, getpid());
1175         memset(app_name, 0x0, 255 * sizeof(char));
1176
1177         TBM_DEBUG("[tbm_surface information]\n");
1178         TBM_DEBUG("no  surface              refcnt  width  height  bpp  size      num_bos num_planes flags format              app_name\n");
1179         /* show the tbm_surface information in surf_list */
1180         if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
1181                 LIST_FOR_EACH_ENTRY_SAFE(surf, tmp_surf, &bufmgr->surf_list, item_link) {
1182                         pid = _tbm_surface_internal_get_debug_pid(surf);
1183                         if (!pid) {
1184                                 /* if pid is null, set the self_pid */
1185                                 pid = getpid();
1186                         }
1187
1188                         _tbm_util_get_appname_from_pid(pid, app_name);
1189                         _tbm_util_get_appname_brief(app_name);
1190
1191                         TBM_DEBUG("%-4d%-23p%-6d%-7d%-8d%-5d%-12d%-10d%-9d%-4d%-20s%s\n",
1192                                   ++surf_cnt,
1193                                   surf,
1194                                   surf->refcnt,
1195                                   surf->info.width,
1196                                   surf->info.height,
1197                                   surf->info.bpp,
1198                                   surf->info.size / 1024,
1199                                   surf->num_bos,
1200                                   surf->num_planes,
1201                                   surf->flags,
1202                                   _tbm_surface_internal_format_to_str(surf->info.format),
1203                                   app_name);
1204
1205                         for (i = 0; i < surf->num_bos; i++) {
1206                                 TBM_DEBUG(" bo:%-12p  %-26d%-10d\n",
1207                                           surf->bos[i],
1208                                           surf->bos[i]->ref_cnt,
1209                                           tbm_bo_size(surf->bos[i]) / 1024);
1210                         }
1211
1212                         memset(app_name, 0x0, 255 * sizeof(char));
1213                 }
1214         } else {
1215                 TBM_DEBUG("no tbm_surfaces.\n");
1216         }
1217         TBM_DEBUG("\n");
1218
1219         TBM_DEBUG("[tbm_bo information]\n");
1220         TBM_DEBUG("no  bo                   refcnt  size     lock_cnt map_cnt flags surface\n");
1221
1222         /* show the tbm_bo information in bo_list */
1223         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
1224                 LIST_FOR_EACH_ENTRY_SAFE(bo, tmp_bo, &bufmgr->bo_list, item_link) {
1225                         TBM_DEBUG("%-4d%-11p   %-6d%-12d%-9d%-9d%-4d%-11p\n",
1226                                   ++bo_cnt,
1227                                   bo,
1228                                   bo->ref_cnt,
1229                                   tbm_bo_size(bo) / 1024,
1230                                   bo->lock_cnt,
1231                                   bo->map_cnt,
1232                                   bo->flags,
1233                                   bo->surface);
1234                 }
1235         } else {
1236                 TBM_DEBUG("no tbm_bos.\n");
1237         }
1238         TBM_DEBUG("\n");
1239
1240         TBM_DEBUG("===============================================================\n");
1241
1242         pthread_mutex_unlock(&gLock);
1243
1244 }
1245
1246 void
1247 tbm_bufmgr_debug_trace(tbm_bufmgr bufmgr, int onoff)
1248 {
1249         TBM_LOG_D("bufmgr=%p onoff=%d\n", bufmgr, onoff);
1250         TBM_LOG_D("Not implemented yet.\n");
1251 }
1252
1253 /* internal function */
1254 int
1255 _tbm_bo_set_surface(tbm_bo bo, tbm_surface_h surface)
1256 {
1257         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1258
1259         bo->surface = surface;
1260
1261         return 1;
1262 }
1263
1264 int
1265 tbm_bufmgr_bind_native_display(tbm_bufmgr bufmgr, void *NativeDisplay)
1266 {
1267         TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), 0);
1268
1269         int ret;
1270
1271         pthread_mutex_lock(&bufmgr->lock);
1272
1273         if (!bufmgr->backend->bufmgr_bind_native_display) {
1274                 pthread_mutex_unlock(&bufmgr->lock);
1275                 return 1;
1276         }
1277
1278         ret = bufmgr->backend->bufmgr_bind_native_display(bufmgr, NativeDisplay);
1279         if (!ret) {
1280                 pthread_mutex_unlock(&bufmgr->lock);
1281                 return 0;
1282         }
1283
1284         pthread_mutex_unlock(&bufmgr->lock);
1285
1286         return 1;
1287 }
1288