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