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