1 /**************************************************************************
5 Copyright 2012 Samsung Electronics co., Ltd. All Rights Reserved.
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>
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:
18 The above copyright notice and this permission notice (including the
19 next paragraph) shall be included in all copies or substantial portions
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.
30 **************************************************************************/
34 #include "tbm_bufmgr.h"
35 #include "tbm_bufmgr_int.h"
36 #include "tbm_bufmgr_backend.h"
54 static pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
55 static pthread_mutex_t tbm_bufmgr_lock = PTHREAD_MUTEX_INITIALIZER;
56 static __thread tbm_error_e tbm_last_error = TBM_ERROR_NONE;
58 static void _tbm_bufmgr_mutex_unlock(void);
60 //#define TBM_BUFMGR_INIT_TIME
62 #define PREFIX_LIB "libtbm_"
63 #define SUFFIX_LIB ".so"
64 #define DEFAULT_LIB PREFIX_LIB"default"SUFFIX_LIB
66 /* values to indicate unspecified fields in XF86ModReqInfo. */
67 #define MAJOR_UNSPEC 0xFF
68 #define MINOR_UNSPEC 0xFF
69 #define PATCH_UNSPEC 0xFFFF
70 #define ABI_VERS_UNSPEC 0xFFFFFFFF
72 #define MODULE_VERSION_NUMERIC(maj, min, patch) \
73 ((((maj) & 0xFF) << 24) | (((min) & 0xFF) << 16) | (patch & 0xFFFF))
74 #define GET_MODULE_MAJOR_VERSION(vers) (((vers) >> 24) & 0xFF)
75 #define GET_MODULE_MINOR_VERSION(vers) (((vers) >> 16) & 0xFF)
76 #define GET_MODULE_PATCHLEVEL(vers) ((vers) & 0xFFFF)
79 #define TBM_BUFMGR_RETURN_IF_FAIL(cond) {\
81 TBM_LOG_E("'%s' failed.\n", #cond);\
82 _tbm_bufmgr_mutex_unlock();\
87 #define TBM_BUFMGR_RETURN_VAL_IF_FAIL(cond, val) {\
89 TBM_LOG_E("'%s' failed.\n", #cond);\
90 _tbm_bufmgr_mutex_unlock();\
102 _tbm_set_last_result(tbm_error_e err)
104 tbm_last_error = err;
108 _tbm_bufmgr_mutex_init(void)
110 static bool tbm_bufmgr_mutex_init = false;
112 if (tbm_bufmgr_mutex_init)
115 if (pthread_mutex_init(&tbm_bufmgr_lock, NULL)) {
116 TBM_LOG_E("fail: tbm_bufmgr mutex init\n");
120 tbm_bufmgr_mutex_init = true;
126 _tbm_bufmgr_mutex_lock(void)
128 if (!_tbm_bufmgr_mutex_init())
131 pthread_mutex_lock(&tbm_bufmgr_lock);
135 _tbm_bufmgr_mutex_unlock(void)
137 pthread_mutex_unlock(&tbm_bufmgr_lock);
140 char * tbm_flag_to_str(int f)
142 static char str[255];
144 if (f == TBM_BO_DEFAULT)
145 snprintf(str, 255, "DEFAULT\n");
147 if (f & TBM_BO_SCANOUT)
148 c = snprintf(&str[c], 255, "SCANOUT,");
149 if (f & TBM_BO_NONCACHABLE)
150 c = snprintf(&str[c], 255, "NONCACHABLE,");
152 c = snprintf(&str[c], 255, "WC");
157 /* LCOV_EXCL_START */
158 static int last_chk_bo_cnt = 0;
160 _tbm_util_check_bo_cnt(tbm_bufmgr bufmgr)
162 if (bufmgr->bo_cnt >= 500 && ((bufmgr->bo_cnt % 20) == 0)) {
163 if (bufmgr->bo_cnt > last_chk_bo_cnt) {
164 TBM_DEBUG("============TBM BO CNT DEBUG: bo_cnt=%d\n", bufmgr->bo_cnt);
165 tbm_bufmgr_debug_show(bufmgr);
166 last_chk_bo_cnt = bufmgr->bo_cnt;
172 _tbm_util_get_max_surface_size(int * w, int * h)
175 tbm_surface_h surface = NULL, tmp = NULL;
176 tbm_surface_info_s info;
184 if (!LIST_IS_EMPTY(&gBufMgr->surf_list)) {
185 LIST_FOR_EACH_ENTRY_SAFE(surface, tmp, &gBufMgr->surf_list, item_link) {
186 if (tbm_surface_get_info(surface, &info) == TBM_SURFACE_ERROR_NONE) {
188 if (*w < info.width) *w = info.width;
189 if (*h < info.height) *h = info.height;
198 _tbm_util_get_appname_brief(char *brief)
202 char temp[255] = {0,};
203 char *saveptr = NULL;
205 token = strtok_r(brief, delim, &saveptr);
207 while (token != NULL) {
208 memset(temp, 0x00, 255 * sizeof(char));
209 strncpy(temp, token, 254 * sizeof(char));
210 token = strtok_r(NULL, delim, &saveptr);
213 snprintf(brief, sizeof(temp), "%s", temp);
217 _tbm_util_get_appname_from_pid(long pid, char *str)
222 char fn_cmdline[255] = {0,};
223 char cmdline[255] = {0,};
225 snprintf(fn_cmdline, sizeof(fn_cmdline), "/proc/%ld/cmdline", app_pid);
227 fp = fopen(fn_cmdline, "r");
229 fprintf(stderr, "cannot file open /proc/%ld/cmdline", app_pid);
233 if (!fgets(cmdline, 255, fp)) {
234 fprintf(stderr, "fail to get appname for pid(%ld)\n", app_pid);
240 len = strlen(cmdline);
242 memset(cmdline, 0x00, 255);
246 snprintf(str, sizeof(cmdline), "%s", cmdline);
251 *user_data_lookup(struct list_head *user_data_list, unsigned long key)
253 tbm_user_data *user_data = NULL;
254 tbm_user_data *old_data = NULL;
256 if (!LIST_IS_EMPTY(user_data_list)) {
257 LIST_FOR_EACH_ENTRY(old_data, user_data_list, item_link) {
258 if (old_data->key == key) {
259 user_data = old_data;
269 *user_data_create(unsigned long key, tbm_data_free data_free_func)
271 tbm_user_data *user_data = NULL;
273 user_data = calloc(1, sizeof(tbm_user_data));
277 user_data->key = key;
278 user_data->free_func = data_free_func;
279 user_data->data = (void *)0;
285 user_data_delete(tbm_user_data *user_data)
287 if (user_data->data && user_data->free_func)
288 user_data->free_func(user_data->data);
290 LIST_DEL(&user_data->item_link);
296 _bo_lock(tbm_bo bo, int device, int opt)
298 tbm_bufmgr bufmgr = bo->bufmgr;
301 if (bufmgr->backend->bo_lock)
302 ret = bufmgr->backend->bo_lock(bo, device, opt);
310 _bo_unlock(tbm_bo bo)
312 tbm_bufmgr bufmgr = bo->bufmgr;
314 if (bufmgr->backend->bo_unlock)
315 bufmgr->backend->bo_unlock(bo);
319 _tbm_bo_lock(tbm_bo bo, int device, int opt)
321 tbm_bufmgr bufmgr = NULL;
330 /* do not try to lock the bo */
331 if (bufmgr->lock_type == LOCK_TRY_NEVER)
334 if (bo->lock_cnt < 0) {
335 TBM_LOG_E("error bo:%p LOCK_CNT=%d\n",
340 if (bufmgr->lock_type == LOCK_TRY_ONCE) {
341 if (bo->lock_cnt == 0) {
342 _tbm_bufmgr_mutex_unlock();
343 ret = _bo_lock(bo, device, opt);
344 _tbm_bufmgr_mutex_lock();
349 } else if (bufmgr->lock_type == LOCK_TRY_ALWAYS) {
350 _tbm_bufmgr_mutex_unlock();
351 ret = _bo_lock(bo, device, opt);
352 _tbm_bufmgr_mutex_lock();
356 TBM_LOG_E("error bo:%p lock_type is wrong.\n",
360 TBM_DBG_LOCK(">> LOCK bo:%p(%d->%d)\n",
361 bo, old, bo->lock_cnt);
367 _tbm_bo_unlock(tbm_bo bo)
369 tbm_bufmgr bufmgr = NULL;
378 /* do not try to unlock the bo */
379 if (bufmgr->lock_type == LOCK_TRY_NEVER)
383 if (bufmgr->lock_type == LOCK_TRY_ONCE) {
384 if (bo->lock_cnt > 0) {
386 if (bo->lock_cnt == 0)
389 } else if (bufmgr->lock_type == LOCK_TRY_ALWAYS) {
390 if (bo->lock_cnt > 0) {
395 TBM_LOG_E("error bo:%p lock_type is wrong.\n",
399 if (bo->lock_cnt < 0)
402 TBM_DBG_LOCK(">> UNLOCK bo:%p(%d->%d)\n",
403 bo, old, bo->lock_cnt);
407 _tbm_bo_is_valid(tbm_bo bo)
409 tbm_bo old_data = NULL, tmp = NULL;
414 if (gBufMgr == NULL) {
415 TBM_LOG_E("error tbm_bufmgr was deinited\n");
419 if (!LIST_IS_EMPTY(&gBufMgr->bo_list)) {
420 LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp, &gBufMgr->bo_list, item_link) {
429 /* LCOV_EXCL_START */
431 _check_version(TBMModuleVersionInfo *data)
436 abimaj = GET_ABI_MAJOR(data->abiversion);
437 abimin = GET_ABI_MINOR(data->abiversion);
439 TBM_DBG("TBM module %s: vendor=\"%s\" ABI=%d,%d\n",
440 data->modname ? data->modname : "UNKNOWN!",
441 data->vendor ? data->vendor : "UNKNOWN!", abimaj, abimin);
443 vermaj = GET_ABI_MAJOR(TBM_ABI_VERSION);
444 vermin = GET_ABI_MINOR(TBM_ABI_VERSION);
446 TBM_DBG("TBM ABI version %d.%d\n",
449 if (abimaj != vermaj) {
450 TBM_LOG_E("TBM module ABI major ver(%d) doesn't match the TBM's ver(%d)\n",
453 } else if (abimin > vermin) {
454 TBM_LOG_E("TBM module ABI minor ver(%d) is newer than the TBM's ver(%d)\n",
462 _tbm_bufmgr_load_module(tbm_bufmgr bufmgr, int fd, const char *file)
464 char path[PATH_MAX] = { 0, };
465 TBMModuleData *initdata = NULL;
468 snprintf(path, sizeof(path), BUFMGR_MODULE_DIR "/%s", file);
470 module_data = dlopen(path, RTLD_LAZY);
472 TBM_LOG_E("failed to load module: %s(%s)\n",
477 initdata = dlsym(module_data, "tbmModuleData");
480 TBMModuleVersionInfo *vers;
482 vers = initdata->vers;
483 init = initdata->init;
486 if (!_check_version(vers)) {
487 dlclose(module_data);
491 TBM_LOG_E("Error: module does not supply version information.\n");
493 dlclose(module_data);
498 if (!init(bufmgr, fd)) {
499 TBM_LOG_E("Fail to init module(%s)\n",
501 dlclose(module_data);
505 if (!bufmgr->backend || !bufmgr->backend->priv) {
506 TBM_LOG_E("Error: module(%s) wrong operation. Check backend or backend's priv.\n",
508 dlclose(module_data);
512 TBM_LOG_E("Error: module does not supply init symbol.\n");
513 dlclose(module_data);
517 TBM_LOG_E("Error: module does not have data object.\n");
518 dlclose(module_data);
522 bufmgr->module_data = module_data;
524 TBM_DBG("Success to load module(%s)\n",
531 _tbm_load_module(tbm_bufmgr bufmgr, int fd)
533 struct dirent **namelist;
534 const char *p = NULL;
538 /* load bufmgr priv from default lib */
539 ret = _tbm_bufmgr_load_module(bufmgr, fd, DEFAULT_LIB);
541 /* load bufmgr priv from configured path */
543 n = scandir(BUFMGR_MODULE_DIR, &namelist, 0, alphasort);
545 TBM_LOG_E("no files : %s\n",
549 if (!ret && strstr(namelist[n]->d_name, PREFIX_LIB)) {
550 p = strstr(namelist[n]->d_name, SUFFIX_LIB);
551 if (p && !strcmp(p, SUFFIX_LIB))
552 ret = _tbm_bufmgr_load_module(bufmgr, fd, namelist[n]->d_name);
565 tbm_bufmgr_init(int fd)
569 #ifdef TBM_BUFMGR_INIT_TIME
570 struct timeval start_tv, end_tv;
573 pthread_mutex_lock(&gLock);
575 #ifdef TBM_BUFMGR_INIT_TIME
576 /* get the start tv */
577 gettimeofday(&start_tv, NULL);
580 /* LCOV_EXCL_START */
582 env = getenv("TBM_DLOG");
585 TBM_LOG_D("TBM_DLOG=%s\n", env);
592 env = getenv("TBM_DEBUG");
595 TBM_LOG_D("TBM_DEBUG=%s\n", env);
602 env = getenv("TBM_TRACE");
605 TBM_LOG_D("TBM_TRACE=%s\n", env);
612 /* initialize buffer manager */
614 gBufMgr->ref_count++;
615 TBM_TRACE("reuse tbm_bufmgr(%p) ref_count(%d) fd(%d)\n", gBufMgr, gBufMgr->ref_count, gBufMgr->fd);
616 pthread_mutex_unlock(&gLock);
620 TBM_DBG("bufmgr init\n");
622 /* allocate bufmgr */
623 gBufMgr = calloc(1, sizeof(struct _tbm_bufmgr));
625 _tbm_set_last_result(TBM_BO_ERROR_HEAP_ALLOC_FAILED);
626 TBM_TRACE("error: fail to alloc bufmgr fd(%d)\n", fd);
627 pthread_mutex_unlock(&gLock);
633 /* load bufmgr priv from env */
634 if (!_tbm_load_module(gBufMgr, gBufMgr->fd)) {
635 /* LCOV_EXCL_START */
636 _tbm_set_last_result(TBM_BO_ERROR_LOAD_MODULE_FAILED);
637 TBM_LOG_E("error : Fail to load bufmgr backend\n");
640 pthread_mutex_unlock(&gLock);
645 /* log for tbm backend_flag */
646 TBM_DBG("backend flag:%x:", gBufMgr->backend->flags);
649 gBufMgr->ref_count = 1;
651 TBM_DBG("create tizen bufmgr:%p ref_count:%d\n",
652 gBufMgr, gBufMgr->ref_count);
654 /* setup the lock_type */
655 env = getenv("BUFMGR_LOCK_TYPE");
656 if (env && !strcmp(env, "always"))
657 gBufMgr->lock_type = LOCK_TRY_ALWAYS;
658 else if (env && !strcmp(env, "none"))
659 gBufMgr->lock_type = LOCK_TRY_NEVER;
660 else if (env && !strcmp(env, "once"))
661 gBufMgr->lock_type = LOCK_TRY_ONCE;
663 gBufMgr->lock_type = LOCK_TRY_ALWAYS;
665 TBM_DBG("BUFMGR_LOCK_TYPE=%s\n",
666 env ? env : "default:once");
668 TBM_TRACE("create tbm_bufmgr(%p) ref_count(%d) fd(%d)\n", gBufMgr, gBufMgr->ref_count, fd);
670 /* intialize bo_list */
671 LIST_INITHEAD(&gBufMgr->bo_list);
673 /* intialize surf_list */
674 LIST_INITHEAD(&gBufMgr->surf_list);
676 /* intialize surf_list */
677 LIST_INITHEAD(&gBufMgr->surf_queue_list);
679 /* intialize debug_key_list */
680 LIST_INITHEAD(&gBufMgr->debug_key_list);
682 #ifdef TBM_BUFMGR_INIT_TIME
684 gettimeofday(&end_tv, NULL);
685 TBM_LOG_I("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)));
688 pthread_mutex_unlock(&gLock);
694 tbm_bufmgr_deinit(tbm_bufmgr bufmgr)
696 TBM_RETURN_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr));
701 tbm_surface_h surf = NULL;
702 tbm_surface_h tmp_surf = NULL;
704 pthread_mutex_lock(&gLock);
707 TBM_LOG_E("gBufmgr already destroy: bufmgr:%p\n", bufmgr);
708 pthread_mutex_unlock(&gLock);
713 if (bufmgr->ref_count > 0) {
714 TBM_TRACE("reduce a ref_count(%d) of tbm_bufmgr(%p)\n", bufmgr->ref_count, bufmgr);
715 pthread_mutex_unlock(&gLock);
719 /* destroy bo_list */
720 if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
721 LIST_FOR_EACH_ENTRY_SAFE(bo, tmp, &bufmgr->bo_list, item_link) {
722 TBM_LOG_E("Un-freed bo(%p, ref:%d)\n",
729 /* destroy surf_list */
730 if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
731 LIST_FOR_EACH_ENTRY_SAFE(surf, tmp_surf, &bufmgr->surf_list, item_link) {
732 TBM_LOG_E("Un-freed surf(%p, ref:%d)\n",
734 tbm_surface_destroy(surf);
738 /* destroy bufmgr priv */
739 bufmgr->backend->bufmgr_deinit(bufmgr->backend->priv);
740 bufmgr->backend->priv = NULL;
741 tbm_backend_free(bufmgr->backend);
742 bufmgr->backend = NULL;
744 TBM_TRACE("destroy tbm_bufmgr(%p)\n", bufmgr);
746 dlclose(bufmgr->module_data);
755 pthread_mutex_unlock(&gLock);
759 tbm_bo_size(tbm_bo bo)
761 tbm_bufmgr bufmgr = NULL;
764 _tbm_bufmgr_mutex_lock();
766 TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
767 TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
771 size = bufmgr->backend->bo_size(bo);
773 TBM_TRACE("bo(%p) size(%d)\n", bo, size);
775 _tbm_bufmgr_mutex_unlock();
781 tbm_bo_ref(tbm_bo bo)
783 _tbm_bufmgr_mutex_lock();
785 TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), NULL);
786 TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), NULL);
790 TBM_TRACE("bo(%p) ref_cnt(%d)\n", bo, bo->ref_cnt);
792 _tbm_bufmgr_mutex_unlock();
798 tbm_bo_unref(tbm_bo bo)
800 tbm_bufmgr bufmgr = NULL;
801 tbm_user_data *old_data = NULL, *tmp = NULL;
803 _tbm_bufmgr_mutex_lock();
805 TBM_BUFMGR_RETURN_IF_FAIL(gBufMgr);
806 TBM_BUFMGR_RETURN_IF_FAIL(_tbm_bo_is_valid(bo));
810 TBM_TRACE("bo(%p) ref_cnt(%d)\n", bo, bo->ref_cnt - 1);
812 if (bo->ref_cnt <= 0) {
813 _tbm_bufmgr_mutex_unlock();
818 if (bo->ref_cnt == 0) {
819 /* destory the user_data_list */
820 if (!LIST_IS_EMPTY(&bo->user_data_list)) {
821 LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp, &bo->user_data_list, item_link) {
822 TBM_DBG("free user_data\n");
823 user_data_delete(old_data);
827 while (bo->lock_cnt > 0) {
828 TBM_LOG_E("error lock_cnt:%d\n",
834 /* call the bo_free */
835 bufmgr->backend->bo_free(bo);
838 LIST_DEL(&bo->item_link);
844 _tbm_bufmgr_mutex_unlock();
848 tbm_bo_alloc(tbm_bufmgr bufmgr, int size, int flags)
851 void *bo_priv = NULL;
853 _tbm_bufmgr_mutex_lock();
855 TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
856 TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, NULL);
857 TBM_BUFMGR_RETURN_VAL_IF_FAIL(size > 0, NULL);
859 bo = calloc(1, sizeof(struct _tbm_bo));
861 TBM_TRACE("error: fail to create of tbm_bo size(%d) flag(%s)\n", size, tbm_flag_to_str(flags));
862 _tbm_set_last_result(TBM_BO_ERROR_HEAP_ALLOC_FAILED);
863 _tbm_bufmgr_mutex_unlock();
867 _tbm_util_check_bo_cnt(bufmgr);
872 bo_priv = bufmgr->backend->bo_alloc(bo, size, flags);
874 TBM_TRACE("error: fail to create of tbm_bo size(%d) flag(%s)\n", size, tbm_flag_to_str(flags));
875 _tbm_set_last_result(TBM_BO_ERROR_BO_ALLOC_FAILED);
877 _tbm_bufmgr_mutex_unlock();
885 TBM_TRACE("bo(%p) size(%d) refcnt(%d), flag(%s)\n", bo, size, bo->ref_cnt, tbm_flag_to_str(bo->flags));
887 LIST_INITHEAD(&bo->user_data_list);
889 LIST_ADD(&bo->item_link, &bufmgr->bo_list);
891 _tbm_bufmgr_mutex_unlock();
897 tbm_bo_import(tbm_bufmgr bufmgr, unsigned int key)
902 void *bo_priv = NULL;
904 _tbm_bufmgr_mutex_lock();
906 TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
907 TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, NULL);
909 if (!bufmgr->backend->bo_import) {
910 _tbm_bufmgr_mutex_unlock();
914 _tbm_util_check_bo_cnt(bufmgr);
916 bo = calloc(1, sizeof(struct _tbm_bo));
918 TBM_TRACE("error: fail to import of tbm_bo by key(%d)\n", key);
919 _tbm_bufmgr_mutex_unlock();
925 bo_priv = bufmgr->backend->bo_import(bo, key);
927 TBM_TRACE("error: fail to import of tbm_bo by key(%d)\n", key);
928 _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FAILED);
930 _tbm_bufmgr_mutex_unlock();
934 if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
935 LIST_FOR_EACH_ENTRY_SAFE(bo2, tmp, &bufmgr->bo_list, item_link) {
936 if (bo2->priv == bo_priv) {
937 TBM_TRACE("find bo(%p) ref(%d) key(%d) flag(%s) in list\n",
938 bo2, bo2->ref_cnt, key, tbm_flag_to_str(bo2->flags));
941 _tbm_bufmgr_mutex_unlock();
952 if (bufmgr->backend->bo_get_flags)
953 bo->flags = bufmgr->backend->bo_get_flags(bo);
955 bo->flags = TBM_BO_DEFAULT;
957 TBM_TRACE("import new bo(%p) ref(%d) key(%d) flag(%s) in list\n",
958 bo, bo->ref_cnt, key, tbm_flag_to_str(bo->flags));
960 LIST_INITHEAD(&bo->user_data_list);
962 LIST_ADD(&bo->item_link, &bufmgr->bo_list);
964 _tbm_bufmgr_mutex_unlock();
970 tbm_bo_import_fd(tbm_bufmgr bufmgr, tbm_fd fd)
975 void *bo_priv = NULL;
977 _tbm_bufmgr_mutex_lock();
979 TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
980 TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, NULL);
982 if (!bufmgr->backend->bo_import_fd) {
983 _tbm_bufmgr_mutex_unlock();
987 _tbm_util_check_bo_cnt(bufmgr);
989 bo = calloc(1, sizeof(struct _tbm_bo));
991 TBM_TRACE("error: fail to import tbm_bo by tbm_fd(%d)\n", fd);
992 _tbm_bufmgr_mutex_unlock();
998 bo_priv = bufmgr->backend->bo_import_fd(bo, fd);
1000 TBM_TRACE("error: fail to import tbm_bo by tbm_fd(%d)\n", fd);
1001 _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FD_FAILED);
1003 _tbm_bufmgr_mutex_unlock();
1007 if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
1008 LIST_FOR_EACH_ENTRY_SAFE(bo2, tmp, &bufmgr->bo_list, item_link) {
1009 if (bo2->priv == bo_priv) {
1010 TBM_TRACE("find bo(%p) ref(%d) fd(%d) flag(%s) in list\n",
1011 bo2, bo2->ref_cnt, fd, tbm_flag_to_str(bo2->flags));
1014 _tbm_bufmgr_mutex_unlock();
1025 if (bufmgr->backend->bo_get_flags)
1026 bo->flags = bufmgr->backend->bo_get_flags(bo);
1028 bo->flags = TBM_BO_DEFAULT;
1030 TBM_TRACE("import bo(%p) ref(%d) fd(%d) flag(%s)in list\n",
1031 bo, bo->ref_cnt, fd, tbm_flag_to_str(bo->flags));
1033 LIST_INITHEAD(&bo->user_data_list);
1035 LIST_ADD(&bo->item_link, &bufmgr->bo_list);
1037 _tbm_bufmgr_mutex_unlock();
1043 tbm_bo_export(tbm_bo bo)
1045 tbm_bufmgr bufmgr = NULL;
1048 _tbm_bufmgr_mutex_lock();
1050 TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1051 TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1055 if (!bufmgr->backend->bo_export) {
1056 _tbm_bufmgr_mutex_unlock();
1060 ret = bufmgr->backend->bo_export(bo);
1062 _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FAILED);
1063 TBM_TRACE("error: bo(%p) tbm_key(%d)\n", bo, ret);
1064 _tbm_bufmgr_mutex_unlock();
1068 TBM_TRACE("bo(%p) tbm_key(%d)\n", bo, ret);
1070 _tbm_bufmgr_mutex_unlock();
1076 tbm_bo_export_fd(tbm_bo bo)
1078 tbm_bufmgr bufmgr = NULL;
1081 _tbm_bufmgr_mutex_lock();
1083 TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), -1);
1084 TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), -1);
1088 if (!bufmgr->backend->bo_export_fd) {
1089 _tbm_bufmgr_mutex_unlock();
1093 ret = bufmgr->backend->bo_export_fd(bo);
1095 _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FD_FAILED);
1096 TBM_TRACE("error: bo(%p) tbm_fd(%d)\n", bo, ret);
1097 _tbm_bufmgr_mutex_unlock();
1101 TBM_TRACE("bo(%p) tbm_fd(%d)\n", bo, ret);
1103 _tbm_bufmgr_mutex_unlock();
1109 tbm_bo_get_handle(tbm_bo bo, int device)
1111 tbm_bufmgr bufmgr = NULL;
1112 tbm_bo_handle bo_handle;
1114 _tbm_bufmgr_mutex_lock();
1116 TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), (tbm_bo_handle) NULL);
1117 TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) NULL);
1121 bo_handle = bufmgr->backend->bo_get_handle(bo, device);
1122 if (bo_handle.ptr == NULL) {
1123 _tbm_set_last_result(TBM_BO_ERROR_GET_HANDLE_FAILED);
1124 TBM_TRACE("error: bo(%p) bo_handle(%p)\n", bo, bo_handle.ptr);
1125 _tbm_bufmgr_mutex_unlock();
1126 return (tbm_bo_handle) NULL;
1129 TBM_TRACE("bo(%p) bo_handle(%p)\n", bo, bo_handle.ptr);
1131 _tbm_bufmgr_mutex_unlock();
1137 tbm_bo_map(tbm_bo bo, int device, int opt)
1139 tbm_bufmgr bufmgr = NULL;
1140 tbm_bo_handle bo_handle;
1142 _tbm_bufmgr_mutex_lock();
1144 TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), (tbm_bo_handle) NULL);
1145 TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) NULL);
1149 if (!_tbm_bo_lock(bo, device, opt)) {
1150 _tbm_set_last_result(TBM_BO_ERROR_LOCK_FAILED);
1151 TBM_TRACE("error: fail to lock bo:%p)\n", bo);
1152 _tbm_bufmgr_mutex_unlock();
1153 return (tbm_bo_handle) NULL;
1156 bo_handle = bufmgr->backend->bo_map(bo, device, opt);
1157 if (bo_handle.ptr == NULL) {
1158 _tbm_set_last_result(TBM_BO_ERROR_MAP_FAILED);
1159 TBM_TRACE("error: fail to map bo:%p\n", bo);
1161 _tbm_bufmgr_mutex_unlock();
1162 return (tbm_bo_handle) NULL;
1165 /* increase the map_count */
1168 TBM_TRACE("bo(%p) map_cnt(%d)\n", bo, bo->map_cnt);
1170 _tbm_bufmgr_mutex_unlock();
1176 tbm_bo_unmap(tbm_bo bo)
1178 tbm_bufmgr bufmgr = NULL;
1181 _tbm_bufmgr_mutex_lock();
1183 TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1184 TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1188 ret = bufmgr->backend->bo_unmap(bo);
1190 TBM_TRACE("error: bo(%p) map_cnt(%d)\n", bo, bo->map_cnt);
1191 _tbm_set_last_result(TBM_BO_ERROR_UNMAP_FAILED);
1192 _tbm_bufmgr_mutex_unlock();
1196 /* decrease the map_count */
1199 TBM_TRACE("bo(%p) map_cnt(%d)\n", bo, bo->map_cnt);
1203 _tbm_bufmgr_mutex_unlock();
1209 tbm_bo_swap(tbm_bo bo1, tbm_bo bo2)
1211 tbm_bufmgr bufmgr = NULL;
1214 _tbm_bufmgr_mutex_lock();
1216 TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1217 TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo1), 0);
1218 TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo2), 0);
1222 TBM_TRACE("before: bo1(%p) bo2(%p)\n", bo1, bo2);
1224 if (bufmgr->backend->bo_size(bo1) != bufmgr->backend->bo_size(bo2)) {
1225 _tbm_set_last_result(TBM_BO_ERROR_SWAP_FAILED);
1226 TBM_TRACE("error: bo1(%p) bo2(%p)\n", bo1, bo2);
1227 _tbm_bufmgr_mutex_unlock();
1231 TBM_TRACE("after: bo1(%p) bo2(%p)\n", bo1, bo2);
1234 bo1->priv = bo2->priv;
1237 _tbm_bufmgr_mutex_unlock();
1243 tbm_bo_locked(tbm_bo bo)
1245 tbm_bufmgr bufmgr = NULL;
1247 _tbm_bufmgr_mutex_lock();
1249 TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1250 TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1254 if (bufmgr->lock_type == LOCK_TRY_NEVER) {
1255 TBM_TRACE("bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
1256 _tbm_bufmgr_mutex_unlock();
1260 if (bo->lock_cnt > 0) {
1261 TBM_TRACE("error: bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
1262 _tbm_bufmgr_mutex_unlock();
1266 TBM_TRACE("bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
1267 _tbm_bufmgr_mutex_unlock();
1273 tbm_bo_add_user_data(tbm_bo bo, unsigned long key,
1274 tbm_data_free data_free_func)
1276 tbm_user_data *data;
1278 _tbm_bufmgr_mutex_lock();
1280 TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1281 TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1283 /* check if the data according to the key exist if so, return false. */
1284 data = user_data_lookup(&bo->user_data_list, key);
1286 TBM_TRACE("warning: user data already exist key(%ld)\n", key);
1287 _tbm_bufmgr_mutex_unlock();
1291 data = user_data_create(key, data_free_func);
1293 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1294 _tbm_bufmgr_mutex_unlock();
1298 TBM_TRACE("bo(%p) key(%lu) data(%p)\n", bo, key, data->data);
1300 LIST_ADD(&data->item_link, &bo->user_data_list);
1302 _tbm_bufmgr_mutex_unlock();
1308 tbm_bo_set_user_data(tbm_bo bo, unsigned long key, void *data)
1310 tbm_user_data *old_data;
1312 _tbm_bufmgr_mutex_lock();
1314 TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1315 TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1317 if (LIST_IS_EMPTY(&bo->user_data_list)) {
1318 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1319 _tbm_bufmgr_mutex_unlock();
1323 old_data = user_data_lookup(&bo->user_data_list, key);
1325 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1326 _tbm_bufmgr_mutex_unlock();
1330 if (old_data->data && old_data->free_func)
1331 old_data->free_func(old_data->data);
1333 old_data->data = data;
1335 TBM_TRACE("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
1337 _tbm_bufmgr_mutex_unlock();
1343 tbm_bo_get_user_data(tbm_bo bo, unsigned long key, void **data)
1345 tbm_user_data *old_data;
1347 _tbm_bufmgr_mutex_lock();
1349 TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1350 TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1352 if (!data || LIST_IS_EMPTY(&bo->user_data_list)) {
1353 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1354 _tbm_bufmgr_mutex_unlock();
1358 old_data = user_data_lookup(&bo->user_data_list, key);
1360 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1362 _tbm_bufmgr_mutex_unlock();
1366 *data = old_data->data;
1368 TBM_TRACE("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
1370 _tbm_bufmgr_mutex_unlock();
1376 tbm_bo_delete_user_data(tbm_bo bo, unsigned long key)
1378 tbm_user_data *old_data = (void *)0;
1380 _tbm_bufmgr_mutex_lock();
1382 TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1383 TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1385 if (LIST_IS_EMPTY(&bo->user_data_list)) {
1386 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1387 _tbm_bufmgr_mutex_unlock();
1391 old_data = user_data_lookup(&bo->user_data_list, key);
1393 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1394 _tbm_bufmgr_mutex_unlock();
1398 TBM_TRACE("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
1400 user_data_delete(old_data);
1402 _tbm_bufmgr_mutex_unlock();
1408 tbm_bufmgr_get_capability(tbm_bufmgr bufmgr)
1410 int capabilities = TBM_BUFMGR_CAPABILITY_NONE;
1412 _tbm_bufmgr_mutex_lock();
1414 TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), TBM_BUFMGR_CAPABILITY_NONE);
1415 TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, TBM_BUFMGR_CAPABILITY_NONE);
1417 TBM_TRACE("tbm_bufmgr(%p) capability(%d)\n", bufmgr, bufmgr->capabilities);
1419 capabilities = bufmgr->capabilities;
1421 _tbm_bufmgr_mutex_unlock();
1423 return capabilities;
1427 tbm_bo_get_flags(tbm_bo bo)
1431 _tbm_bufmgr_mutex_lock();
1433 TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1434 TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1438 TBM_TRACE("bo(%p)\n", bo);
1440 _tbm_bufmgr_mutex_unlock();
1445 /* LCOV_EXCL_START */
1447 tbm_get_last_error(void)
1449 return tbm_last_error;
1453 tbm_bufmgr_debug_show(tbm_bufmgr bufmgr)
1455 tbm_bo bo = NULL, tmp_bo = NULL;
1457 tbm_surface_h surf = NULL, tmp_surf = NULL;
1460 char app_name[255] = {0,};
1461 unsigned int pid = 0;
1462 char title[255] = {0,};
1463 char data[255] = {0,};
1464 tbm_surface_debug_data *debug_old_data = NULL, *debug_tmp = NULL;
1466 pthread_mutex_lock(&gLock);
1468 if (!TBM_BUFMGR_IS_VALID(bufmgr) || (bufmgr != gBufMgr)) {
1469 TBM_LOG_E("invalid bufmgr\n");
1470 pthread_mutex_unlock(&gLock);
1475 _tbm_util_get_appname_from_pid(getpid(), app_name);
1476 _tbm_util_get_appname_brief(app_name);
1477 TBM_DEBUG("============TBM DEBUG: %s(%d)===========================\n",
1478 app_name, getpid());
1479 memset(app_name, 0x0, 255 * sizeof(char));
1480 snprintf(title, 255, "%s", "no surface refcnt width height bpp size n_b n_p flags format app_name ");
1481 if (!LIST_IS_EMPTY(&bufmgr->debug_key_list)) {
1482 LIST_FOR_EACH_ENTRY_SAFE(debug_old_data, debug_tmp, &bufmgr->debug_key_list, item_link) {
1483 strncat(title, " ", 3);
1484 strncat(title, debug_old_data->key, strlen(debug_old_data->key) + 1);
1488 TBM_DEBUG("[tbm_surface information]\n");
1489 TBM_DEBUG("%s\n", title);
1490 /* show the tbm_surface information in surf_list */
1491 if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
1494 LIST_FOR_EACH_ENTRY_SAFE(surf, tmp_surf, &bufmgr->surf_list, item_link) {
1495 pid = _tbm_surface_internal_get_debug_pid(surf);
1497 /* if pid is null, set the self_pid */
1501 _tbm_util_get_appname_from_pid(pid, app_name);
1502 _tbm_util_get_appname_brief(app_name);
1504 snprintf(data, 255, "%-2d %-9p %-4d %-5d %-6d %-3d %-6d %-2d %-2d %-3d %-8s %-15s",
1511 surf->info.size / 1024,
1515 _tbm_surface_internal_format_to_str(surf->info.format) + 11,
1518 if (!LIST_IS_EMPTY(&bufmgr->debug_key_list)) {
1519 LIST_FOR_EACH_ENTRY_SAFE(debug_old_data, debug_tmp, &bufmgr->debug_key_list, item_link) {
1520 strncat(data, " ", 3);
1522 value = _tbm_surface_internal_get_debug_data(surf, debug_old_data->key);
1524 strncat(data, value, strlen(value) + 1);
1526 strncat(data, "none", 5);
1529 TBM_DEBUG("%s\n", data);
1531 for (i = 0; i < surf->num_bos; i++) {
1532 TBM_DEBUG(" bo:%-12p %-26d%-10d\n",
1534 surf->bos[i]->ref_cnt,
1535 bufmgr->backend->bo_size(surf->bos[i]) / 1024);
1538 memset(app_name, 0x0, 255 * sizeof(char));
1541 TBM_DEBUG("no tbm_surfaces.\n");
1545 TBM_DEBUG("[tbm_bo information]\n");
1546 TBM_DEBUG("no bo refcnt size lock_cnt map_cnt flags surface\n");
1548 /* show the tbm_bo information in bo_list */
1549 if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
1550 LIST_FOR_EACH_ENTRY_SAFE(bo, tmp_bo, &bufmgr->bo_list, item_link) {
1551 TBM_DEBUG("%-4d%-11p %-4d %-6d %-5d %-4d %-3d %-11p\n",
1555 bufmgr->backend->bo_size(bo) / 1024,
1562 TBM_DEBUG("no tbm_bos.\n");
1566 TBM_DEBUG("===============================================================\n");
1568 pthread_mutex_unlock(&gLock);
1572 tbm_bufmgr_debug_trace(tbm_bufmgr bufmgr, int onoff)
1574 _tbm_bufmgr_mutex_lock();
1576 TBM_BUFMGR_RETURN_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr));
1577 TBM_BUFMGR_RETURN_IF_FAIL(bufmgr == gBufMgr);
1580 TBM_LOG_D("bufmgr=%p onoff=%d\n", bufmgr, onoff);
1584 _tbm_bufmgr_mutex_unlock();
1588 tbm_bufmgr_debug_queue_dump(char *path, int count, int onoff)
1592 TBM_RETURN_VAL_IF_FAIL(path != NULL, 0);
1593 TBM_LOG_D("path=%s count=%d onoff=%d\n", path, count, onoff);
1595 pthread_mutex_lock(&gLock);
1598 if (_tbm_util_get_max_surface_size(&w, &h) == 0) {
1599 TBM_LOG_I("No tbm_surface.\n");
1600 pthread_mutex_unlock(&gLock);
1604 tbm_surface_internal_dump_start(path, w, h, count);
1606 } else if (onoff == 0) {
1607 tbm_surface_internal_dump_end();
1610 pthread_mutex_unlock(&gLock);
1614 pthread_mutex_unlock(&gLock);
1619 tbm_bufmgr_debug_dump_all(char *path)
1621 int w = 0, h = 0, count = 0;
1622 tbm_surface_h surface = NULL, tmp = NULL;
1624 TBM_RETURN_VAL_IF_FAIL(path != NULL, 0);
1625 TBM_LOG_D("path=%s\n", path);
1627 pthread_mutex_lock(&gLock);
1629 count = _tbm_util_get_max_surface_size(&w, &h);
1631 TBM_LOG_I("No tbm_surface.\n");
1632 pthread_mutex_unlock(&gLock);
1636 tbm_surface_internal_dump_start(path, w, h, count);
1638 LIST_FOR_EACH_ENTRY_SAFE(surface, tmp, &gBufMgr->surf_list, item_link) {
1639 tbm_surface_internal_dump_buffer(surface, "dump_all");
1642 tbm_surface_internal_dump_end();
1644 pthread_mutex_unlock(&gLock);
1649 /* internal function */
1651 _tbm_bufmgr_get_bufmgr(void)
1657 _tbm_bo_set_surface(tbm_bo bo, tbm_surface_h surface)
1659 _tbm_bufmgr_mutex_lock();
1661 TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1662 TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1664 bo->surface = surface;
1666 _tbm_bufmgr_mutex_unlock();
1672 tbm_bufmgr_bind_native_display(tbm_bufmgr bufmgr, void *NativeDisplay)
1676 _tbm_bufmgr_mutex_lock();
1678 TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1680 if (!bufmgr->backend->bufmgr_bind_native_display) {
1681 TBM_TRACE("error: tbm_bufmgr(%p) NativeDisplay(%p)\n", bufmgr, NativeDisplay);
1682 _tbm_bufmgr_mutex_unlock();
1686 ret = bufmgr->backend->bufmgr_bind_native_display(bufmgr, NativeDisplay);
1688 TBM_TRACE("error: tbm_bufmgr(%p) NativeDisplay(%p)\n", bufmgr, NativeDisplay);
1689 _tbm_bufmgr_mutex_unlock();
1693 TBM_TRACE("tbm_bufmgr(%p) NativeDisplay(%p)\n", bufmgr, NativeDisplay);
1695 _tbm_bufmgr_mutex_unlock();
1699 /* LCOV_EXCL_STOP */