/* SPDX-License-Identifier: Apache-2.0 OR MIT */ /* * Copyright (c) 2025 Rockchip Electronics Co., Ltd. */ #define MODULE_TAG "kmpp_meta" #include #include #include "mpp_mem.h" #include "mpp_list.h" #include "mpp_lock.h" #include "mpp_debug.h" #include "mpp_thread.h" #include "mpp_singleton.h" #include "kmpp_obj.h" #include "kmpp_meta_impl.h" #define KMETA_DBG_FUNC (0x00000001) #define KMETA_DBG_SIZE (0x00000002) #define KMETA_DBG_SET (0x00000004) #define KMETA_DBG_GET (0x00000008) #define kmeta_dbg(flag, fmt, ...) _mpp_dbg_f(kmpp_meta_debug, flag, fmt, ## __VA_ARGS__) #define kmeta_dbg_func(fmt, ...) kmeta_dbg(KMETA_DBG_FUNC, fmt, ## __VA_ARGS__) #define kmeta_dbg_size(fmt, ...) kmeta_dbg(KMETA_DBG_SIZE, fmt, ## __VA_ARGS__) #define kmeta_dbg_set(fmt, ...) kmeta_dbg(KMETA_DBG_SET, fmt, ## __VA_ARGS__) #define kmeta_dbg_get(fmt, ...) kmeta_dbg(KMETA_DBG_GET, fmt, ## __VA_ARGS__) #define META_ON_OPS (0x00010000) #define META_VAL_INVALID (0x00000000) #define META_VAL_VALID (0x00000001) #define META_VAL_READY (0x00000002) #define META_READY_MASK (META_VAL_VALID | META_VAL_READY) /* property mask */ #define META_VAL_IS_OBJ (0x00000010) #define META_VAL_IS_SHM (0x00000020) #define META_PROP_MASK (META_VAL_IS_OBJ | META_VAL_IS_SHM) #define META_UNMASK_PROP(x) MPP_FETCH_AND(x, (~META_PROP_MASK)) #define META_KEY_TO_U64(key, type) ((rk_u64)((rk_u32)htobe32(key)) | ((rk_u64)type << 32)) typedef enum KmppMetaDataType_e { /* kmpp meta data of normal data type */ TYPE_VAL_32 = '3', TYPE_VAL_64 = '6', TYPE_KPTR = 'k', /* kernel pointer */ TYPE_UPTR = 'u', /* userspace pointer */ TYPE_SPTR = 's', /* share memory pointer */ } KmppMetaType; typedef struct KmppMetaSrv_s { pthread_mutex_t lock; struct list_head list; KmppObjDef def; rk_s32 offset_size; rk_u32 meta_id; rk_s32 meta_count; } KmppMetaSrv; typedef struct KmppMetaPriv_s { struct list_head list; KmppObj meta; rk_u32 meta_id; } KmppMetaPriv; static KmppMetaSrv *srv_meta = NULL; static rk_u32 kmpp_meta_debug = 0; #define get_meta_srv(caller) \ ({ \ KmppMetaSrv *__tmp; \ if (srv_meta) { \ __tmp = srv_meta; \ } else { \ mpp_loge_f("kmpp meta srv not init at %s : %s\n", __FUNCTION__, caller); \ __tmp = NULL; \ } \ __tmp; \ }) static rk_s32 kmpp_meta_impl_init(void *entry, KmppObj obj, const char *caller) { KmppMetaPriv *priv = (KmppMetaPriv *)kmpp_obj_to_priv(obj); KmppMetaSrv *srv = get_meta_srv(caller); (void)entry; if (srv) { priv->meta = obj; INIT_LIST_HEAD(&priv->list); pthread_mutex_lock(&srv->lock); list_add_tail(&priv->list, &srv->list); priv->meta_id = srv->meta_id++; srv->meta_count++; pthread_mutex_unlock(&srv->lock); } return rk_ok; } static rk_s32 kmpp_meta_impl_deinit(void *entry, KmppObj obj, const char *caller) { KmppMetaPriv *priv = (KmppMetaPriv *)kmpp_obj_to_priv(obj); KmppMetaSrv *srv = get_meta_srv(caller); (void)entry; if (srv) { pthread_mutex_lock(&srv->lock); list_del_init(&priv->list); srv->meta_count--; pthread_mutex_unlock(&srv->lock); } return rk_ok; } static void kmpp_meta_deinit(void) { KmppMetaSrv *srv = srv_meta; if (!srv) { kmeta_dbg_func("kmpp meta already deinit\n"); return; } if (srv->def) { kmpp_objdef_put(srv->def); srv->def = NULL; } pthread_mutex_destroy(&srv->lock); MPP_FREE(srv); srv_meta = NULL; } static void kmpp_meta_init(void) { KmppMetaSrv *srv = srv_meta; pthread_mutexattr_t attr; if (srv) { kmeta_dbg_func("kmpp meta %p already init\n", srv); kmpp_meta_deinit(); } srv = mpp_calloc(KmppMetaSrv, 1); if (!srv) { mpp_loge_f("kmpp meta malloc failed\n"); return; } pthread_mutexattr_init(&attr); pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&srv->lock, &attr); pthread_mutexattr_destroy(&attr); INIT_LIST_HEAD(&srv->list); kmpp_objdef_get(&srv->def, "KmppMeta"); if (!srv->def) { kmeta_dbg_func("kmpp meta get objdef failed\n"); MPP_FREE(srv); return; } kmpp_objdef_set_prop(srv->def, "priv_size", sizeof(KmppMetaPriv)); kmpp_objdef_add_init(srv->def, kmpp_meta_impl_init); kmpp_objdef_add_deinit(srv->def, kmpp_meta_impl_deinit); { KmppEntry *tbl = NULL; kmpp_objdef_get_entry(srv->def, "size", &tbl); srv->offset_size = tbl ? tbl->tbl.elem_offset : 0; } srv_meta = srv; } MPP_SINGLETON(MPP_SGLN_KMPP_META, kmpp_meta, kmpp_meta_init, kmpp_meta_deinit); static void *meta_key_to_addr(KmppObj meta, KmppMetaKey key, KmppMetaType type) { if (meta) { KmppMetaSrv *srv = srv_meta; rk_u64 val = META_KEY_TO_U64(key, type); KmppEntry *tbl = NULL; kmpp_objdef_get_entry(srv->def, (const char *)&val, &tbl); if (tbl) return ((rk_u8 *)kmpp_obj_to_entry(meta)) + tbl->tbl.elem_offset; } return NULL; } static rk_s32 meta_inc_size(KmppObj meta, rk_s32 val, const char *caller) { rk_s32 ret = 0; if (meta && srv_meta) { void *entry = kmpp_obj_to_entry(meta); rk_s32 offset = srv_meta->offset_size; if (entry && offset) { rk_s32 *p = (rk_s32 *)((rk_u8 *)entry + offset); ret = MPP_FETCH_ADD(p, val); kmeta_dbg_size("meta %p size %d -> %d at %s\n", meta, p[0], ret, caller); } } return ret; } static rk_s32 meta_dec_size(KmppObj meta, rk_s32 val, const char *caller) { rk_s32 ret = 0; if (meta && srv_meta) { void *entry = kmpp_obj_to_entry(meta); rk_s32 offset = srv_meta->offset_size; if (entry && offset) { rk_s32 *p = (rk_s32 *)((rk_u8 *)entry + offset); ret = MPP_FETCH_SUB(p, val); kmeta_dbg_size("meta %p size %d -> %d at %s\n", meta, p[0], ret, caller); } } return ret; } rk_s32 kmpp_meta_get(KmppMeta *meta, const char *caller) { KmppMetaSrv *srv = get_meta_srv(caller); if (!srv) return rk_nok; return kmpp_obj_get(meta, srv->def, caller); } rk_s32 kmpp_meta_put(KmppMeta meta, const char *caller) { KmppMetaSrv *srv = get_meta_srv(caller); if (!srv) return rk_nok; return kmpp_obj_put(meta, caller); } rk_s32 kmpp_meta_size(KmppMeta meta, const char *caller) { return meta_inc_size(meta, 0, caller); } rk_s32 kmpp_meta_dump(KmppMeta meta, const char *caller) { return kmpp_obj_udump_f(meta, caller); } rk_s32 kmpp_meta_dump_all(const char *caller) { KmppMetaSrv *srv = get_meta_srv(caller); if (srv) { KmppMeta meta = NULL; KmppMetaPriv *pos, *n; pthread_mutex_lock(&srv->lock); list_for_each_entry_safe(pos, n, &srv->list, KmppMetaPriv, list) { meta = pos->meta; mpp_logi("meta %p:%d size %d\n", meta, pos->meta_id, kmpp_meta_size(meta, caller)); kmpp_meta_dump(meta, caller); } } return rk_ok; } #define KMPP_META_ACCESSOR(func_type, arg_type, key_type, key_field) \ rk_s32 kmpp_meta_set_##func_type(KmppMeta meta, KmppMetaKey key, arg_type val) \ { \ KmppMetaVal *meta_val = meta_key_to_addr(meta, key, key_type); \ if (!meta_val) \ return rk_nok; \ if (MPP_BOOL_CAS(&meta_val->state, META_VAL_INVALID, META_VAL_VALID)) \ meta_inc_size(meta, 1, __FUNCTION__); \ meta_val->key_field = val; \ MPP_FETCH_OR(&meta_val->state, META_VAL_READY); \ return rk_ok; \ } \ rk_s32 kmpp_meta_get_##func_type(KmppMeta meta, KmppMetaKey key, arg_type *val) \ { \ KmppMetaVal *meta_val = meta_key_to_addr(meta, key, key_type); \ if (!meta_val) \ return rk_nok; \ if (MPP_BOOL_CAS(&meta_val->state, META_READY_MASK, META_VAL_INVALID)) { \ if (val) *val = meta_val->key_field; \ meta_dec_size(meta, 1, __FUNCTION__); \ return rk_ok; \ } \ return rk_nok; \ } \ rk_s32 kmpp_meta_get_##func_type##_d(KmppMeta meta, KmppMetaKey key, arg_type *val, arg_type def) \ { \ KmppMetaVal *meta_val = meta_key_to_addr(meta, key, key_type); \ if (!meta_val) \ return rk_nok; \ if (MPP_BOOL_CAS(&meta_val->state, META_READY_MASK, META_VAL_INVALID)) { \ if (val) *val = meta_val->key_field; \ meta_dec_size(meta, 1, __FUNCTION__); \ } else { \ if (val) *val = def; \ } \ return rk_ok; \ } KMPP_META_ACCESSOR(s32, rk_s32, TYPE_VAL_32, val_s32) KMPP_META_ACCESSOR(s64, rk_s64, TYPE_VAL_64, val_s64) KMPP_META_ACCESSOR(ptr, void *, TYPE_UPTR, val_ptr) rk_s32 kmpp_meta_set_obj(KmppMeta meta, KmppMetaKey key, KmppObj val) { KmppMetaObj *meta_obj = meta_key_to_addr(meta, key, TYPE_SPTR); if (!meta_obj) return rk_nok; if (MPP_BOOL_CAS(&meta_obj->state, META_VAL_INVALID, META_VAL_VALID)) meta_inc_size(meta, 1, __FUNCTION__); { KmppShmPtr *ptr = kmpp_obj_to_shm(val); if (ptr) { meta_obj->val_shm.uaddr = ptr->uaddr; meta_obj->val_shm.kaddr = ptr->kaddr;; MPP_FETCH_OR(&meta_obj->state, META_VAL_IS_SHM); } else { meta_obj->val_shm.uaddr = 0; meta_obj->val_shm.kptr = val; MPP_FETCH_AND(&meta_obj->state, ~META_VAL_IS_SHM); } } MPP_FETCH_OR(&meta_obj->state, META_VAL_READY); return rk_ok; } rk_s32 kmpp_meta_get_obj(KmppMeta meta, KmppMetaKey key, KmppObj *val) { KmppMetaObj *meta_obj = meta_key_to_addr(meta, key, TYPE_SPTR); if (!meta_obj) return rk_nok; META_UNMASK_PROP(&meta_obj->state); if (MPP_BOOL_CAS(&meta_obj->state, META_READY_MASK, META_VAL_INVALID)) { if (val) *val = meta_obj->val_shm.kptr; meta_dec_size(meta, 1, __FUNCTION__); return rk_ok; } return rk_nok; } rk_s32 kmpp_meta_get_obj_d(KmppMeta meta, KmppMetaKey key, KmppObj *val, KmppObj def) { KmppMetaObj *meta_obj = meta_key_to_addr(meta, key, TYPE_SPTR); if (!meta_obj) return rk_nok; META_UNMASK_PROP(&meta_obj->state); if (MPP_BOOL_CAS(&meta_obj->state, META_READY_MASK, META_VAL_INVALID)) { if (val) *val = meta_obj->val_shm.kptr; meta_dec_size(meta, 1, __FUNCTION__); } else { if (val) *val = def ? def : NULL; } return rk_ok; } rk_s32 kmpp_meta_set_shm(KmppMeta meta, KmppMetaKey key, KmppShmPtr *sptr) { KmppMetaObj *meta_obj = (KmppMetaObj *)meta_key_to_addr(meta, key, TYPE_SPTR); if (!meta_obj) return rk_nok; if (MPP_BOOL_CAS(&meta_obj->state, META_VAL_INVALID, META_VAL_VALID)) meta_inc_size(meta, 1, __FUNCTION__); if (sptr) { meta_obj->val_shm.uaddr = sptr->uaddr; meta_obj->val_shm.kaddr = sptr->kaddr; } else { meta_obj->val_shm.uaddr = 0; meta_obj->val_shm.kptr = 0; } if (sptr && sptr->uaddr) MPP_FETCH_OR(&meta_obj->state, META_VAL_IS_SHM); else MPP_FETCH_AND(&meta_obj->state, ~META_VAL_IS_SHM); MPP_FETCH_OR(&meta_obj->state, META_VAL_READY); return rk_ok; } rk_s32 kmpp_meta_get_shm(KmppMeta meta, KmppMetaKey key, KmppShmPtr *sptr) { KmppMetaObj *meta_obj = meta_key_to_addr(meta, key, TYPE_SPTR); if (!meta_obj) return rk_nok; META_UNMASK_PROP(&meta_obj->state); if (MPP_BOOL_CAS(&meta_obj->state, META_READY_MASK, META_VAL_INVALID)) { if (sptr) { sptr->uaddr = meta_obj->val_shm.uaddr; sptr->kaddr = meta_obj->val_shm.kaddr; } meta_dec_size(meta, 1, __FUNCTION__); return rk_ok; } return rk_nok; } rk_s32 kmpp_meta_get_shm_d(KmppMeta meta, KmppMetaKey key, KmppShmPtr *sptr, KmppShmPtr *def) { KmppMetaObj *meta_obj = meta_key_to_addr(meta, key, TYPE_SPTR); if (!meta_obj) return rk_nok; META_UNMASK_PROP(&meta_obj->state); if (MPP_BOOL_CAS(&meta_obj->state, META_READY_MASK, META_VAL_INVALID)) { if (sptr) { sptr->uaddr = meta_obj->val_shm.uaddr; sptr->kaddr = meta_obj->val_shm.kaddr; } meta_dec_size(meta, 1, __FUNCTION__); } else { if (sptr) { if (def) { sptr->uaddr = def->uaddr; sptr->kaddr = def->kaddr; } else { sptr->uaddr = 0; sptr->kaddr = 0; } } } return rk_ok; }