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