remove getenv() function.
[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 #include <sys/resource.h>
40
41 int trace_mask = 0;
42
43 #ifdef HAVE_DLOG
44 int bDlog;
45 #endif
46
47 tbm_bufmgr gBufMgr;
48 int b_dump_queue;
49
50 static pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
51 static pthread_mutex_t tbm_bufmgr_lock = PTHREAD_MUTEX_INITIALIZER;
52 static double scale_factor = 0;
53 void _tbm_bufmgr_mutex_unlock(void);
54
55 //#define TBM_BUFMGR_INIT_TIME
56
57 #define PREFIX_LIB    "libtbm_"
58 #define SUFFIX_LIB    ".so"
59 #define DEFAULT_LIB   PREFIX_LIB"default"SUFFIX_LIB
60
61 /* values to indicate unspecified fields in XF86ModReqInfo. */
62 #define MAJOR_UNSPEC      0xFF
63 #define MINOR_UNSPEC      0xFF
64 #define PATCH_UNSPEC      0xFFFF
65 #define ABI_VERS_UNSPEC   0xFFFFFFFF
66
67 #define MODULE_VERSION_NUMERIC(maj, min, patch) \
68                         ((((maj) & 0xFF) << 24) | (((min) & 0xFF) << 16) | (patch & 0xFFFF))
69 #define GET_MODULE_MAJOR_VERSION(vers)    (((vers) >> 24) & 0xFF)
70 #define GET_MODULE_MINOR_VERSION(vers)    (((vers) >> 16) & 0xFF)
71 #define GET_MODULE_PATCHLEVEL(vers)    ((vers) & 0xFFFF)
72
73 #define MAX_SIZE_N(dest)        (sizeof(dest) - strlen(dest) - 1)
74
75 /* check condition */
76 #define TBM_BUFMGR_RETURN_IF_FAIL(cond) {\
77         if (!(cond)) {\
78                 TBM_ERR("'%s' failed.\n", #cond);\
79                 _tbm_set_last_result(TBM_ERROR_INVALID_PARAMETER);\
80                 _tbm_bufmgr_mutex_unlock();\
81                 return;\
82         } \
83 }
84
85 #define TBM_BUFMGR_RETURN_VAL_IF_FAIL(cond, val) {\
86         if (!(cond)) {\
87                 TBM_ERR("'%s' failed.\n", #cond);\
88                 _tbm_set_last_result(TBM_ERROR_INVALID_PARAMETER);\
89                 _tbm_bufmgr_mutex_unlock();\
90                 return val;\
91         } \
92 }
93
94 /* LCOV_EXCL_START */
95
96 void
97 _tbm_bufmgr_mutex_lock(void)
98 {
99         pthread_mutex_lock(&tbm_bufmgr_lock);
100 }
101
102 void
103 _tbm_bufmgr_mutex_unlock(void)
104 {
105         pthread_mutex_unlock(&tbm_bufmgr_lock);
106 }
107
108 static int
109 _tbm_util_get_max_surface_size(int *w, int *h)
110 {
111         tbm_surface_info_s info;
112         tbm_surface_h surface = NULL;
113         int count = 0;
114
115         *w = 0;
116         *h = 0;
117
118         if (gBufMgr == NULL || LIST_IS_EMPTY(&gBufMgr->surf_list))
119                 return count;
120
121         LIST_FOR_EACH_ENTRY(surface, &gBufMgr->surf_list, item_link) {
122                 if (tbm_surface_get_info(surface, &info) == TBM_SURFACE_ERROR_NONE) {
123                         count++;
124                         if (*w < info.width)
125                                 *w = info.width;
126                         if (*h < info.height)
127                                 *h = info.height;
128                 }
129         }
130
131         return count;
132 }
133
134 static void
135 _tbm_util_get_appname_brief(char *brief)
136 {
137         char delim[] = "/";
138         char *token = NULL;
139         char temp[255] = {0,};
140         char *saveptr = NULL;
141
142         token = strtok_r(brief, delim, &saveptr);
143
144         while (token != NULL) {
145                 memset(temp, 0x00, 255 * sizeof(char));
146                 strncpy(temp, token, 254 * sizeof(char));
147                 token = strtok_r(NULL, delim, &saveptr);
148         }
149
150         snprintf(brief, sizeof(temp), "%s", temp);
151 }
152
153 static void
154 _tbm_util_get_appname_from_pid(long pid, char *str)
155 {
156         char fn_cmdline[255] = {0, }, cmdline[255];
157         FILE *fp;
158         int len;
159
160         if (pid <= 0) return;
161
162         snprintf(fn_cmdline, sizeof(fn_cmdline), "/proc/%ld/cmdline", pid);
163
164         fp = fopen(fn_cmdline, "r");
165         if (fp == 0) {
166                 TBM_ERR("cannot file open %s\n", fn_cmdline);
167                 return;
168         }
169
170         if (!fgets(cmdline, 255, fp)) {
171                 TBM_ERR("fail to get appname for pid(%ld)\n", pid);
172                 fclose(fp);
173                 return;
174         }
175
176         fclose(fp);
177
178         len = strlen(cmdline);
179         if (len < 1)
180                 memset(cmdline, 0x00, 255);
181         else
182                 cmdline[len] = 0;
183
184         snprintf(str, sizeof(cmdline), "%s", cmdline);
185 }
186
187 static int
188 _check_version(TBMModuleVersionInfo *data)
189 {
190         int backend_module_major, backend_module_minor;
191         int tbm_backend_major, tbm_backend_minor;
192
193         backend_module_major = GET_ABI_MAJOR(data->abiversion);
194         backend_module_minor = GET_ABI_MINOR(data->abiversion);
195
196         TBM_DBG("TBM module %s: vendor=\"%s\" ABI=%d,%d\n",
197             data->modname ? data->modname : "UNKNOWN!",
198             data->vendor ? data->vendor : "UNKNOWN!", backend_module_major, backend_module_minor);
199
200         tbm_backend_major = GET_ABI_MAJOR(TBM_ABI_VERSION);
201         tbm_backend_minor = GET_ABI_MINOR(TBM_ABI_VERSION);
202
203         TBM_DBG("TBM ABI version %d.%d\n",
204             tbm_backend_major, tbm_backend_minor);
205
206         if (backend_module_major != tbm_backend_major) {
207                 TBM_ERR("TBM module ABI major ver(%d) doesn't match the TBM's ver(%d)\n",
208                         backend_module_major, tbm_backend_major);
209                 return 0;
210         } else if (backend_module_minor > tbm_backend_minor) {
211                 TBM_ERR("TBM module ABI minor ver(%d) is newer than the TBM's ver(%d)\n",
212                         backend_module_minor, tbm_backend_minor);
213                 return 0;
214         }
215
216         return 1;
217 }
218
219 static int
220 _tbm_backend_check_bufmgr_func(tbm_backend_bufmgr_func *bufmgr_func)
221 {
222         TBM_RETURN_VAL_IF_FAIL(bufmgr_func, 0); /* mandatory symbol */
223         TBM_RETURN_VAL_IF_FAIL(bufmgr_func->bufmgr_get_capabilities, 0); /* mandatory symbol */
224         TBM_RETURN_VAL_IF_FAIL(bufmgr_func->bufmgr_bind_native_display, 0); /* mandatory symbol */
225         TBM_RETURN_VAL_IF_FAIL(bufmgr_func->bufmgr_get_supported_formats, 0); /* mandatory symbol */
226         TBM_RETURN_VAL_IF_FAIL(bufmgr_func->bufmgr_get_plane_data, 0); /* mandatory symbol */
227         TBM_RETURN_VAL_IF_FAIL(bufmgr_func->bufmgr_alloc_bo, 0); /* mandatory symbol */
228         if (!bufmgr_func->bufmgr_alloc_bo_with_format)
229                 TBM_DBG("No bufmgr_func->bufmgr_alloc_bo_with_format.");
230         TBM_RETURN_VAL_IF_FAIL(bufmgr_func->bufmgr_import_fd, 0); /* mandatory symbol */
231         if (!bufmgr_func->bufmgr_import_key)
232                 TBM_DBG("No bufmgr_func->bo_export_key.");
233
234         return 1;
235 }
236
237 static int
238 _tbm_backend_check_bufmgr_bo(tbm_backend_bo_func *bo_func)
239 {
240         TBM_RETURN_VAL_IF_FAIL(bo_func, 0); /* mandatory symbol */
241         TBM_RETURN_VAL_IF_FAIL(bo_func->bo_free, 0); /* mandatory symbol */
242         TBM_RETURN_VAL_IF_FAIL(bo_func->bo_get_size, 0); /* mandatory symbol */
243         TBM_RETURN_VAL_IF_FAIL(bo_func->bo_get_memory_types, 0); /* mandatory symbol */
244         TBM_RETURN_VAL_IF_FAIL(bo_func->bo_get_handle, 0); /* mandatory symbol */
245         TBM_RETURN_VAL_IF_FAIL(bo_func->bo_map, 0); /* mandatory symbol */
246         TBM_RETURN_VAL_IF_FAIL(bo_func->bo_unmap, 0); /* mandatory symbol */
247         if (!bo_func->bo_lock)
248                 TBM_DBG("No bo_func->bo_lock.");
249         if (!bo_func->bo_unlock)
250                 TBM_DBG("No bo_func->bo_unlock.");
251         TBM_RETURN_VAL_IF_FAIL(bo_func->bo_export_fd, 0); /* mandatory symbol */
252         if (!bo_func->bo_export_key)
253                 TBM_INFO("No bo_func->bo_export_key.");
254
255         return 1;
256 }
257
258 static int
259 _tbm_backend_load_module(tbm_bufmgr bufmgr, const char *file)
260 {
261         char path[PATH_MAX] = {0, };
262         void *module_data = NULL;
263         tbm_backend_module *backend_module_data = NULL;
264         tbm_backend_bufmgr_data *bufmgr_data = NULL;
265         int backend_module_major, backend_module_minor;
266         int tbm_backend_major, tbm_backend_minor;
267         tbm_error_e error;
268
269         snprintf(path, sizeof(path), BUFMGR_MODULE_DIR "/%s", file);
270
271         module_data = dlopen(path, RTLD_LAZY);
272         if (!module_data) {
273                 TBM_ERR("failed to load module: %s(%s)\n", dlerror(), file);
274                 return 0;
275         }
276
277         backend_module_data = dlsym(module_data, "tbm_backend_module_data");
278         if (!backend_module_data) {
279                 TBM_ERR("Error: module does not have data object.\n");
280                 goto err;
281         }
282
283         tbm_backend_major = GET_ABI_MAJOR(TBM_BACKEND_ABI_LATEST_VERSION);
284         tbm_backend_minor = GET_ABI_MINOR(TBM_BACKEND_ABI_LATEST_VERSION);
285         TBM_INFO("TBM Backend ABI version %d.%d\n", tbm_backend_major, tbm_backend_minor);
286
287         backend_module_major = GET_ABI_MAJOR(backend_module_data->abi_version);
288         backend_module_minor = GET_ABI_MINOR(backend_module_data->abi_version);
289
290         TBM_INFO("TBM module %s: vendor=\"%s\" Backend ABI version=%d.%d\n",
291             backend_module_data->name ? backend_module_data->name : "UNKNOWN!",
292             backend_module_data->vendor ? backend_module_data->vendor : "UNKNOWN!",
293                 backend_module_major, backend_module_minor);
294
295         if (backend_module_major > tbm_backend_major) {
296                 TBM_ERR("TBM module ABI major ver(%d) is newer than the TBM's ver(%d)\n",
297                         backend_module_major, tbm_backend_major);
298                 goto err;
299         } else if (backend_module_minor > tbm_backend_minor) {
300                 TBM_ERR("TBM module ABI minor ver(%d) is newer than the TBM's ver(%d)\n",
301                         backend_module_minor, tbm_backend_minor);
302                 goto err;
303         }
304
305         if (!backend_module_data->init) {
306                 TBM_ERR("Error: module does not supply init symbol.\n");
307                 goto err;
308         }
309
310         if (!backend_module_data->deinit)       {
311                 TBM_ERR("Error: module does not supply deinit symbol.\n");
312                 goto err;
313         }
314
315         bufmgr_data = backend_module_data->init(bufmgr, &error);
316         if (!bufmgr_data) {
317                 TBM_ERR("Fail to init module(%s)\n", file);
318                 goto err;
319         }
320
321         /* check the mandatory symbols of the backend module */
322         if (!_tbm_backend_check_bufmgr_func(bufmgr->bufmgr_func)) {
323                 TBM_ERR("Fail to check the bufmgr_func symboles.");
324                 goto err;
325         }
326
327         if (!_tbm_backend_check_bufmgr_bo(bufmgr->bo_func)) {
328                 TBM_ERR("Fail to check the bufmgr_bo symboles.");
329                 goto err;
330         }
331
332         /* get the capability */
333         bufmgr->capabilities = bufmgr->bufmgr_func->bufmgr_get_capabilities(bufmgr_data, &error);
334         if (bufmgr->capabilities == TBM_BUFMGR_CAPABILITY_NONE) {
335                 TBM_ERR("The capabilities of the backend module is TBM_BUFMGR_CAPABILITY_NONE.");
336                 TBM_ERR("TBM_BUFMGR_CAPABILITY_SHARE_FD is the essential capability.");
337                 goto err;
338         }
339
340         if (!(bufmgr->capabilities & TBM_BUFMGR_CAPABILITY_SHARE_FD)) {
341                 TBM_ERR("The capabilities of the backend module had no TBM_BUFMGR_CAPABILITY_SHARE_FD.");
342                 TBM_ERR("The tbm backend has to get TBM_BUFMGR_CAPABILITY_SHARE_FD. ");
343                 goto err;
344         }
345
346         bufmgr->module_data = module_data;
347         bufmgr->backend_module_data = backend_module_data;
348         bufmgr->bufmgr_data = bufmgr_data;
349
350         TBM_DBG("Success to load module(%s)\n", file);
351         TBM_STDOUT_INFO("Success to load module(%s)", file);
352
353         return 1;
354
355 err:
356         if (bufmgr_data)
357                 bufmgr->backend_module_data->deinit(bufmgr_data);
358         if (module_data)
359                 dlclose(module_data);
360
361         return 0;
362 }
363
364 static int
365 _tbm_bufmgr_load_module(tbm_bufmgr bufmgr, int fd, const char *file)
366 {
367         char path[PATH_MAX] = {0, };
368         TBMModuleVersionInfo *vers;
369         TBMModuleData *initdata;
370         ModuleInitProc init;
371         void *module_data;
372
373         snprintf(path, sizeof(path), BUFMGR_MODULE_DIR "/%s", file);
374
375         module_data = dlopen(path, RTLD_LAZY);
376         if (!module_data) {
377                 TBM_ERR("failed to load module: %s(%s)\n", dlerror(), file);
378                 return 0;
379         }
380
381         initdata = dlsym(module_data, "tbmModuleData");
382         if (!initdata) {
383                 TBM_ERR("Error: module does not have data object.\n");
384                 goto err;
385         }
386
387         vers = initdata->vers;
388         if (!vers) {
389                 TBM_ERR("Error: module does not supply version information.\n");
390                 goto err;
391         }
392
393         init = initdata->init;
394         if (!init) {
395                 TBM_ERR("Error: module does not supply init symbol.\n");
396                 goto err;
397         }
398
399         if (!_check_version(vers)) {
400                 TBM_ERR("Fail to check version.\n");
401                 goto err;
402         }
403
404         if (!init(bufmgr, fd)) {
405                 TBM_ERR("Fail to init module(%s)\n", file);
406                 goto err;
407         }
408
409         if (!bufmgr->backend || !bufmgr->backend->priv) {
410                 TBM_ERR("Error: module(%s) wrong operation. Check backend or backend's priv.\n", file);
411                 goto err;
412         }
413
414         bufmgr->module_data = module_data;
415
416         TBM_DBG("Success to load module(%s)\n", file);
417
418         return 1;
419
420 err:
421         dlclose(module_data);
422         return 0;
423 }
424
425 static int
426 _tbm_load_module(tbm_bufmgr bufmgr, int fd)
427 {
428         struct dirent **namelist;
429         int ret = 0, n;
430
431         /* try to load the new backend module */
432         ret = _tbm_backend_load_module(bufmgr, DEFAULT_LIB);
433         if (ret)
434                 return 1;
435
436         /* try to load the old(deprecated) backend mdoule */
437         ret = _tbm_bufmgr_load_module(bufmgr, fd, DEFAULT_LIB);
438         if (ret)
439                 return 1;
440
441         /* load bufmgr priv from configured path */
442         n = scandir(BUFMGR_MODULE_DIR, &namelist, 0, alphasort);
443         if (n < 0) {
444                 TBM_ERR("no files : %s\n", BUFMGR_MODULE_DIR);
445                 return 0;
446         }
447
448         while (n--) {
449                 if (!ret && strstr(namelist[n]->d_name, PREFIX_LIB)) {
450                         const char *p = strstr(namelist[n]->d_name, SUFFIX_LIB);
451
452                         if (p && !strcmp(p, SUFFIX_LIB)) {
453                                 ret = _tbm_backend_load_module(bufmgr, namelist[n]->d_name);
454                                 if (!ret)
455                                         ret = _tbm_bufmgr_load_module(bufmgr, fd,
456                                                                         namelist[n]->d_name);
457                         }
458                 }
459
460                 free(namelist[n]);
461         }
462
463         free(namelist);
464
465         return ret;
466 }
467 /* LCOV_EXCL_STOP */
468
469 static tbm_bufmgr
470 _tbm_bufmgr_init(int fd, int server)
471 {
472 #ifdef TBM_BUFMGR_INIT_TIME
473         struct timeval start_tv, end_tv;
474 #endif
475         char *env;
476
477 #ifdef TBM_BUFMGR_INIT_TIME
478         /* get the start tv */
479         gettimeofday(&start_tv, NULL);
480 #endif
481
482         bDlog = 1;
483         trace_mask = 0;
484
485         pthread_mutex_lock(&gLock);
486
487         _tbm_set_last_result(TBM_ERROR_NONE);
488
489         if (fd >= 0) {
490                 TBM_WRN("!!!!!WARNING:: The tbm_bufmgr_init DOSE NOT use argument fd ANYMORE.\n");
491                 TBM_WRN("!!!!!WARNING:: IT WILL BE CHANGED like tbm_bufmgr_init(int fd) --> tbm_bufmgr_init(void).\n");
492         }
493
494
495         /* initialize buffer manager */
496         if (gBufMgr) {
497                 gBufMgr->ref_count++;
498                 TBM_DBG("reuse  tbm_bufmgr(%p) ref_count(%d) fd(%d)\n", gBufMgr, gBufMgr->ref_count, gBufMgr->fd);
499                 pthread_mutex_unlock(&gLock);
500                 return gBufMgr;
501         }
502
503         TBM_DBG("bufmgr init\n");
504
505         /* allocate bufmgr */
506         gBufMgr = calloc(1, sizeof(struct _tbm_bufmgr));
507         if (!gBufMgr) {
508                 TBM_ERR("error: fail to alloc bufmgr fd(%d)\n", fd);
509                 _tbm_set_last_result(TBM_ERROR_OUT_OF_MEMORY);
510                 pthread_mutex_unlock(&gLock);
511                 return NULL;
512         }
513
514         gBufMgr->fd = fd;
515
516         /* set the display_server flag before loading the backend module */
517         if (server) {
518                 TBM_INFO("The tbm_bufmgr(%p) is used by display server. Need to bind the native_display.\n", gBufMgr);
519                 gBufMgr->display_server = 1;
520         }
521
522         /* load bufmgr priv from env */
523         TBM_STDOUT_INFO("loading backend module");
524         if (!_tbm_load_module(gBufMgr, gBufMgr->fd)) {
525                 TBM_ERR("error : Fail to load bufmgr backend\n");
526                 _tbm_set_last_result(TBM_ERROR_INVALID_OPERATION);
527                 free(gBufMgr);
528                 gBufMgr = NULL;
529                 pthread_mutex_unlock(&gLock);
530                 return NULL;
531
532         }
533         TBM_STDOUT_INFO("loading backend module done");
534         /* LCOV_EXCL_STOP */
535
536         gBufMgr->ref_count = 1;
537
538         TBM_INFO("create tizen bufmgr:%p ref_count:%d\n",
539             gBufMgr, gBufMgr->ref_count);
540
541         /* setup the bo_lock_type */
542         env = getenv("BUFMGR_LOCK_TYPE");
543         if (env && !strcmp(env, "always"))
544                 gBufMgr->bo_lock_type = TBM_BUFMGR_BO_LOCK_TYPE_ALWAYS;
545         else if (env && !strcmp(env, "none"))
546                 gBufMgr->bo_lock_type = TBM_BUFMGR_BO_LOCK_TYPE_NEVER;
547         else if (env && !strcmp(env, "once"))
548                 gBufMgr->bo_lock_type = TBM_BUFMGR_BO_LOCK_TYPE_ONCE;
549         else
550                 gBufMgr->bo_lock_type = TBM_BUFMGR_BO_LOCK_TYPE_ALWAYS;
551
552         TBM_DBG("BUFMGR_LOCK_TYPE=%s\n", env ? env : "default:once");
553
554         /* intialize bo_list */
555         LIST_INITHEAD(&gBufMgr->bo_list);
556
557         /* intialize surf_list */
558         LIST_INITHEAD(&gBufMgr->surf_list);
559
560         /* intialize surf_queue_list */
561         LIST_INITHEAD(&gBufMgr->surf_queue_list);
562
563         /* intialize debug_key_list */
564         LIST_INITHEAD(&gBufMgr->debug_key_list);
565
566 #ifdef TBM_BUFMGR_INIT_TIME
567         /* get the end tv */
568         gettimeofday(&end_tv, NULL);
569         TBM_INFO("tbm_bufmgr_init time: %ld ms", ((end_tv.tv_sec * 1000 + end_tv.tv_usec / 1000) - (start_tv.tv_sec * 1000 + start_tv.tv_usec / 1000)));
570 #endif
571
572         pthread_mutex_unlock(&gLock);
573
574         return gBufMgr;
575 }
576
577 tbm_bufmgr
578 tbm_bufmgr_init(int fd)
579 {
580         tbm_bufmgr bufmgr;
581
582         bufmgr = _tbm_bufmgr_init(fd, 0);
583
584         return bufmgr;
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_bufmgr_mutex_lock();
593         pthread_mutex_lock(&gLock);
594         _tbm_set_last_result(TBM_ERROR_NONE);
595
596         if (!gBufMgr) {
597                 TBM_ERR("gBufmgr already destroy: bufmgr:%p\n", bufmgr);
598                 pthread_mutex_unlock(&gLock);
599                 _tbm_bufmgr_mutex_unlock();
600                 return;
601         }
602
603         bufmgr->ref_count--;
604         if (bufmgr->ref_count > 0) {
605                 TBM_DBG("reduce a ref_count(%d) of tbm_bufmgr(%p)\n", bufmgr->ref_count, bufmgr);
606                 pthread_mutex_unlock(&gLock);
607                 _tbm_bufmgr_mutex_unlock();
608                 return;
609         }
610
611         /* destroy bo_list */
612         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
613                 tbm_bo bo = NULL, tmp;
614
615                 LIST_FOR_EACH_ENTRY_SAFE(bo, tmp, &bufmgr->bo_list, item_link) {
616                         TBM_ERR("Un-freed bo(%p, ref:%d)\n", bo, bo->ref_cnt);
617                         _tbm_bo_free(bo);
618                 }
619                 LIST_DELINIT(&bufmgr->bo_list);
620         }
621
622         /* destroy surf_list */
623         if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
624                 tbm_surface_h surf = NULL, tmp;
625
626                 LIST_FOR_EACH_ENTRY_SAFE(surf, tmp, &bufmgr->surf_list, item_link) {
627                         TBM_ERR("Un-freed surf(%p, ref:%d)\n", surf, surf->refcnt);
628                         tbm_surface_destroy(surf);
629                 }
630                 LIST_DELINIT(&bufmgr->surf_list);
631         }
632
633         if (bufmgr->backend_module_data) {
634                 /* deinit and backend destroys the backend func and data */
635                 bufmgr->backend_module_data->deinit(bufmgr->bufmgr_data);
636                 bufmgr->bo_func = NULL;
637                 bufmgr->bufmgr_func = NULL;
638                 bufmgr->bufmgr_data = NULL;
639                 bufmgr->backend_module_data = NULL;
640         } else {
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
648         TBM_INFO("destroy tbm_bufmgr(%p)\n", bufmgr);
649
650         dlclose(bufmgr->module_data);
651
652         if (bufmgr->fd > 0)
653                 close(bufmgr->fd);
654
655         free(bufmgr);
656         gBufMgr = NULL;
657
658         pthread_mutex_unlock(&gLock);
659         _tbm_bufmgr_mutex_unlock();
660 }
661
662 unsigned int
663 tbm_bufmgr_get_capability(tbm_bufmgr bufmgr)
664 {
665         unsigned int capabilities = TBM_BUFMGR_CAPABILITY_NONE;
666
667         _tbm_bufmgr_mutex_lock();
668         _tbm_set_last_result(TBM_ERROR_NONE);
669
670         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), TBM_BUFMGR_CAPABILITY_NONE);
671         TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, TBM_BUFMGR_CAPABILITY_NONE);
672
673         capabilities = bufmgr->capabilities;
674
675         _tbm_bufmgr_mutex_unlock();
676
677         return capabilities;
678 }
679
680 /* LCOV_EXCL_START */
681 char *
682 tbm_bufmgr_debug_tbm_info_get(tbm_bufmgr bufmgr)
683 {
684         char app_name[255] = {0,}, title[512] = {0,};
685         tbm_surface_debug_data *debug_old_data = NULL;
686         char *str;
687         int len = 1024*4;
688         int c = 0;
689         int size;
690         tbm_error_e error;
691         long pid = 0;
692
693         pthread_mutex_lock(&gLock);
694         _tbm_set_last_result(TBM_ERROR_NONE);
695
696         if (!TBM_BUFMGR_IS_VALID(bufmgr) || (bufmgr != gBufMgr)) {
697                 TBM_ERR("invalid bufmgr\n");
698                 _tbm_set_last_result(TBM_ERROR_INVALID_PARAMETER);
699                 pthread_mutex_unlock(&gLock);
700                 return NULL;
701         }
702
703         str = malloc(len);
704         if (!str) {
705                 TBM_ERR("Fail to allocate the string.\n");
706                 _tbm_set_last_result(TBM_ERROR_OUT_OF_MEMORY);
707                 pthread_mutex_unlock(&gLock);
708                 return NULL;
709         }
710
711         TBM_SNRPRINTF(str, len, c, "\n");
712         pid = syscall(SYS_getpid);
713         _tbm_util_get_appname_from_pid(pid, app_name);
714         _tbm_util_get_appname_brief(app_name);
715         TBM_SNRPRINTF(str, len, c, "===========================================TBM DEBUG: %s(%ld)===========================================\n",
716                   app_name, pid);
717
718         snprintf(title, 255, "%s", "no  surface     refcnt  width  height  bpp  size    n_b  n_p  flags    format    app_name              ");
719
720         if (!LIST_IS_EMPTY(&bufmgr->debug_key_list)) {
721                 LIST_FOR_EACH_ENTRY(debug_old_data, &bufmgr->debug_key_list, item_link) {
722                         strncat(title, "  ", MAX_SIZE_N(title));
723                         strncat(title, debug_old_data->key, MAX_SIZE_N(title));
724                 }
725         }
726
727         TBM_SNRPRINTF(str, len, c, "[tbm_surface information]\n");
728         TBM_SNRPRINTF(str, len, c, "%s\n", title);
729
730         /* show the tbm_surface information in surf_list */
731         if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
732                 tbm_surface_h surf = NULL;
733                 int surf_cnt = 0;
734
735                 LIST_FOR_EACH_ENTRY(surf, &bufmgr->surf_list, item_link) {
736                         char data[512] = {0,};
737                         unsigned int surf_pid = 0;
738                         int i;
739
740                         surf_pid = _tbm_surface_internal_get_debug_pid(surf);
741                         if (!surf_pid) {
742                                 /* if pid is null, set the self_pid */
743                                 surf_pid = syscall(SYS_getpid);;
744                         }
745
746                         memset(app_name, 0x0, 255 * sizeof(char));
747                         if (geteuid() == 0) {
748                                 _tbm_util_get_appname_from_pid(surf_pid, app_name);
749                                 _tbm_util_get_appname_brief(app_name);
750                         } else {
751                                 snprintf(app_name, sizeof(app_name), "%d", surf_pid);
752                         }
753
754                         snprintf(data, 255, "%-3d %-11p   %-5d %-6u %-7u %-4u %-7u  %-3d  %-3d %-8d %-9s %-22s",
755                                   ++surf_cnt,
756                                   surf,
757                                   surf->refcnt,
758                                   surf->info.width,
759                                   surf->info.height,
760                                   surf->info.bpp,
761                                   surf->info.size / 1024,
762                                   surf->num_bos,
763                                   surf->num_planes,
764                                   surf->flags,
765                                   _tbm_surface_internal_format_to_str(surf->info.format) + 11,
766                                   app_name);
767
768                         if (!LIST_IS_EMPTY(&bufmgr->debug_key_list)) {
769                                 LIST_FOR_EACH_ENTRY(debug_old_data, &bufmgr->debug_key_list, item_link) {
770                                         char *value;
771
772                                         strncat(data, "  ", MAX_SIZE_N(title));
773
774                                         value = _tbm_surface_internal_get_debug_data(surf, debug_old_data->key);
775                                         if (value)
776                                                 strncat(data, value, MAX_SIZE_N(title));
777                                         else
778                                                 strncat(data, "none", MAX_SIZE_N(title));
779                                 }
780                         }
781                         TBM_SNRPRINTF(str, len, c, "%s\n", data);
782
783                         for (i = 0; i < surf->num_bos; i++) {
784                                 if (bufmgr->backend_module_data) {
785                                         size = bufmgr->bo_func->bo_get_size(surf->bos[i]->bo_data, &error);
786                                         if (error != TBM_ERROR_NONE)
787                                                 TBM_WRN("fail to get the size of bo.");
788                                 } else
789                                         size = bufmgr->backend->bo_size(surf->bos[i]);
790                                 TBM_SNRPRINTF(str, len, c, " bo:%-12p  %-26d%-10d\n",
791                                           surf->bos[i],
792                                           surf->bos[i]->ref_cnt,
793                                           size / 1024);
794                         }
795                 }
796         } else
797                 TBM_SNRPRINTF(str, len, c, " no tbm_surfaces.\n");
798         TBM_SNRPRINTF(str, len, c, "\n");
799
800         TBM_SNRPRINTF(str, len, c, "[tbm_bo information]\n");
801         TBM_SNRPRINTF(str, len, c, "no  bo          refcnt  size    lock_cnt  map_cnt  flags   surface     name\n");
802
803         /* show the tbm_bo information in bo_list */
804         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
805                 int bo_cnt = 0;
806                 tbm_bo bo = NULL;
807                 tbm_key key = 0;
808
809                 LIST_FOR_EACH_ENTRY(bo, &bufmgr->bo_list, item_link) {
810                         if (bufmgr->backend_module_data) {
811                                 size = bufmgr->bo_func->bo_get_size(bo->bo_data, &error);
812                                 if (error != TBM_ERROR_NONE)
813                                         TBM_WRN("fail to get the size of bo.");
814                                 key = bufmgr->bo_func->bo_export_key(bo->bo_data, &error);
815                                 if (error != TBM_ERROR_NONE)
816                                         TBM_WRN("fail to get the tdm_key of bo.");
817                         } else {
818                                 size = bufmgr->backend->bo_size(bo);
819                                 key = bufmgr->backend->bo_export(bo);
820                         }
821                         TBM_SNRPRINTF(str, len, c, "%-3d %-11p   %-5d %-7d    %-6d    %-5u %-7d %-11p  %-4d\n",
822                                   ++bo_cnt,
823                                   bo,
824                                   bo->ref_cnt,
825                                   size / 1024,
826                                   bo->lock_cnt,
827                                   bo->map_cnt,
828                                   bo->flags,
829                                   bo->surface,
830                                   key);
831                 }
832         } else
833                 TBM_SNRPRINTF(str, len, c, "no tbm_bos.\n");
834         TBM_SNRPRINTF(str, len, c, "\n");
835
836         TBM_SNRPRINTF(str, len, c, "========================================================================================================\n");
837
838         pthread_mutex_unlock(&gLock);
839
840         return str;
841 }
842
843 void
844 tbm_bufmgr_debug_show(tbm_bufmgr bufmgr)
845 {
846         char * str;
847         str = tbm_bufmgr_debug_tbm_info_get(bufmgr);
848         if (str) {
849                 TBM_DBG("       %s", str);
850                 free(str);
851         }
852 }
853
854 void
855 tbm_bufmgr_debug_trace(tbm_bufmgr bufmgr, int onoff)
856 {
857         _tbm_bufmgr_mutex_lock();
858         _tbm_set_last_result(TBM_ERROR_NONE);
859
860         TBM_BUFMGR_RETURN_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr));
861         TBM_BUFMGR_RETURN_IF_FAIL(bufmgr == gBufMgr);
862
863 #ifdef TRACE
864         TBM_LOG_D("bufmgr=%p onoff=%d\n", bufmgr, onoff);
865         bTrace = onoff;
866 #endif
867
868         _tbm_bufmgr_mutex_unlock();
869 }
870
871 void
872 tbm_bufmgr_debug_set_trace_mask(tbm_bufmgr bufmgr, tbm_bufmgr_debug_trace_mask mask, int set)
873 {
874         _tbm_bufmgr_mutex_lock();
875         _tbm_set_last_result(TBM_ERROR_NONE);
876
877         TBM_BUFMGR_RETURN_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr));
878         TBM_BUFMGR_RETURN_IF_FAIL(bufmgr == gBufMgr);
879
880         if (set == 1) {
881                 trace_mask |= mask;
882
883                 TBM_INFO("bufmgr=%p sets the trace_mask=%d\n", bufmgr, mask);
884                 if (trace_mask&TBM_BUFGMR_DEBUG_TRACE_BO)
885                         TBM_INFO("  TBM_BUFGMR_DEBUG_TRACE_BO");
886                 if (trace_mask&TBM_BUFGMR_DEBUG_TRACE_SURFACE_INTERNAL)
887                         TBM_INFO("  TBM_BUFGMR_DEBUG_TRACE_SURFACE_INTERNAL");
888                 if (trace_mask&TBM_BUFGMR_DEBUG_TRACE_SURFACE)
889                         TBM_INFO("  TBM_BUFGMR_DEBUG_TRACE_SURFACE");
890                 if (trace_mask&TBM_BUFGMR_DEBUG_TRACE_SURFACE_QUEUE)
891                         TBM_INFO("  TBM_BUFGMR_DEBUG_TRACE_SURFACE_QUEUE");
892         } else if (set == 0) {
893                 trace_mask &= ~mask;
894
895                 TBM_INFO("bufmgr=%p unsets the trace_mask=%d\n", bufmgr, mask);
896                 if (trace_mask&TBM_BUFGMR_DEBUG_TRACE_BO)
897                         TBM_INFO("  TBM_BUFGMR_DEBUG_TRACE_BO");
898                 if (trace_mask&TBM_BUFGMR_DEBUG_TRACE_SURFACE_INTERNAL)
899                         TBM_INFO("  TBM_BUFGMR_DEBUG_TRACE_SURFACE_INTERNAL");
900                 if (trace_mask&TBM_BUFGMR_DEBUG_TRACE_SURFACE)
901                         TBM_INFO("  TBM_BUFGMR_DEBUG_TRACE_SURFACE");
902                 if (trace_mask&TBM_BUFGMR_DEBUG_TRACE_SURFACE_QUEUE)
903                         TBM_INFO("  TBM_BUFGMR_DEBUG_TRACE_SURFACE_QUEUE");
904         } else {
905                 TBM_WRN("set value is wrong.(set=%d)", set);
906         }
907
908         _tbm_bufmgr_mutex_unlock();
909 }
910
911 void
912 tbm_bufmgr_debug_dump_set_scale(double scale)
913 {
914         pthread_mutex_lock(&gLock);
915         _tbm_set_last_result(TBM_ERROR_NONE);
916         scale_factor = scale;
917         pthread_mutex_unlock(&gLock);
918 }
919
920 int
921 tbm_bufmgr_debug_get_ref_count(void)
922 {
923         int refcnt;
924
925         pthread_mutex_lock(&gLock);
926
927         _tbm_set_last_result(TBM_ERROR_NONE);
928
929         refcnt = (gBufMgr) ? gBufMgr->ref_count : 0;
930
931         pthread_mutex_unlock(&gLock);
932
933         return refcnt;
934 }
935
936 int
937 tbm_bufmgr_debug_queue_dump(char *path, int count, int onoff)
938 {
939         pthread_mutex_lock(&gLock);
940         _tbm_set_last_result(TBM_ERROR_NONE);
941
942         if (onoff == 0) {
943                 TBM_DBG("count=%d onoff=%d\n", count, onoff);
944                 b_dump_queue = 0;
945                 tbm_surface_internal_dump_end();
946         } else {
947                 int w, h;
948
949                 if (path == NULL) {
950                         TBM_ERR("path is null");
951                         pthread_mutex_unlock(&gLock);
952                         return 0;
953                 }
954                 TBM_DBG("path=%s count=%d onoff=%d\n", path, count, onoff);
955
956                 if (_tbm_util_get_max_surface_size(&w, &h) == 0) {
957                         TBM_ERR("Fail to get tbm_surface size.\n");
958                         pthread_mutex_unlock(&gLock);
959                         return 0;
960                 }
961
962                 tbm_surface_internal_dump_with_scale_start(path, w, h, count, scale_factor);
963                 scale_factor = 0;
964
965                 b_dump_queue = 1;
966         }
967
968         pthread_mutex_unlock(&gLock);
969
970         return 1;
971 }
972
973 int
974 tbm_bufmgr_debug_dump_all(char *path)
975 {
976         int w, h, count = 0;
977         tbm_surface_h surface = NULL;
978
979         pthread_mutex_lock(&gLock);
980         _tbm_set_last_result(TBM_ERROR_NONE);
981
982         if (!path) {
983                 TBM_ERR("path is null.\n");
984                 pthread_mutex_unlock(&gLock);
985                 return 0;
986         }
987
988         TBM_DBG("path=%s\n", path);
989
990         count = _tbm_util_get_max_surface_size(&w, &h);
991         if (count == 0) {
992                 TBM_ERR("No tbm_surface.\n");
993                 pthread_mutex_unlock(&gLock);
994                 return 0;
995         }
996
997         tbm_surface_internal_dump_with_scale_start(path, w, h, count, scale_factor);
998         scale_factor = 0;
999
1000         LIST_FOR_EACH_ENTRY(surface, &gBufMgr->surf_list, item_link)
1001                 tbm_surface_internal_dump_buffer(surface, "dump_all");
1002
1003         tbm_surface_internal_dump_end();
1004
1005         pthread_mutex_unlock(&gLock);
1006
1007         return 1;
1008 }
1009
1010 /* internal function */
1011 tbm_bufmgr
1012 _tbm_bufmgr_get_bufmgr(void)
1013 {
1014         return gBufMgr;
1015 }
1016
1017 int
1018 tbm_bufmgr_bind_native_display(tbm_bufmgr bufmgr, void *native_display)
1019 {
1020         int ret;
1021         tbm_error_e error;
1022
1023         _tbm_bufmgr_mutex_lock();
1024         _tbm_set_last_result(TBM_ERROR_NONE);
1025
1026         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1027
1028         if (bufmgr->backend_module_data) {
1029                 if (!bufmgr->bufmgr_func->bufmgr_bind_native_display) {
1030                         TBM_WRN("skip: tbm_bufmgr(%p) native_display(%p)\n",
1031                                         bufmgr, native_display);
1032                         _tbm_set_last_result(TBM_ERROR_NOT_SUPPORTED);
1033                         _tbm_bufmgr_mutex_unlock();
1034                         return 1;
1035                 }
1036
1037                 error = bufmgr->bufmgr_func->bufmgr_bind_native_display(bufmgr->bufmgr_data, (tbm_native_display *)native_display);
1038                 if (error != TBM_ERROR_NONE) {
1039                         TBM_ERR("error: tbm_bufmgr(%p) native_display(%p) error(%d)\n",
1040                                         bufmgr, native_display, error);
1041                         _tbm_set_last_result(error);
1042                         _tbm_bufmgr_mutex_unlock();
1043                         return 0;
1044                 }
1045                 ret = 1;
1046         } else {
1047                 if (!bufmgr->backend->bufmgr_bind_native_display) {
1048                         TBM_WRN("skip: tbm_bufmgr(%p) native_display(%p)\n",
1049                                         bufmgr, native_display);
1050                         _tbm_set_last_result(TBM_ERROR_NOT_SUPPORTED);
1051                         _tbm_bufmgr_mutex_unlock();
1052                         return 1;
1053                 }
1054
1055                 ret = bufmgr->backend->bufmgr_bind_native_display(bufmgr, native_display);
1056                 if (!ret) {
1057                         TBM_ERR("error: tbm_bufmgr(%p) native_display(%p)\n",
1058                                         bufmgr, native_display);
1059                         _tbm_set_last_result(TBM_ERROR_INVALID_OPERATION);
1060                         _tbm_bufmgr_mutex_unlock();
1061                         return 0;
1062                 }
1063         }
1064
1065         TBM_INFO("tbm_bufmgr(%p) native_display(%p)\n", bufmgr, native_display);
1066
1067         _tbm_bufmgr_mutex_unlock();
1068
1069         return 1;
1070 }
1071
1072 tbm_bufmgr
1073 tbm_bufmgr_server_init(void)
1074 {
1075         tbm_bufmgr bufmgr;
1076
1077         bufmgr = _tbm_bufmgr_init(-1, 1);
1078
1079         return bufmgr;
1080 }
1081
1082 int
1083 tbm_bufmgr_set_bo_lock_type(tbm_bufmgr bufmgr, tbm_bufmgr_bo_lock_type bo_lock_type)
1084 {
1085         _tbm_bufmgr_mutex_lock();
1086         _tbm_set_last_result(TBM_ERROR_NONE);
1087
1088         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1089         TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, 0);
1090
1091         pthread_mutex_lock(&gLock);
1092         gBufMgr->bo_lock_type = bo_lock_type;
1093         pthread_mutex_unlock(&gLock);
1094
1095         TBM_INFO("The bo_lock_type of the bo is %d\n", bo_lock_type);
1096
1097         _tbm_bufmgr_mutex_unlock();
1098
1099         return 1;
1100 }
1101
1102
1103 int tbm_bufmgr_get_fd_limit(void)
1104 {
1105         struct rlimit lim;
1106
1107         if (getrlimit(RLIMIT_NOFILE, &lim))
1108                 return 1024;
1109
1110         return (int)lim.rlim_cur;
1111 }
1112
1113 tbm_bufmgr tbm_bufmgr_get(void)
1114 {
1115         return gBufMgr;
1116 }
1117 /* LCOV_EXCL_STOP */