* Copyright (c) 2025 Huawei Technologies Co.,Ltd.
*
* CBB is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
* -------------------------------------------------------------------------
*
* mes_shm_dl.c
*
*
* IDENTIFICATION
* src/cm_mes/mes_shm_dl.c
*
* -------------------------------------------------------------------------
*/
#include <string.h>
#include "mes_interface.h"
#include "cm_utils/cm_utils.h"
#include "ubs_mem_def.h"
#include "mes_shm_dl.h"
typedef struct UbsMemFunc {
bool matrix_mem_inited;
int (*ubsmem_init_attributes)(ubsmem_options_t *ubsm_shmem_opts);
int (*ubsmem_initialize)(const ubsmem_options_t *ubsm_shmem_opts);
int (*ubsmem_finalize)(void);
int (*ubsmem_create_region)(const char *region_name, size_t size, const ubsmem_region_attributes_t *reg_attr);
int (*ubsmem_lookup_regions)(ubsmem_regions_t *regions);
int (*ubsmem_destroy_region)(const char *region_name);
int (*ubsmem_shmem_allocate)(const char *region_name, const char *name, size_t size, mode_t mode, uint64_t flags);
int (*ubsmem_shmem_deallocate)(const char *name);
int (*ubsmem_shmem_map)(void *addr, size_t length, int port, int flags, const char *name, off_t offset,
void **local_ptr);
int (*ubsmem_shmem_unmap)(void *local_ptr, size_t length);
} UbsMemFunc;
typedef struct UbDistCommFunc {
int (*ub_comm_queue_init)(ub_shm_comm_t *handle, ub_shm_area_t *init_region, ub_ring_region_map_t *ring_regions,
ub_comm_conf_t *conf);
int (*ub_comm_queue_deinit)(ub_shm_comm_t *handle);
int (*ub_comm_queue_send)(ub_shm_comm_t *handle, const message_t *msg);
int (*ub_comm_queue_recv)(ub_shm_comm_t *handle, void *buffer, uint32_t length);
bool (*ub_comm_queue_check_ready)(ub_shm_comm_t *handle, const uint8_t node_id);
int (*ub_comm_queue_register_process_func)(ub_shm_comm_t *handle, uint8_t msg_type, ub_func_type_t func_type,
ub_callback_t func, void *ctx);
void (*ub_atomic_register_log_func)(ub_atomic_log_func func);
int (*ub_atomic_set_log_level)(int level);
} UbDistCommFunc;
void* g_ubsMemDl = NULL;
void* g_ubDistCommDl = NULL;
UbsMemFunc g_ubsMemFunc;
UbDistCommFunc g_ubDistCommFunc;
static int mes_fill_so_path_from_dir(char *path_buf, const char *so_basename)
{
const char *env_key = NULL;
const char *default_full_path = NULL;
if (strcmp(so_basename, UBS_MEM_SO_NAME) == 0) {
env_key = UBS_MEM_ENV_PATH;
default_full_path = UBS_MEM_DEFAULT_SO_PATH;
} else if (strcmp(so_basename, UB_DIST_COMM_SO_NAME) == 0) {
env_key = UB_DIST_COMM_ENV_PATH;
default_full_path = UB_DIST_COMM_DEFAULT_SO_PATH;
} else {
return CM_ERROR;
}
if (path_buf == NULL) {
return CM_ERROR;
}
const uint32_t path_buf_len = PATH_LENGTH;
const char *dir = getenv(env_key);
if (dir != NULL && dir[0] != '\0') {
char resolved_dir[PATH_LENGTH] = {0};
bool resolved = (realpath_file(dir, resolved_dir, PATH_LENGTH) == CM_SUCCESS && resolved_dir[0] != '\0');
if (!resolved) {
LOG_RUN_ERR("realpath_file failed for %s (%s)", dir, so_basename);
} else {
int n = snprintf_s(path_buf, path_buf_len, path_buf_len - 1, "%s/%s", resolved_dir, so_basename);
if (n >= 0) {
return CM_SUCCESS;
}
LOG_RUN_ERR("construct %s/%s failed, ret %d.", resolved_dir, so_basename, n);
}
LOG_RUN_WAR("[mes] %s: resolve failed, fallback %s", so_basename, default_full_path);
}
errno_t rc = strncpy_s(path_buf, path_buf_len, default_full_path, path_buf_len - 1);
if (rc != EOK) {
LOG_RUN_ERR("[mes] %s: strncpy_s default path failed, rc=%d.", so_basename, rc);
return CM_ERROR;
}
return CM_SUCCESS;
}
static int UbsMemDlsym(void)
{
if (cm_load_symbol(g_ubsMemDl, "ubsmem_init_attributes",
(void **)&g_ubsMemFunc.ubsmem_init_attributes) != CM_SUCCESS) {
return CM_ERROR;
}
if (cm_load_symbol(g_ubsMemDl, "ubsmem_initialize",
(void **)&g_ubsMemFunc.ubsmem_initialize) != CM_SUCCESS) {
return CM_ERROR;
}
if (cm_load_symbol(g_ubsMemDl, "ubsmem_finalize",
(void **)&g_ubsMemFunc.ubsmem_finalize) != CM_SUCCESS) {
return CM_ERROR;
}
if (cm_load_symbol(g_ubsMemDl, "ubsmem_lookup_regions",
(void **)&g_ubsMemFunc.ubsmem_lookup_regions) != CM_SUCCESS) {
return CM_ERROR;
}
if (cm_load_symbol(g_ubsMemDl, "ubsmem_create_region",
(void **)&g_ubsMemFunc.ubsmem_create_region) != CM_SUCCESS) {
return CM_ERROR;
}
if (cm_load_symbol(g_ubsMemDl, "ubsmem_destroy_region",
(void **)&g_ubsMemFunc.ubsmem_destroy_region) != CM_SUCCESS) {
return CM_ERROR;
}
if (cm_load_symbol(g_ubsMemDl, "ubsmem_shmem_allocate",
(void **)&g_ubsMemFunc.ubsmem_shmem_allocate) != CM_SUCCESS) {
return CM_ERROR;
}
if (cm_load_symbol(g_ubsMemDl, "ubsmem_shmem_deallocate",
(void **)&g_ubsMemFunc.ubsmem_shmem_deallocate) != CM_SUCCESS) {
return CM_ERROR;
}
if (cm_load_symbol(g_ubsMemDl, "ubsmem_shmem_map",
(void **)&g_ubsMemFunc.ubsmem_shmem_map) != CM_SUCCESS) {
return CM_ERROR;
}
if (cm_load_symbol(g_ubsMemDl, "ubsmem_shmem_unmap",
(void **)&g_ubsMemFunc.ubsmem_shmem_unmap) != CM_SUCCESS) {
return CM_ERROR;
}
return CM_SUCCESS;
}
void FinishUbsMemDl(void)
{
errno_t rc;
if (g_ubsMemFunc.matrix_mem_inited) {
int ret = mes_ubsmem_finalize();
if (ret != UBSM_OK) {
LOG_RUN_ERR("Failed to finalize ubs_mem, error: %d.", ret);
}
LOG_RUN_INF("finalized ubs_mem.");
}
if (g_ubsMemDl != NULL) {
dlclose(g_ubsMemDl);
g_ubsMemDl = NULL;
rc = memset_s(&g_ubsMemFunc, sizeof(UbsMemFunc), 0, sizeof(UbsMemFunc));
if (rc != EOK) {
LOG_RUN_ERR("memset_s g_ubsMemFunc failed, rc=%d.", rc);
}
LOG_RUN_INF("Successfully closed ubs_mem dynamic library.");
}
if (g_ubDistCommDl != NULL) {
dlclose(g_ubDistCommDl);
g_ubDistCommDl = NULL;
rc = memset_s(&g_ubDistCommFunc, sizeof(UbDistCommFunc), 0, sizeof(UbDistCommFunc));
if (rc != EOK) {
LOG_RUN_ERR("memset_s g_ubDistCommFunc failed, rc=%d.", rc);
}
LOG_RUN_INF("Successfully closed ub_dist_comm dynamic library.");
}
}
int InitUbsMemDl(char* path, uint32_t pathLen)
{
if (path == NULL || pathLen == 0) {
LOG_RUN_ERR("InitUbsMemDl path is nullptr");
return CM_ERROR;
}
int ret = CM_ERROR;
if (g_ubsMemDl != NULL) {
return CM_SUCCESS;
}
ret = cm_open_dl(&g_ubsMemDl, path);
if (ret != CM_SUCCESS) {
LOG_RUN_ERR("dlopen ubsMem path %s", path);
return CM_ERROR;
}
ret = UbsMemDlsym();
if (ret != CM_SUCCESS) {
LOG_RUN_ERR("dlsym Ubs Mem func, path %s", path);
FinishUbsMemDl();
return CM_ERROR;
}
return CM_SUCCESS;
}
static int UbDistCommDlsym(void)
{
if (cm_load_symbol(g_ubDistCommDl, "ub_comm_queue_init",
(void **)&g_ubDistCommFunc.ub_comm_queue_init) != CM_SUCCESS) {
return CM_ERROR;
}
if (cm_load_symbol(g_ubDistCommDl, "ub_comm_queue_deinit",
(void **)&g_ubDistCommFunc.ub_comm_queue_deinit) != CM_SUCCESS) {
return CM_ERROR;
}
if (cm_load_symbol(g_ubDistCommDl, "ub_comm_queue_send",
(void **)&g_ubDistCommFunc.ub_comm_queue_send) != CM_SUCCESS) {
return CM_ERROR;
}
if (cm_load_symbol(g_ubDistCommDl, "ub_comm_queue_recv",
(void **)&g_ubDistCommFunc.ub_comm_queue_recv) != CM_SUCCESS) {
return CM_ERROR;
}
if (cm_load_symbol(g_ubDistCommDl, "ub_comm_queue_check_ready",
(void **)&g_ubDistCommFunc.ub_comm_queue_check_ready) != CM_SUCCESS) {
return CM_ERROR;
}
if (cm_load_symbol(g_ubDistCommDl, "ub_comm_queue_register_process_func",
(void **)&g_ubDistCommFunc.ub_comm_queue_register_process_func) != CM_SUCCESS) {
return CM_ERROR;
}
if (cm_load_symbol(g_ubDistCommDl, "ub_atomic_register_log_func",
(void **)&g_ubDistCommFunc.ub_atomic_register_log_func) != CM_SUCCESS) {
return CM_ERROR;
}
if (cm_load_symbol(g_ubDistCommDl, "ub_atomic_set_log_level",
(void **)&g_ubDistCommFunc.ub_atomic_set_log_level) != CM_SUCCESS) {
return CM_ERROR;
}
return CM_SUCCESS;
}
static int InitUbDistCommDl(char *path, uint32_t pathLen)
{
int ret;
if (path == NULL || pathLen == 0) {
LOG_RUN_ERR("InitUbDistCommDl path is nullptr");
return CM_ERROR;
}
if (g_ubDistCommDl != NULL) {
return CM_SUCCESS;
}
ret = cm_open_dl(&g_ubDistCommDl, path);
if (ret != CM_SUCCESS) {
LOG_RUN_ERR("dlopen ub_dist_comm path %s", path);
return CM_ERROR;
}
ret = UbDistCommDlsym();
if (ret != CM_SUCCESS) {
LOG_RUN_ERR("dlsym ub_dist_comm func, path %s", path);
if (g_ubDistCommDl != NULL) {
(void)dlclose(g_ubDistCommDl);
g_ubDistCommDl = NULL;
}
return CM_ERROR;
}
return CM_SUCCESS;
}
static int ub_dist_comm_log_callback(int level, const char *file, const char *func, uint32_t line, const char *message)
{
switch (level) {
case LOG_LEVEL_DEBUG:
LOG_DEBUG_INF("[UB_DIST_COMM] %s:%d %s: %s", file, line, func, message);
break;
case LOG_LEVEL_INFO:
LOG_RUN_INF("[UB_DIST_COMM] %s:%d %s: %s", file, line, func, message);
break;
case LOG_LEVEL_WARN:
LOG_RUN_WAR("[UB_DIST_COMM] %s:%d %s: %s", file, line, func, message);
break;
case LOG_LEVEL_ERROR:
LOG_RUN_ERR("[UB_DIST_COMM] %s:%d %s: %s", file, line, func, message);
break;
case LOG_LEVEL_CRITICAL:
LOG_RUN_ERR("[UB_DIST_COMM] %s:%d %s: %s", file, line, func, message);
break;
default:
LOG_RUN_INF("[UB_DIST_COMM] %s:%d %s: %s", file, line, func, message);
break;
}
return 0;
}
static int mes_get_ub_dist_comm_log_level(void)
{
* CBB/MES uses bitmask-based log switches, while ub_dist_comm expects a
* threshold level. Map the currently enabled highest-detail level to the
* nearest ub_dist_comm threshold.
*/
if (LOG_DEBUG_INF_ON || LOG_DEBUG_WAR_ON || LOG_DEBUG_ERR_ON ||
LOG_MEC_ON || LOG_TRACE_ON || LOG_PROFILE_ON) {
return LOG_LEVEL_DEBUG;
}
if (LOG_RUN_INF_ON || LOG_OPER_ON) {
return LOG_LEVEL_INFO;
}
if (LOG_RUN_WAR_ON) {
return LOG_LEVEL_ERROR;
}
return LOG_LEVEL_CRITICAL;
}
static void register_ub_dist_comm_log(void)
{
ub_atomic_register_log_func(ub_dist_comm_log_callback);
LOG_RUN_INF("Successfully registered ub_dist_comm log callback.");
int log_level = mes_get_ub_dist_comm_log_level();
int ret = ub_atomic_set_log_level(log_level);
if (ret != 0) {
LOG_RUN_WAR("Failed to set ub_dist_comm log level, error: %d.", ret);
}
}
int mes_init_ubs_dlopen_so(void)
{
char ubs_path[PATH_LENGTH] = {0};
char queue_path[PATH_LENGTH] = {0};
if (mes_fill_so_path_from_dir(ubs_path, UBS_MEM_SO_NAME) != CM_SUCCESS) {
return CM_ERROR;
}
if (mes_fill_so_path_from_dir(queue_path, UB_DIST_COMM_SO_NAME) != CM_SUCCESS) {
return CM_ERROR;
}
LOG_RUN_INF("[mes] mes_init_ubs_dlopen_so ubs_mem soPath=%s, ub_dist_comm soPath=%s", ubs_path, queue_path);
if (InitUbsMemDl(ubs_path, PATH_LENGTH) != CM_SUCCESS) {
LOG_RUN_ERR("mes init UbsMemDl failed.");
return CM_ERROR;
}
if (InitUbDistCommDl(queue_path, PATH_LENGTH) != CM_SUCCESS) {
LOG_RUN_ERR("mes init ub_dist_comm dl failed.");
FinishUbsMemDl();
return CM_ERROR;
}
register_ub_dist_comm_log();
return CM_SUCCESS;
}
int mes_ubsmem_init_attributes(ubsmem_options_t *ubsm_shmem_opts)
{
if (g_ubsMemFunc.ubsmem_init_attributes != NULL) {
return g_ubsMemFunc.ubsmem_init_attributes(ubsm_shmem_opts);
}
return CM_ERROR;
}
int mes_ubsmem_initialize(const ubsmem_options_t *ubsm_shmem_opts)
{
if (g_ubsMemFunc.ubsmem_initialize != NULL) {
return g_ubsMemFunc.ubsmem_initialize(ubsm_shmem_opts);
}
return CM_ERROR;
}
int mes_ubsmem_finalize(void)
{
if (g_ubsMemFunc.ubsmem_finalize != NULL) {
return g_ubsMemFunc.ubsmem_finalize();
}
return CM_ERROR;
}
int mes_ubsmem_lookup_regions(ubsmem_regions_t *regions)
{
if (g_ubsMemFunc.ubsmem_lookup_regions != NULL) {
return g_ubsMemFunc.ubsmem_lookup_regions(regions);
}
return CM_ERROR;
}
int mes_ubsmem_create_region(const char *region_name, size_t size,
const ubsmem_region_attributes_t *reg_attr)
{
if (g_ubsMemFunc.ubsmem_create_region != NULL) {
return g_ubsMemFunc.ubsmem_create_region(region_name, size, reg_attr);
}
return CM_ERROR;
}
int mes_ubsmem_destroy_region(const char *region_name)
{
if (g_ubsMemFunc.ubsmem_destroy_region != NULL) {
return g_ubsMemFunc.ubsmem_destroy_region(region_name);
}
return CM_ERROR;
}
int mes_ubsmem_shmem_allocate(const char *region_name, const char *name,
size_t size, mode_t mode, uint64_t flags)
{
if (g_ubsMemFunc.ubsmem_shmem_allocate != NULL) {
return g_ubsMemFunc.ubsmem_shmem_allocate(region_name, name, size, mode, flags);
}
return CM_ERROR;
}
int mes_ubsmem_shmem_deallocate(const char *name)
{
if (g_ubsMemFunc.ubsmem_shmem_deallocate != NULL) {
return g_ubsMemFunc.ubsmem_shmem_deallocate(name);
}
return CM_ERROR;
}
int mes_ubsmem_shmem_map(void *addr, size_t length, int port, int flags,
const char *name, off_t offset, void **local_ptr)
{
if (g_ubsMemFunc.ubsmem_shmem_map != NULL) {
return g_ubsMemFunc.ubsmem_shmem_map(addr, length, port, flags, name, offset, local_ptr);
}
return CM_ERROR;
}
int mes_ubsmem_shmem_unmap(void *local_ptr, size_t length)
{
if (g_ubsMemFunc.ubsmem_shmem_unmap != NULL) {
return g_ubsMemFunc.ubsmem_shmem_unmap(local_ptr, length);
}
return CM_ERROR;
}
int mes_ubsmem_init_and_set_inited(ubsmem_options_t *opts)
{
int ret = mes_ubsmem_init_attributes(opts);
if (ret != UBSM_OK) {
LOG_RUN_ERR("Failed to initialize ubsmem attributes, error: %d.", ret);
return ret;
}
ret = mes_ubsmem_initialize(opts);
if (ret != UBSM_OK) {
LOG_RUN_ERR("Failed to initialize ubsmem, error: %d.", ret);
return ret;
}
g_ubsMemFunc.matrix_mem_inited = true;
return CM_SUCCESS;
}
int ub_comm_queue_init(ub_shm_comm_t *handle, ub_shm_area_t *init_region, ub_ring_region_map_t *ring_regions,
ub_comm_conf_t *conf)
{
if (g_ubDistCommFunc.ub_comm_queue_init != NULL) {
return g_ubDistCommFunc.ub_comm_queue_init(handle, init_region, ring_regions, conf);
}
LOG_RUN_ERR("ub_comm_queue_init function not loaded.");
return CM_ERROR;
}
int ub_comm_queue_deinit(ub_shm_comm_t *handle)
{
if (g_ubDistCommFunc.ub_comm_queue_deinit != NULL) {
return g_ubDistCommFunc.ub_comm_queue_deinit(handle);
}
LOG_RUN_ERR("ub_comm_queue_deinit function not loaded.");
return CM_ERROR;
}
int ub_comm_queue_send(ub_shm_comm_t *handle, const message_t *msg)
{
if (g_ubDistCommFunc.ub_comm_queue_send != NULL) {
return g_ubDistCommFunc.ub_comm_queue_send(handle, msg);
}
LOG_RUN_ERR("ub_comm_queue_send function not loaded.");
return CM_ERROR;
}
int ub_comm_queue_recv(ub_shm_comm_t *handle, void *buffer, uint32_t length)
{
if (g_ubDistCommFunc.ub_comm_queue_recv != NULL) {
return g_ubDistCommFunc.ub_comm_queue_recv(handle, buffer, length);
}
LOG_RUN_ERR("ub_comm_queue_recv function not loaded.");
return CM_ERROR;
}
bool ub_comm_queue_check_ready(ub_shm_comm_t *handle, const uint8_t node_id)
{
if (g_ubDistCommFunc.ub_comm_queue_check_ready != NULL) {
return g_ubDistCommFunc.ub_comm_queue_check_ready(handle, node_id);
}
LOG_RUN_ERR("ub_comm_queue_check_ready function not loaded.");
return false;
}
int ub_comm_queue_register_process_func(ub_shm_comm_t *handle, uint8_t msg_type, ub_func_type_t func_type,
ub_callback_t func, void *ctx)
{
if (g_ubDistCommFunc.ub_comm_queue_register_process_func != NULL) {
return g_ubDistCommFunc.ub_comm_queue_register_process_func(handle, msg_type, func_type, func, ctx);
}
LOG_RUN_ERR("ub_comm_queue_register_process_func function not loaded.");
return CM_ERROR;
}
void ub_atomic_register_log_func(ub_atomic_log_func func)
{
if (g_ubDistCommFunc.ub_atomic_register_log_func != NULL) {
g_ubDistCommFunc.ub_atomic_register_log_func(func);
return;
}
LOG_RUN_ERR("ub_atomic_register_log_func function not loaded.");
}
int ub_atomic_set_log_level(int level)
{
if (g_ubDistCommFunc.ub_atomic_set_log_level != NULL) {
return g_ubDistCommFunc.ub_atomic_set_log_level(level);
}
LOG_RUN_ERR("ub_atomic_set_log_level function not loaded.");
return CM_ERROR;
}