tbm_bufmgr: use syscall instead getpid
[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 static 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 static 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 static 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
374         return 1;
375
376 err:
377         if (bufmgr_data)
378                 bufmgr->backend_module_data->deinit(bufmgr_data);
379         if (module_data)
380                 dlclose(module_data);
381
382         return 0;
383 }
384
385 static int
386 _tbm_bufmgr_load_module(tbm_bufmgr bufmgr, int fd, const char *file)
387 {
388         char path[PATH_MAX] = {0, };
389         TBMModuleVersionInfo *vers;
390         TBMModuleData *initdata;
391         ModuleInitProc init;
392         void *module_data;
393
394         snprintf(path, sizeof(path), BUFMGR_MODULE_DIR "/%s", file);
395
396         module_data = dlopen(path, RTLD_LAZY);
397         if (!module_data) {
398                 TBM_ERR("failed to load module: %s(%s)\n", dlerror(), file);
399                 return 0;
400         }
401
402         initdata = dlsym(module_data, "tbmModuleData");
403         if (!initdata) {
404                 TBM_ERR("Error: module does not have data object.\n");
405                 goto err;
406         }
407
408         vers = initdata->vers;
409         if (!vers) {
410                 TBM_ERR("Error: module does not supply version information.\n");
411                 goto err;
412         }
413
414         init = initdata->init;
415         if (!init) {
416                 TBM_ERR("Error: module does not supply init symbol.\n");
417                 goto err;
418         }
419
420         if (!_check_version(vers)) {
421                 TBM_ERR("Fail to check version.\n");
422                 goto err;
423         }
424
425         if (!init(bufmgr, fd)) {
426                 TBM_ERR("Fail to init module(%s)\n", file);
427                 goto err;
428         }
429
430         if (!bufmgr->backend || !bufmgr->backend->priv) {
431                 TBM_ERR("Error: module(%s) wrong operation. Check backend or backend's priv.\n", file);
432                 goto err;
433         }
434
435         bufmgr->module_data = module_data;
436
437         TBM_DBG("Success to load module(%s)\n", file);
438
439         return 1;
440
441 err:
442         dlclose(module_data);
443         return 0;
444 }
445
446 static int
447 _tbm_load_module(tbm_bufmgr bufmgr, int fd)
448 {
449         struct dirent **namelist;
450         int ret = 0, n;
451
452         /* try to load the new backend module */
453         ret = _tbm_backend_load_module(bufmgr, DEFAULT_LIB);
454         if (ret)
455                 return 1;
456
457         /* try to load the old(deprecated) backend mdoule */
458         ret = _tbm_bufmgr_load_module(bufmgr, fd, DEFAULT_LIB);
459         if (ret)
460                 return 1;
461
462         /* load bufmgr priv from configured path */
463         n = scandir(BUFMGR_MODULE_DIR, &namelist, 0, alphasort);
464         if (n < 0) {
465                 TBM_ERR("no files : %s\n", BUFMGR_MODULE_DIR);
466                 return 0;
467         }
468
469         while (n--) {
470                 if (!ret && strstr(namelist[n]->d_name, PREFIX_LIB)) {
471                         const char *p = strstr(namelist[n]->d_name, SUFFIX_LIB);
472
473                         if (p && !strcmp(p, SUFFIX_LIB)) {
474                                 ret = _tbm_backend_load_module(bufmgr, namelist[n]->d_name);
475                                 if (!ret)
476                                         ret = _tbm_bufmgr_load_module(bufmgr, fd,
477                                                                         namelist[n]->d_name);
478                         }
479                 }
480
481                 free(namelist[n]);
482         }
483
484         free(namelist);
485
486         return ret;
487 }
488 /* LCOV_EXCL_STOP */
489
490 static tbm_bufmgr
491 _tbm_bufmgr_init(int fd, int server)
492 {
493 #ifdef TBM_BUFMGR_INIT_TIME
494         struct timeval start_tv, end_tv;
495 #endif
496         char *env;
497
498 #ifdef TBM_BUFMGR_INIT_TIME
499         /* get the start tv */
500         gettimeofday(&start_tv, NULL);
501 #endif
502
503         /* LCOV_EXCL_START */
504 #ifdef HAVE_DLOG
505         env = getenv("TBM_DLOG");
506         if (env) {
507                 bDlog = atoi(env);
508                 TBM_DBG("TBM_DLOG=%s\n", env);
509         } else
510                 bDlog = 1;
511 #endif
512
513 #ifdef TRACE
514         env = getenv("TBM_TRACE");
515         if (env) {
516                 trace_mask = atoi(env);
517                 TBM_DBG("TBM_TRACE=%s\n", env);
518         } else
519                 trace_mask = 0;
520 #endif
521
522         pthread_mutex_lock(&gLock);
523
524         _tbm_set_last_result(TBM_ERROR_NONE);
525
526         if (fd >= 0) {
527                 TBM_WRN("!!!!!WARNING:: The tbm_bufmgr_init DOSE NOT use argument fd ANYMORE.\n");
528                 TBM_WRN("!!!!!WARNING:: IT WILL BE CHANGED like tbm_bufmgr_init(int fd) --> tbm_bufmgr_init(void).\n");
529         }
530
531
532         /* initialize buffer manager */
533         if (gBufMgr) {
534                 gBufMgr->ref_count++;
535                 TBM_DBG("reuse  tbm_bufmgr(%p) ref_count(%d) fd(%d)\n", gBufMgr, gBufMgr->ref_count, gBufMgr->fd);
536                 pthread_mutex_unlock(&gLock);
537                 return gBufMgr;
538         }
539
540         TBM_DBG("bufmgr init\n");
541
542         /* allocate bufmgr */
543         gBufMgr = calloc(1, sizeof(struct _tbm_bufmgr));
544         if (!gBufMgr) {
545                 TBM_ERR("error: fail to alloc bufmgr fd(%d)\n", fd);
546                 _tbm_set_last_result(TBM_ERROR_OUT_OF_MEMORY);
547                 pthread_mutex_unlock(&gLock);
548                 return NULL;
549         }
550
551         gBufMgr->fd = fd;
552
553         /* set the display_server flag before loading the backend module */
554         if (server) {
555                 TBM_INFO("The tbm_bufmgr(%p) is used by display server. Need to bind the native_display.\n", gBufMgr);
556                 gBufMgr->display_server = 1;
557         }
558
559         /* load bufmgr priv from env */
560         if (!_tbm_load_module(gBufMgr, gBufMgr->fd)) {
561                 TBM_ERR("error : Fail to load bufmgr backend\n");
562                 _tbm_set_last_result(TBM_ERROR_INVALID_OPERATION);
563                 free(gBufMgr);
564                 gBufMgr = NULL;
565                 pthread_mutex_unlock(&gLock);
566                 return NULL;
567
568         }
569         /* LCOV_EXCL_STOP */
570
571         gBufMgr->ref_count = 1;
572
573         TBM_INFO("create tizen bufmgr:%p ref_count:%d\n",
574             gBufMgr, gBufMgr->ref_count);
575
576         /* setup the bo_lock_type */
577         env = getenv("BUFMGR_LOCK_TYPE");
578         if (env && !strcmp(env, "always"))
579                 gBufMgr->bo_lock_type = TBM_BUFMGR_BO_LOCK_TYPE_ALWAYS;
580         else if (env && !strcmp(env, "none"))
581                 gBufMgr->bo_lock_type = TBM_BUFMGR_BO_LOCK_TYPE_NEVER;
582         else if (env && !strcmp(env, "once"))
583                 gBufMgr->bo_lock_type = TBM_BUFMGR_BO_LOCK_TYPE_ONCE;
584         else
585                 gBufMgr->bo_lock_type = TBM_BUFMGR_BO_LOCK_TYPE_ALWAYS;
586
587         TBM_DBG("BUFMGR_LOCK_TYPE=%s\n", env ? env : "default:once");
588
589         /* intialize bo_list */
590         LIST_INITHEAD(&gBufMgr->bo_list);
591
592         /* intialize surf_list */
593         LIST_INITHEAD(&gBufMgr->surf_list);
594
595         /* intialize surf_queue_list */
596         LIST_INITHEAD(&gBufMgr->surf_queue_list);
597
598         /* intialize debug_key_list */
599         LIST_INITHEAD(&gBufMgr->debug_key_list);
600
601 #ifdef TBM_BUFMGR_INIT_TIME
602         /* get the end tv */
603         gettimeofday(&end_tv, NULL);
604         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)));
605 #endif
606
607         pthread_mutex_unlock(&gLock);
608
609         return gBufMgr;
610 }
611
612 tbm_bufmgr
613 tbm_bufmgr_init(int fd)
614 {
615         tbm_bufmgr bufmgr;
616
617         bufmgr = _tbm_bufmgr_init(fd, 0);
618
619         return bufmgr;
620 }
621
622 void
623 tbm_bufmgr_deinit(tbm_bufmgr bufmgr)
624 {
625         TBM_RETURN_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr));
626
627         _tbm_bufmgr_mutex_lock();
628         pthread_mutex_lock(&gLock);
629         _tbm_set_last_result(TBM_ERROR_NONE);
630
631         if (!gBufMgr) {
632                 TBM_ERR("gBufmgr already destroy: bufmgr:%p\n", bufmgr);
633                 pthread_mutex_unlock(&gLock);
634                 _tbm_bufmgr_mutex_unlock();
635                 return;
636         }
637
638         bufmgr->ref_count--;
639         if (bufmgr->ref_count > 0) {
640                 TBM_DBG("reduce a ref_count(%d) of tbm_bufmgr(%p)\n", bufmgr->ref_count, bufmgr);
641                 pthread_mutex_unlock(&gLock);
642                 _tbm_bufmgr_mutex_unlock();
643                 return;
644         }
645
646         /* destroy bo_list */
647         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
648                 tbm_bo bo = NULL, tmp;
649
650                 LIST_FOR_EACH_ENTRY_SAFE(bo, tmp, &bufmgr->bo_list, item_link) {
651                         TBM_ERR("Un-freed bo(%p, ref:%d)\n", bo, bo->ref_cnt);
652                         _tbm_bo_free(bo);
653                 }
654                 LIST_DELINIT(&bufmgr->bo_list);
655         }
656
657         /* destroy surf_list */
658         if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
659                 tbm_surface_h surf = NULL, tmp;
660
661                 LIST_FOR_EACH_ENTRY_SAFE(surf, tmp, &bufmgr->surf_list, item_link) {
662                         TBM_ERR("Un-freed surf(%p, ref:%d)\n", surf, surf->refcnt);
663                         tbm_surface_destroy(surf);
664                 }
665                 LIST_DELINIT(&bufmgr->surf_list);
666         }
667
668         if (bufmgr->backend_module_data) {
669                 /* deinit and backend destroys the backend func and data */
670                 bufmgr->backend_module_data->deinit(bufmgr->bufmgr_data);
671                 bufmgr->bo_func = NULL;
672                 bufmgr->bufmgr_func = NULL;
673                 bufmgr->bufmgr_data = NULL;
674                 bufmgr->backend_module_data = NULL;
675         } else {
676                 /* destroy bufmgr priv */
677                 bufmgr->backend->bufmgr_deinit(bufmgr->backend->priv);
678                 bufmgr->backend->priv = NULL;
679                 tbm_backend_free(bufmgr->backend);
680                 bufmgr->backend = NULL;
681         }
682
683         TBM_INFO("destroy tbm_bufmgr(%p)\n", bufmgr);
684
685         dlclose(bufmgr->module_data);
686
687         if (bufmgr->fd > 0)
688                 close(bufmgr->fd);
689
690         free(bufmgr);
691         gBufMgr = NULL;
692
693         pthread_mutex_unlock(&gLock);
694         _tbm_bufmgr_mutex_unlock();
695 }
696
697 unsigned int
698 tbm_bufmgr_get_capability(tbm_bufmgr bufmgr)
699 {
700         unsigned int capabilities = TBM_BUFMGR_CAPABILITY_NONE;
701
702         _tbm_bufmgr_mutex_lock();
703         _tbm_set_last_result(TBM_ERROR_NONE);
704
705         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), TBM_BUFMGR_CAPABILITY_NONE);
706         TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, TBM_BUFMGR_CAPABILITY_NONE);
707
708         capabilities = bufmgr->capabilities;
709
710         _tbm_bufmgr_mutex_unlock();
711
712         return capabilities;
713 }
714
715 /* LCOV_EXCL_START */
716 char *
717 tbm_bufmgr_debug_tbm_info_get(tbm_bufmgr bufmgr)
718 {
719         char app_name[255] = {0,}, title[512] = {0,};
720         tbm_surface_debug_data *debug_old_data = NULL;
721         char *str;
722         int len = 1024*4;
723         int c = 0;
724         int size;
725         tbm_error_e error;
726         long pid = 0;
727
728         pthread_mutex_lock(&gLock);
729         _tbm_set_last_result(TBM_ERROR_NONE);
730
731         if (!TBM_BUFMGR_IS_VALID(bufmgr) || (bufmgr != gBufMgr)) {
732                 TBM_ERR("invalid bufmgr\n");
733                 _tbm_set_last_result(TBM_ERROR_INVALID_PARAMETER);
734                 pthread_mutex_unlock(&gLock);
735                 return NULL;
736         }
737
738         str = malloc(len);
739         if (!str) {
740                 TBM_ERR("Fail to allocate the string.\n");
741                 _tbm_set_last_result(TBM_ERROR_OUT_OF_MEMORY);
742                 pthread_mutex_unlock(&gLock);
743                 return NULL;
744         }
745
746         TBM_SNRPRINTF(str, len, c, "\n");
747         pid = syscall(SYS_getpid);
748         _tbm_util_get_appname_from_pid(pid, app_name);
749         _tbm_util_get_appname_brief(app_name);
750         TBM_SNRPRINTF(str, len, c, "============TBM DEBUG: %s(%ld)===========================\n",
751                   app_name, pid);
752
753         snprintf(title, 255, "%s", "no  surface     refcnt  width  height  bpp  size    n_b  n_p  flags  format    app_name       ");
754
755         if (!LIST_IS_EMPTY(&bufmgr->debug_key_list)) {
756                 LIST_FOR_EACH_ENTRY(debug_old_data, &bufmgr->debug_key_list, item_link) {
757                         strncat(title, "  ", MAX_SIZE_N(title));
758                         strncat(title, debug_old_data->key, MAX_SIZE_N(title));
759                 }
760         }
761
762         TBM_SNRPRINTF(str, len, c, "[tbm_surface information]\n");
763         TBM_SNRPRINTF(str, len, c, "%s\n", title);
764
765         /* show the tbm_surface information in surf_list */
766         if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
767                 tbm_surface_h surf = NULL;
768                 int surf_cnt = 0;
769
770                 LIST_FOR_EACH_ENTRY(surf, &bufmgr->surf_list, item_link) {
771                         char data[512] = {0,};
772                         long surf_pid = 0;
773                         int i;
774
775                         surf_pid = _tbm_surface_internal_get_debug_pid(surf);
776                         if (!surf_pid) {
777                                 /* if pid is null, set the self_pid */
778                                 surf_pid = syscall(SYS_getpid);;
779                         }
780
781                         memset(app_name, 0x0, 255 * sizeof(char));
782                         _tbm_util_get_appname_from_pid(surf_pid, app_name);
783                         _tbm_util_get_appname_brief(app_name);
784
785                         snprintf(data, 255, "%-2d  %-9p    %-4d  %-5u  %-6u  %-3u  %-6u   %-2d   %-2d    %-3d  %-8s  %-15s",
786                                   ++surf_cnt,
787                                   surf,
788                                   surf->refcnt,
789                                   surf->info.width,
790                                   surf->info.height,
791                                   surf->info.bpp,
792                                   surf->info.size / 1024,
793                                   surf->num_bos,
794                                   surf->num_planes,
795                                   surf->flags,
796                                   _tbm_surface_internal_format_to_str(surf->info.format) + 11,
797                                   app_name);
798
799                         if (!LIST_IS_EMPTY(&bufmgr->debug_key_list)) {
800                                 LIST_FOR_EACH_ENTRY(debug_old_data, &bufmgr->debug_key_list, item_link) {
801                                         char *value;
802
803                                         strncat(data, "  ", MAX_SIZE_N(title));
804
805                                         value = _tbm_surface_internal_get_debug_data(surf, debug_old_data->key);
806                                         if (value)
807                                                 strncat(data, value, MAX_SIZE_N(title));
808                                         else
809                                                 strncat(data, "none", MAX_SIZE_N(title));
810                                 }
811                         }
812                         TBM_SNRPRINTF(str, len, c, "%s\n", data);
813
814                         for (i = 0; i < surf->num_bos; i++) {
815                                 if (bufmgr->backend_module_data) {
816                                         size = bufmgr->bo_func->bo_get_size(surf->bos[i]->bo_data, &error);
817                                         if (error != TBM_ERROR_NONE)
818                                                 TBM_WRN("fail to get the size of bo.");
819                                 } else
820                                         size = bufmgr->backend->bo_size(surf->bos[i]);
821                                 TBM_SNRPRINTF(str, len, c, " bo:%-12p  %-26d%-10d\n",
822                                           surf->bos[i],
823                                           surf->bos[i]->ref_cnt,
824                                           size / 1024);
825                         }
826                 }
827         } else
828                 TBM_SNRPRINTF(str, len, c, " no tbm_surfaces.\n");
829         TBM_SNRPRINTF(str, len, c, "\n");
830
831         TBM_SNRPRINTF(str, len, c, "[tbm_bo information]\n");
832         TBM_SNRPRINTF(str, len, c, "no  bo          refcnt  size    lock_cnt  map_cnt  flags  surface     name\n");
833
834         /* show the tbm_bo information in bo_list */
835         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
836                 int bo_cnt = 0;
837                 tbm_bo bo = NULL;
838                 tbm_key key = 0;
839
840                 LIST_FOR_EACH_ENTRY(bo, &bufmgr->bo_list, item_link) {
841                         if (bufmgr->backend_module_data) {
842                                 size = bufmgr->bo_func->bo_get_size(bo->bo_data, &error);
843                                 if (error != TBM_ERROR_NONE)
844                                         TBM_WRN("fail to get the size of bo.");
845                                 key = bufmgr->bo_func->bo_export_key(bo->bo_data, &error);
846                                 if (error != TBM_ERROR_NONE)
847                                         TBM_WRN("fail to get the tdm_key of bo.");
848                         } else {
849                                 size = bufmgr->backend->bo_size(bo);
850                                 key = bufmgr->backend->bo_export(bo);
851                         }
852                         TBM_SNRPRINTF(str, len, c, "%-4d%-11p   %-4d  %-6d     %-5d     %-4u    %-3d  %-11p  %-4d\n",
853                                   ++bo_cnt,
854                                   bo,
855                                   bo->ref_cnt,
856                                   size / 1024,
857                                   bo->lock_cnt,
858                                   bo->map_cnt,
859                                   bo->flags,
860                                   bo->surface,
861                                   key);
862                 }
863         } else
864                 TBM_SNRPRINTF(str, len, c, "no tbm_bos.\n");
865         TBM_SNRPRINTF(str, len, c, "\n");
866
867         TBM_SNRPRINTF(str, len, c, "===============================================================\n");
868
869         pthread_mutex_unlock(&gLock);
870
871         return str;
872 }
873
874 void
875 tbm_bufmgr_debug_show(tbm_bufmgr bufmgr)
876 {
877         char * str;
878         str = tbm_bufmgr_debug_tbm_info_get(bufmgr);
879         if (str) {
880                 TBM_DBG("       %s", str);
881                 free(str);
882         }
883 }
884
885 void
886 tbm_bufmgr_debug_trace(tbm_bufmgr bufmgr, int onoff)
887 {
888         _tbm_bufmgr_mutex_lock();
889         _tbm_set_last_result(TBM_ERROR_NONE);
890
891         TBM_BUFMGR_RETURN_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr));
892         TBM_BUFMGR_RETURN_IF_FAIL(bufmgr == gBufMgr);
893
894 #ifdef TRACE
895         TBM_LOG_D("bufmgr=%p onoff=%d\n", bufmgr, onoff);
896         bTrace = onoff;
897 #endif
898
899         _tbm_bufmgr_mutex_unlock();
900 }
901
902 void
903 tbm_bufmgr_debug_set_trace_mask(tbm_bufmgr bufmgr, tbm_bufmgr_debug_trace_mask mask, int set)
904 {
905         _tbm_bufmgr_mutex_lock();
906         _tbm_set_last_result(TBM_ERROR_NONE);
907
908         TBM_BUFMGR_RETURN_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr));
909         TBM_BUFMGR_RETURN_IF_FAIL(bufmgr == gBufMgr);
910
911         if (set == 1) {
912                 trace_mask |= mask;
913
914                 TBM_INFO("bufmgr=%p sets the trace_mask=%d\n", bufmgr, mask);
915                 if (trace_mask&TBM_BUFGMR_DEBUG_TRACE_BO)
916                         TBM_INFO("  TBM_BUFGMR_DEBUG_TRACE_BO");
917                 if (trace_mask&TBM_BUFGMR_DEBUG_TRACE_SURFACE_INTERNAL)
918                         TBM_INFO("  TBM_BUFGMR_DEBUG_TRACE_SURFACE_INTERNAL");
919                 if (trace_mask&TBM_BUFGMR_DEBUG_TRACE_SURFACE)
920                         TBM_INFO("  TBM_BUFGMR_DEBUG_TRACE_SURFACE");
921                 if (trace_mask&TBM_BUFGMR_DEBUG_TRACE_SURFACE_QUEUE)
922                         TBM_INFO("  TBM_BUFGMR_DEBUG_TRACE_SURFACE_QUEUE");
923         } else if (set == 0) {
924                 trace_mask &= ~mask;
925
926                 TBM_INFO("bufmgr=%p unsets the trace_mask=%d\n", bufmgr, mask);
927                 if (trace_mask&TBM_BUFGMR_DEBUG_TRACE_BO)
928                         TBM_INFO("  TBM_BUFGMR_DEBUG_TRACE_BO");
929                 if (trace_mask&TBM_BUFGMR_DEBUG_TRACE_SURFACE_INTERNAL)
930                         TBM_INFO("  TBM_BUFGMR_DEBUG_TRACE_SURFACE_INTERNAL");
931                 if (trace_mask&TBM_BUFGMR_DEBUG_TRACE_SURFACE)
932                         TBM_INFO("  TBM_BUFGMR_DEBUG_TRACE_SURFACE");
933                 if (trace_mask&TBM_BUFGMR_DEBUG_TRACE_SURFACE_QUEUE)
934                         TBM_INFO("  TBM_BUFGMR_DEBUG_TRACE_SURFACE_QUEUE");
935         } else {
936                 TBM_WRN("set value is wrong.(set=%d)", set);
937         }
938
939         _tbm_bufmgr_mutex_unlock();
940 }
941
942 void
943 tbm_bufmgr_debug_dump_set_scale(double scale)
944 {
945         pthread_mutex_lock(&gLock);
946         _tbm_set_last_result(TBM_ERROR_NONE);
947         scale_factor = scale;
948         pthread_mutex_unlock(&gLock);
949 }
950
951 int
952 tbm_bufmgr_debug_get_ref_count(void)
953 {
954         int refcnt;
955
956         pthread_mutex_lock(&gLock);
957
958         _tbm_set_last_result(TBM_ERROR_NONE);
959
960         refcnt = (gBufMgr) ? gBufMgr->ref_count : 0;
961
962         pthread_mutex_unlock(&gLock);
963
964         return refcnt;
965 }
966
967 int
968 tbm_bufmgr_debug_queue_dump(char *path, int count, int onoff)
969 {
970         pthread_mutex_lock(&gLock);
971         _tbm_set_last_result(TBM_ERROR_NONE);
972
973         if (onoff == 0) {
974                 TBM_DBG("count=%d onoff=%d\n", count, onoff);
975                 b_dump_queue = 0;
976                 tbm_surface_internal_dump_end();
977         } else {
978                 int w, h;
979
980                 if (path == NULL) {
981                         TBM_ERR("path is null");
982                         pthread_mutex_unlock(&gLock);
983                         return 0;
984                 }
985                 TBM_DBG("path=%s count=%d onoff=%d\n", path, count, onoff);
986
987                 if (_tbm_util_get_max_surface_size(&w, &h) == 0) {
988                         TBM_ERR("Fail to get tbm_surface size.\n");
989                         pthread_mutex_unlock(&gLock);
990                         return 0;
991                 }
992
993                 tbm_surface_internal_dump_with_scale_start(path, w, h, count, scale_factor);
994                 scale_factor = 0;
995
996                 b_dump_queue = 1;
997         }
998
999         pthread_mutex_unlock(&gLock);
1000
1001         return 1;
1002 }
1003
1004 int
1005 tbm_bufmgr_debug_dump_all(char *path)
1006 {
1007         int w, h, count = 0;
1008         tbm_surface_h surface = NULL;
1009
1010         pthread_mutex_lock(&gLock);
1011         _tbm_set_last_result(TBM_ERROR_NONE);
1012
1013         if (!path) {
1014                 TBM_ERR("path is null.\n");
1015                 pthread_mutex_unlock(&gLock);
1016                 return 0;
1017         }
1018
1019         TBM_DBG("path=%s\n", path);
1020
1021         count = _tbm_util_get_max_surface_size(&w, &h);
1022         if (count == 0) {
1023                 TBM_ERR("No tbm_surface.\n");
1024                 pthread_mutex_unlock(&gLock);
1025                 return 0;
1026         }
1027
1028         tbm_surface_internal_dump_with_scale_start(path, w, h, count, scale_factor);
1029         scale_factor = 0;
1030
1031         LIST_FOR_EACH_ENTRY(surface, &gBufMgr->surf_list, item_link)
1032                 tbm_surface_internal_dump_buffer(surface, "dump_all");
1033
1034         tbm_surface_internal_dump_end();
1035
1036         pthread_mutex_unlock(&gLock);
1037
1038         return 1;
1039 }
1040
1041 /* internal function */
1042 tbm_bufmgr
1043 _tbm_bufmgr_get_bufmgr(void)
1044 {
1045         return gBufMgr;
1046 }
1047
1048 int
1049 tbm_bufmgr_bind_native_display(tbm_bufmgr bufmgr, void *native_display)
1050 {
1051         int ret;
1052         tbm_error_e error;
1053
1054         _tbm_bufmgr_mutex_lock();
1055         _tbm_set_last_result(TBM_ERROR_NONE);
1056
1057         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1058
1059         if (bufmgr->backend_module_data) {
1060                 if (!bufmgr->bufmgr_func->bufmgr_bind_native_display) {
1061                         TBM_WRN("skip: tbm_bufmgr(%p) native_display(%p)\n",
1062                                         bufmgr, native_display);
1063                         _tbm_set_last_result(TBM_ERROR_NOT_SUPPORTED);
1064                         _tbm_bufmgr_mutex_unlock();
1065                         return 1;
1066                 }
1067
1068                 error = bufmgr->bufmgr_func->bufmgr_bind_native_display(bufmgr->bufmgr_data, (tbm_native_display *)native_display);
1069                 if (error != TBM_ERROR_NONE) {
1070                         TBM_ERR("error: tbm_bufmgr(%p) native_display(%p) error(%d)\n",
1071                                         bufmgr, native_display, error);
1072                         _tbm_set_last_result(error);
1073                         _tbm_bufmgr_mutex_unlock();
1074                         return 0;
1075                 }
1076                 ret = 1;
1077         } else {
1078                 if (!bufmgr->backend->bufmgr_bind_native_display) {
1079                         TBM_WRN("skip: tbm_bufmgr(%p) native_display(%p)\n",
1080                                         bufmgr, native_display);
1081                         _tbm_set_last_result(TBM_ERROR_NOT_SUPPORTED);
1082                         _tbm_bufmgr_mutex_unlock();
1083                         return 1;
1084                 }
1085
1086                 ret = bufmgr->backend->bufmgr_bind_native_display(bufmgr, native_display);
1087                 if (!ret) {
1088                         TBM_ERR("error: tbm_bufmgr(%p) native_display(%p)\n",
1089                                         bufmgr, native_display);
1090                         _tbm_set_last_result(TBM_ERROR_INVALID_OPERATION);
1091                         _tbm_bufmgr_mutex_unlock();
1092                         return 0;
1093                 }
1094         }
1095
1096         TBM_INFO("tbm_bufmgr(%p) native_display(%p)\n", bufmgr, native_display);
1097
1098         _tbm_bufmgr_mutex_unlock();
1099
1100         return 1;
1101 }
1102
1103 tbm_bufmgr
1104 tbm_bufmgr_server_init(void)
1105 {
1106         tbm_bufmgr bufmgr;
1107
1108         bufmgr = _tbm_bufmgr_init(-1, 1);
1109
1110         return bufmgr;
1111 }
1112
1113 int
1114 tbm_bufmgr_set_bo_lock_type(tbm_bufmgr bufmgr, tbm_bufmgr_bo_lock_type bo_lock_type)
1115 {
1116         _tbm_bufmgr_mutex_lock();
1117         _tbm_set_last_result(TBM_ERROR_NONE);
1118
1119         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1120         TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, 0);
1121
1122         pthread_mutex_lock(&gLock);
1123         gBufMgr->bo_lock_type = bo_lock_type;
1124         pthread_mutex_unlock(&gLock);
1125
1126         TBM_INFO("The bo_lock_type of the bo is %d\n", bo_lock_type);
1127
1128         _tbm_bufmgr_mutex_unlock();
1129
1130         return 1;
1131 }
1132
1133
1134 int tbm_bufmgr_get_fd_limit(void)
1135 {
1136         struct rlimit lim;
1137
1138         if (getrlimit(RLIMIT_NOFILE, &lim))
1139                 return 1024;
1140
1141         return (int)lim.rlim_cur;
1142 }
1143
1144 tbm_bufmgr tbm_bufmgr_get(void)
1145 {
1146         return gBufMgr;
1147 }
1148 /* LCOV_EXCL_STOP */