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