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