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