Check valid gBufmgr in tbm_bufmgr_deinit
[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         if (!gBufMgr) {
601                 TBM_LOG_E("gBufmgr already destroy: bufmgr:%p\n", bufmgr);
602                 pthread_mutex_unlock(&gLock);
603                 return;
604         }
605
606         bufmgr->ref_count--;
607         if (bufmgr->ref_count > 0) {
608                 DBG("tizen bufmgr destroy: bufmgr:%p, ref_count:%d\n",
609                         bufmgr, bufmgr->ref_count);
610                 pthread_mutex_unlock(&gLock);
611                 return;
612         }
613
614         /* destroy bo_list */
615         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
616                 LIST_FOR_EACH_ENTRY_SAFE(bo, tmp, &bufmgr->bo_list, item_link) {
617                         TBM_LOG_E("Un-freed bo(%p, ref:%d)\n",
618                                 bo, bo->ref_cnt);
619                         bo->ref_cnt = 1;
620                         tbm_bo_unref(bo);
621                 }
622         }
623
624         /* destroy surf_list */
625         if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
626                 LIST_FOR_EACH_ENTRY_SAFE(surf, tmp_surf, &bufmgr->surf_list, item_link) {
627                         TBM_LOG_E("Un-freed surf(%p, ref:%d)\n",
628                                 surf, surf->refcnt);
629                         tbm_surface_destroy(surf);
630                 }
631         }
632
633         /* destroy bufmgr priv */
634         bufmgr->backend->bufmgr_deinit(bufmgr->backend->priv);
635         bufmgr->backend->priv = NULL;
636         tbm_backend_free(bufmgr->backend);
637         bufmgr->backend = NULL;
638
639         pthread_mutex_destroy(&bufmgr->lock);
640
641         DBG("tizen bufmgr destroy: bufmgr:%p\n",
642             bufmgr);
643
644         dlclose(bufmgr->module_data);
645
646         if (bufmgr->fd > 0)
647                 close(bufmgr->fd);
648
649         free(bufmgr);
650         bufmgr = NULL;
651         gBufMgr = NULL;
652
653         pthread_mutex_unlock(&gLock);
654 }
655
656 int
657 tbm_bo_size(tbm_bo bo)
658 {
659         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
660
661         tbm_bufmgr bufmgr = bo->bufmgr;
662         int size;
663
664         pthread_mutex_lock(&bufmgr->lock);
665
666         size = bufmgr->backend->bo_size(bo);
667
668         pthread_mutex_unlock(&bufmgr->lock);
669
670         return size;
671 }
672
673 tbm_bo
674 tbm_bo_ref(tbm_bo bo)
675 {
676         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), NULL);
677
678         tbm_bufmgr bufmgr = bo->bufmgr;
679
680         pthread_mutex_lock(&bufmgr->lock);
681
682         _tbm_bo_ref(bo);
683
684         pthread_mutex_unlock(&bufmgr->lock);
685
686         return bo;
687 }
688
689 void
690 tbm_bo_unref(tbm_bo bo)
691 {
692         TBM_RETURN_IF_FAIL(_tbm_bo_is_valid(bo));
693
694         tbm_bufmgr bufmgr = bo->bufmgr;
695
696         pthread_mutex_lock(&bufmgr->lock);
697
698         _tbm_bo_unref(bo);
699
700         pthread_mutex_unlock(&bufmgr->lock);
701 }
702
703 tbm_bo
704 tbm_bo_alloc(tbm_bufmgr bufmgr, int size, int flags)
705 {
706         TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr) && (size > 0), NULL);
707
708         tbm_bo bo = NULL;
709         void *bo_priv = NULL;
710
711         bo = calloc(1, sizeof(struct _tbm_bo));
712         if (!bo) {
713                 _tbm_set_last_result(TBM_BO_ERROR_HEAP_ALLOC_FAILED);
714                 return NULL;
715         }
716
717         bo->bufmgr = bufmgr;
718
719         pthread_mutex_lock(&bufmgr->lock);
720
721         bo_priv = bufmgr->backend->bo_alloc(bo, size, flags);
722         if (!bo_priv) {
723                 _tbm_set_last_result(TBM_BO_ERROR_BO_ALLOC_FAILED);
724                 free(bo);
725                 pthread_mutex_unlock(&bufmgr->lock);
726                 return NULL;
727         }
728
729         bo->ref_cnt = 1;
730         bo->flags = flags;
731         bo->priv = bo_priv;
732
733         LIST_INITHEAD(&bo->user_data_list);
734
735         LIST_ADD(&bo->item_link, &bufmgr->bo_list);
736
737         pthread_mutex_unlock(&bufmgr->lock);
738
739         return bo;
740 }
741
742 tbm_bo
743 tbm_bo_import(tbm_bufmgr bufmgr, unsigned int key)
744 {
745         TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
746
747         tbm_bo bo = NULL;
748         tbm_bo bo2 = NULL;
749         tbm_bo tmp = NULL;
750         void *bo_priv = NULL;
751
752         pthread_mutex_lock(&bufmgr->lock);
753
754         bo = calloc(1, sizeof(struct _tbm_bo));
755         if (!bo) {
756                 pthread_mutex_unlock(&bufmgr->lock);
757                 return NULL;
758         }
759
760         bo->bufmgr = bufmgr;
761
762         bo_priv = bufmgr->backend->bo_import(bo, key);
763         if (!bo_priv) {
764                 _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FAILED);
765                 free(bo);
766                 pthread_mutex_unlock(&bufmgr->lock);
767                 return NULL;
768         }
769
770         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
771                 LIST_FOR_EACH_ENTRY_SAFE(bo2, tmp, &bufmgr->bo_list, item_link) {
772                         if (bo2->priv == bo_priv) {
773                                 DBG("find bo(%p, ref:%d key:%d) in list\n",
774                                     bo2, bo2->ref_cnt, key);
775
776                                 bo2->ref_cnt++;
777                                 free(bo);
778                                 pthread_mutex_unlock(&bufmgr->lock);
779                                 return bo2;
780                         }
781                 }
782         }
783
784         bo->ref_cnt = 1;
785         bo->priv = bo_priv;
786
787         if (bufmgr->backend->bo_get_flags)
788                 bo->flags = bufmgr->backend->bo_get_flags(bo);
789         else
790                 bo->flags = TBM_BO_DEFAULT;
791
792         LIST_INITHEAD(&bo->user_data_list);
793
794         LIST_ADD(&bo->item_link, &bufmgr->bo_list);
795
796         pthread_mutex_unlock(&bufmgr->lock);
797
798         return bo;
799 }
800
801 tbm_bo
802 tbm_bo_import_fd(tbm_bufmgr bufmgr, tbm_fd fd)
803 {
804         TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
805
806         tbm_bo bo = NULL;
807         tbm_bo bo2 = NULL;
808         tbm_bo tmp = NULL;
809         void *bo_priv = NULL;
810
811         pthread_mutex_lock(&bufmgr->lock);
812
813         bo = calloc(1, sizeof(struct _tbm_bo));
814         if (!bo) {
815                 pthread_mutex_unlock(&bufmgr->lock);
816                 return NULL;
817         }
818
819         bo->bufmgr = bufmgr;
820
821         bo_priv = bufmgr->backend->bo_import_fd(bo, fd);
822         if (!bo_priv) {
823                 _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FD_FAILED);
824                 free(bo);
825                 pthread_mutex_unlock(&bufmgr->lock);
826                 return NULL;
827         }
828
829         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
830                 LIST_FOR_EACH_ENTRY_SAFE(bo2, tmp, &bufmgr->bo_list, item_link) {
831                         if (bo2->priv == bo_priv) {
832                                 DBG("find bo(%p, ref:%d, fd:%d) in list\n",
833                                     bo2, bo2->ref_cnt, fd);
834
835                                 bo2->ref_cnt++;
836                                 free(bo);
837                                 pthread_mutex_unlock(&bufmgr->lock);
838                                 return bo2;
839                         }
840                 }
841         }
842
843         bo->ref_cnt = 1;
844         bo->priv = bo_priv;
845
846         if (bufmgr->backend->bo_get_flags)
847                 bo->flags = bufmgr->backend->bo_get_flags(bo);
848         else
849                 bo->flags = TBM_BO_DEFAULT;
850
851         LIST_INITHEAD(&bo->user_data_list);
852
853         LIST_ADD(&bo->item_link, &bufmgr->bo_list);
854
855         pthread_mutex_unlock(&bufmgr->lock);
856
857         return bo;
858 }
859
860 tbm_key
861 tbm_bo_export(tbm_bo bo)
862 {
863         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
864
865         tbm_bufmgr bufmgr;
866         tbm_key ret;
867
868         bufmgr = bo->bufmgr;
869
870         pthread_mutex_lock(&bufmgr->lock);
871         ret = bufmgr->backend->bo_export(bo);
872         if (!ret) {
873                 _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FAILED);
874                 pthread_mutex_unlock(&bufmgr->lock);
875                 return ret;
876         }
877         pthread_mutex_unlock(&bufmgr->lock);
878
879         return ret;
880 }
881
882 tbm_fd
883 tbm_bo_export_fd(tbm_bo bo)
884 {
885         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), -1);
886
887         tbm_bufmgr bufmgr;
888         int ret;
889
890         bufmgr = bo->bufmgr;
891
892         pthread_mutex_lock(&bufmgr->lock);
893         ret = bufmgr->backend->bo_export_fd(bo);
894         if (ret < 0) {
895                 _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FD_FAILED);
896                 pthread_mutex_unlock(&bufmgr->lock);
897                 return ret;
898         }
899         pthread_mutex_unlock(&bufmgr->lock);
900
901         return ret;
902 }
903
904 tbm_bo_handle
905 tbm_bo_get_handle(tbm_bo bo, int device)
906 {
907         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) 0);
908
909         tbm_bufmgr bufmgr;
910         tbm_bo_handle bo_handle;
911
912         bufmgr = bo->bufmgr;
913
914         pthread_mutex_lock(&bufmgr->lock);
915         bo_handle = bufmgr->backend->bo_get_handle(bo, device);
916         if (bo_handle.ptr == NULL) {
917                 _tbm_set_last_result(TBM_BO_ERROR_GET_HANDLE_FAILED);
918                 pthread_mutex_unlock(&bufmgr->lock);
919                 return (tbm_bo_handle) NULL;
920         }
921         pthread_mutex_unlock(&bufmgr->lock);
922
923         return bo_handle;
924 }
925
926 tbm_bo_handle
927 tbm_bo_map(tbm_bo bo, int device, int opt)
928 {
929         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) 0);
930
931         tbm_bufmgr bufmgr;
932         tbm_bo_handle bo_handle;
933
934         bufmgr = bo->bufmgr;
935
936         pthread_mutex_lock(&bufmgr->lock);
937
938         if (!_tbm_bo_lock(bo, device, opt)) {
939                 _tbm_set_last_result(TBM_BO_ERROR_LOCK_FAILED);
940                 TBM_LOG_E("error fail to lock bo:%p)\n",
941                         bo);
942                 pthread_mutex_unlock(&bufmgr->lock);
943                 return (tbm_bo_handle) NULL;
944         }
945
946         bo_handle = bufmgr->backend->bo_map(bo, device, opt);
947         if (bo_handle.ptr == NULL) {
948                 _tbm_set_last_result(TBM_BO_ERROR_MAP_FAILED);
949                 TBM_LOG_E("error fail to map bo:%p\n",
950                         bo);
951
952                 _tbm_bo_unlock(bo);
953                 pthread_mutex_unlock(&bufmgr->lock);
954                 return (tbm_bo_handle) NULL;
955         }
956
957         /* increase the map_count */
958         bo->map_cnt++;
959
960         pthread_mutex_unlock(&bufmgr->lock);
961
962         return bo_handle;
963 }
964
965 int
966 tbm_bo_unmap(tbm_bo bo)
967 {
968         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
969
970         tbm_bufmgr bufmgr;
971         int ret;
972
973         bufmgr = bo->bufmgr;
974
975         pthread_mutex_lock(&bufmgr->lock);
976
977         ret = bufmgr->backend->bo_unmap(bo);
978         if (!ret) {
979
980                 _tbm_set_last_result(TBM_BO_ERROR_UNMAP_FAILED);
981                 pthread_mutex_unlock(&bufmgr->lock);
982                 return ret;
983         }
984
985         /* decrease the map_count */
986         bo->map_cnt--;
987
988         _tbm_bo_unlock(bo);
989
990         pthread_mutex_unlock(&bufmgr->lock);
991
992         return ret;
993 }
994
995 int
996 tbm_bo_swap(tbm_bo bo1, tbm_bo bo2)
997 {
998         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo1), 0);
999         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo2), 0);
1000
1001         void *temp;
1002
1003         pthread_mutex_lock(&bo1->bufmgr->lock);
1004
1005         if (bo1->bufmgr->backend->bo_size(bo1) != bo2->bufmgr->backend->bo_size(bo2)) {
1006                 _tbm_set_last_result(TBM_BO_ERROR_SWAP_FAILED);
1007                 pthread_mutex_unlock(&bo1->bufmgr->lock);
1008                 return 0;
1009         }
1010
1011         temp = bo1->priv;
1012         bo1->priv = bo2->priv;
1013         bo2->priv = temp;
1014
1015         pthread_mutex_unlock(&bo1->bufmgr->lock);
1016
1017         return 1;
1018 }
1019
1020 int
1021 tbm_bo_locked(tbm_bo bo)
1022 {
1023         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1024
1025         tbm_bufmgr bufmgr;
1026
1027         bufmgr = bo->bufmgr;
1028
1029         if (bufmgr->lock_type == LOCK_TRY_NEVER)
1030                 return 0;
1031
1032         pthread_mutex_lock(&bufmgr->lock);
1033
1034         if (bo->lock_cnt > 0) {
1035                 pthread_mutex_unlock(&bufmgr->lock);
1036                 return 1;
1037         }
1038
1039         pthread_mutex_unlock(&bufmgr->lock);
1040
1041         return 0;
1042 }
1043
1044 int
1045 tbm_bo_add_user_data(tbm_bo bo, unsigned long key,
1046                      tbm_data_free data_free_func)
1047 {
1048         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1049
1050         tbm_user_data *data;
1051
1052         /* check if the data according to the key exist if so, return false. */
1053         data = user_data_lookup(&bo->user_data_list, key);
1054         if (data) {
1055                 TBM_LOG_W("waring user data already exist. key:%ld\n",
1056                         key);
1057                 return 0;
1058         }
1059
1060         data = user_data_create(key, data_free_func);
1061         if (!data)
1062                 return 0;
1063
1064         LIST_ADD(&data->item_link, &bo->user_data_list);
1065
1066         return 1;
1067 }
1068
1069 int
1070 tbm_bo_set_user_data(tbm_bo bo, unsigned long key, void *data)
1071 {
1072         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1073
1074         tbm_user_data *old_data;
1075
1076         if (LIST_IS_EMPTY(&bo->user_data_list))
1077                 return 0;
1078
1079         old_data = user_data_lookup(&bo->user_data_list, key);
1080         if (!old_data)
1081                 return 0;
1082
1083         if (old_data->data && old_data->free_func)
1084                 old_data->free_func(old_data->data);
1085
1086         old_data->data = data;
1087
1088         return 1;
1089 }
1090
1091 int
1092 tbm_bo_get_user_data(tbm_bo bo, unsigned long key, void **data)
1093 {
1094         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1095
1096         tbm_user_data *old_data;
1097
1098         if (!data || LIST_IS_EMPTY(&bo->user_data_list))
1099                 return 0;
1100
1101         old_data = user_data_lookup(&bo->user_data_list, key);
1102         if (!old_data) {
1103                 *data = NULL;
1104                 return 0;
1105         }
1106
1107         *data = old_data->data;
1108
1109         return 1;
1110 }
1111
1112 int
1113 tbm_bo_delete_user_data(tbm_bo bo, unsigned long key)
1114 {
1115         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1116
1117         tbm_user_data *old_data = (void *)0;
1118
1119         if (LIST_IS_EMPTY(&bo->user_data_list))
1120                 return 0;
1121
1122         old_data = user_data_lookup(&bo->user_data_list, key);
1123         if (!old_data)
1124                 return 0;
1125
1126         user_data_delete(old_data);
1127
1128         return 1;
1129 }
1130
1131 tbm_error_e
1132 tbm_get_last_error(void)
1133 {
1134         return tbm_last_error;
1135 }
1136
1137 unsigned int
1138 tbm_bufmgr_get_capability(tbm_bufmgr bufmgr)
1139 {
1140         TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), 0);
1141
1142         unsigned int capability = TBM_BUFMGR_CAPABILITY_NONE;
1143
1144         if (bufmgr->backend->bo_import && bufmgr->backend->bo_export)
1145                 capability |= TBM_BUFMGR_CAPABILITY_SHARE_KEY;
1146
1147         if (bufmgr->backend->bo_import_fd && bufmgr->backend->bo_export_fd)
1148                 capability |= TBM_BUFMGR_CAPABILITY_SHARE_FD;
1149
1150         return capability;
1151 }
1152
1153 int
1154 tbm_bo_get_flags(tbm_bo bo)
1155 {
1156         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1157
1158         return bo->flags;
1159 }
1160
1161 void
1162 tbm_bufmgr_debug_show(tbm_bufmgr bufmgr)
1163 {
1164         TBM_RETURN_IF_FAIL(bufmgr != NULL);
1165         tbm_bo bo = NULL, tmp_bo = NULL;
1166         int bo_cnt = 0;
1167
1168         tbm_surface_h surf = NULL, tmp_surf = NULL;
1169         int surf_cnt = 0;
1170         int i;
1171         char app_name[255] = {0,};
1172         unsigned int pid = 0;
1173
1174         pthread_mutex_lock(&gLock);
1175
1176         TBM_DEBUG("\n");
1177         _tbm_util_get_appname_from_pid(getpid(), app_name);
1178         _tbm_util_get_appname_brief(app_name);
1179         TBM_DEBUG("============TBM DEBUG: %s(%d)===========================\n",
1180                   app_name, getpid());
1181         memset(app_name, 0x0, 255 * sizeof(char));
1182
1183         TBM_DEBUG("[tbm_surface information]\n");
1184         TBM_DEBUG("no  surface              refcnt  width  height  bpp  size      num_bos num_planes flags format              app_name\n");
1185         /* show the tbm_surface information in surf_list */
1186         if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
1187                 LIST_FOR_EACH_ENTRY_SAFE(surf, tmp_surf, &bufmgr->surf_list, item_link) {
1188                         pid = _tbm_surface_internal_get_debug_pid(surf);
1189                         if (!pid) {
1190                                 /* if pid is null, set the self_pid */
1191                                 pid = getpid();
1192                         }
1193
1194                         _tbm_util_get_appname_from_pid(pid, app_name);
1195                         _tbm_util_get_appname_brief(app_name);
1196
1197                         TBM_DEBUG("%-4d%-23p%-6d%-7d%-8d%-5d%-12d%-10d%-9d%-4d%-20s%s\n",
1198                                   ++surf_cnt,
1199                                   surf,
1200                                   surf->refcnt,
1201                                   surf->info.width,
1202                                   surf->info.height,
1203                                   surf->info.bpp,
1204                                   surf->info.size / 1024,
1205                                   surf->num_bos,
1206                                   surf->num_planes,
1207                                   surf->flags,
1208                                   _tbm_surface_internal_format_to_str(surf->info.format),
1209                                   app_name);
1210
1211                         for (i = 0; i < surf->num_bos; i++) {
1212                                 TBM_DEBUG(" bo:%-12p  %-26d%-10d\n",
1213                                           surf->bos[i],
1214                                           surf->bos[i]->ref_cnt,
1215                                           tbm_bo_size(surf->bos[i]) / 1024);
1216                         }
1217
1218                         memset(app_name, 0x0, 255 * sizeof(char));
1219                 }
1220         } else {
1221                 TBM_DEBUG("no tbm_surfaces.\n");
1222         }
1223         TBM_DEBUG("\n");
1224
1225         TBM_DEBUG("[tbm_bo information]\n");
1226         TBM_DEBUG("no  bo                   refcnt  size     lock_cnt map_cnt flags surface\n");
1227
1228         /* show the tbm_bo information in bo_list */
1229         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
1230                 LIST_FOR_EACH_ENTRY_SAFE(bo, tmp_bo, &bufmgr->bo_list, item_link) {
1231                         TBM_DEBUG("%-4d%-11p   %-6d%-12d%-9d%-9d%-4d%-11p\n",
1232                                   ++bo_cnt,
1233                                   bo,
1234                                   bo->ref_cnt,
1235                                   tbm_bo_size(bo) / 1024,
1236                                   bo->lock_cnt,
1237                                   bo->map_cnt,
1238                                   bo->flags,
1239                                   bo->surface);
1240                 }
1241         } else {
1242                 TBM_DEBUG("no tbm_bos.\n");
1243         }
1244         TBM_DEBUG("\n");
1245
1246         TBM_DEBUG("===============================================================\n");
1247
1248         pthread_mutex_unlock(&gLock);
1249
1250 }
1251
1252 void
1253 tbm_bufmgr_debug_trace(tbm_bufmgr bufmgr, int onoff)
1254 {
1255         TBM_LOG_D("bufmgr=%p onoff=%d\n", bufmgr, onoff);
1256         TBM_LOG_D("Not implemented yet.\n");
1257 }
1258
1259 /* internal function */
1260 int
1261 _tbm_bo_set_surface(tbm_bo bo, tbm_surface_h surface)
1262 {
1263         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1264
1265         bo->surface = surface;
1266
1267         return 1;
1268 }
1269
1270 int
1271 tbm_bufmgr_bind_native_display(tbm_bufmgr bufmgr, void *NativeDisplay)
1272 {
1273         TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), 0);
1274
1275         int ret;
1276
1277         pthread_mutex_lock(&bufmgr->lock);
1278
1279         if (!bufmgr->backend->bufmgr_bind_native_display) {
1280                 pthread_mutex_unlock(&bufmgr->lock);
1281                 return 1;
1282         }
1283
1284         ret = bufmgr->backend->bufmgr_bind_native_display(bufmgr, NativeDisplay);
1285         if (!ret) {
1286                 pthread_mutex_unlock(&bufmgr->lock);
1287                 return 0;
1288         }
1289
1290         pthread_mutex_unlock(&bufmgr->lock);
1291
1292         return 1;
1293 }
1294