singe/thirdparty/rockchip-mpp/osal/mpp_ring.c
2026-09-10 20:17:28 -05:00

269 lines
6.6 KiB
C

/* SPDX-License-Identifier: Apache-2.0 OR MIT */
/*
* Copyright (c) 2026 Rockchip Electronics Co., Ltd.
*/
#define MODULE_TAG "mpp_ring"
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <linux/memfd.h>
#include "mpp_env.h"
#include "mpp_debug.h"
#include "mpp_common.h"
#include "mpp_mem_pool.h"
#include "mpp_singleton.h"
#include "mpp_ring.h"
#define RING_DBG_FLOW (0x00000001)
#define RING_DBG_INIT (0x00000002)
#define ring_dbg(flag, fmt, ...) mpp_dbg(mpp_ring_debug, flag, fmt, ## __VA_ARGS__)
#define ring_dbg_f(flag, fmt, ...) mpp_dbg_f(mpp_ring_debug, flag, fmt, ## __VA_ARGS__)
#define ring_dbg_flow(fmt, ...) ring_dbg(RING_DBG_FLOW, fmt, ## __VA_ARGS__)
#define ring_dbg_init(fmt, ...) ring_dbg(RING_DBG_INIT, fmt, ## __VA_ARGS__)
typedef struct MppRingImpl_t {
void *ptr;
rk_s32 fd;
rk_s32 size;
rk_s32 size_align;
} MppRingImpl;
static const char *module_name = MODULE_TAG;
static MppMemPool pool_ring = NULL;
static rk_s32 page_sz = 0;
static rk_u32 mpp_ring_debug = 0;
#ifdef __BIONIC__
/* Android ndk before API 29 */
#include <sys/syscall.h>
#ifndef MFD_CLOEXEC
#define MFD_CLOEXEC 0x0001U
#endif
#ifndef __NR_memfd_create
#if defined(__aarch64__) && !defined(__ILP32__)
# define __NR_memfd_create 279 /* 64-bit ARM64 */
#elif defined(__arm__) || defined(__aarch64__) && defined(__ILP32__)
# define __NR_memfd_create 356 /* 32-bit ARM / compat */
#else
#error "please define __NR_memfd_create for your arch"
#endif
#endif
static inline int memfd_create_impl(const char *name, unsigned int flags)
{
return syscall(__NR_memfd_create, name, flags);
}
#define memfd_create memfd_create_impl
#endif
static void *mmap_twice(RK_S32 fd, RK_S32 n)
{
char *whole;
char *base;
char *base2;
whole = mmap(NULL, 2 * n, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
if (whole == MAP_FAILED) {
mpp_loge("whole mmap size %d failed %s\n", 2 * n, strerror(errno));
return NULL;
}
base = mmap(whole, n, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, fd, 0);
if (base == MAP_FAILED) {
mpp_loge("first segment mmap size %d failed %s\n", n, strerror(errno));
munmap(whole, 2 * n);
return NULL;
}
base2 = mmap(whole + n, n, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, fd, 0);
if (base2 == MAP_FAILED) {
munmap(whole, 2 * n);
mpp_loge("second segment mmap size %d failed %s\n", n, strerror(errno));
return NULL;
}
ring_dbg_flow("mmap twice fd %d size %d whole %p base %p:%p\n",
fd, n, whole, base, base2);
return whole;
}
static void munmap_twice(void *ptr, rk_s32 n)
{
if (ptr) {
ring_dbg_flow("mummap twice size %d ptr %p:%p\n", n, ptr, (char *)ptr + n);
munmap(ptr, 2 * n);
}
}
static void mpp_ring_srv_init()
{
if (pool_ring)
return;
mpp_env_get_u32("mpp_ring_debug", &mpp_ring_debug, 0);
page_sz = sysconf(_SC_PAGESIZE);
pool_ring = mpp_mem_pool_init_f(MODULE_TAG, sizeof(MppRingImpl));
ring_dbg_init("page size %d\n", page_sz);
}
static void mpp_ring_srv_deinit()
{
if (pool_ring) {
mpp_mem_pool_deinit_f(pool_ring);
pool_ring = NULL;
}
}
MPP_SINGLETON(MPP_SGLN_RING, mpp_ring, mpp_ring_srv_init, mpp_ring_srv_deinit)
rk_s32 mpp_ring_get(MppRing *ring, rk_s32 size, const char *name)
{
MppRingImpl *impl = NULL;
void *ptr = NULL;
rk_s32 fd = -1;
rk_s32 size_align;
mpp_env_get_u32("mpp_ring_debug", &mpp_ring_debug, 0);
if (NULL == ring || size <= 0) {
mpp_loge_f("invalid input ring %p size %d\n", ring, size);
return rk_nok;
}
*ring = NULL;
if (NULL == name)
name = module_name;
size_align = MPP_ALIGN(size, page_sz);
do {
fd = memfd_create(name, MFD_CLOEXEC);
if (fd < 0) {
mpp_loge_f("failed to create memfd ret %d %s\n", fd, strerror(errno));
break;
}
if (ftruncate(fd, size_align) < 0) {
mpp_loge_f("failed to truncate memfd ret %d %s\n", fd, strerror(errno));
break;
}
ptr = mmap_twice(fd, size_align);
if (ptr == NULL)
break;
impl = (MppRingImpl*)mpp_mem_pool_get_f(pool_ring);
if (NULL == impl) {
mpp_loge_f("failed to get ring impl from pool\n");
break;
}
impl->ptr = ptr;
impl->fd = fd;
impl->size = size;
impl->size_align = size_align;
*ring = impl;
ring_dbg_flow("mpp_ring_get size %d -> aligned %d fd %d ptr %p\n",
size, size_align, fd, ptr);
return rk_ok;
} while (0);
munmap_twice(ptr, size_align);
if (fd >= 0)
close(fd);
return rk_nok;
}
rk_s32 mpp_ring_put(MppRing ring)
{
MppRingImpl *impl = (MppRingImpl *)ring;
if (NULL == impl)
return rk_nok;
ring_dbg_flow("mpp_ring_put aligned %d fd %d ptr %p\n",
impl->size_align, impl->fd, impl->ptr);
munmap_twice(impl->ptr, impl->size_align);
if (impl->fd >= 0)
close(impl->fd);
mpp_mem_pool_put_f(pool_ring, impl);
return rk_ok;
}
void *mpp_ring_get_ptr(MppRing ring)
{
MppRingImpl *impl = (MppRingImpl *)ring;
return (impl != NULL) ? impl->ptr : NULL;
}
void *mpp_ring_resize(MppRing ring, rk_s32 new_size)
{
MppRingImpl *impl = (MppRingImpl *)ring;
rk_s32 new_aligned;
void *new_ptr;
if (!impl || new_size <= 0)
return NULL;
new_aligned = MPP_ALIGN(new_size, page_sz);
if (new_aligned == impl->size)
return impl->ptr;
munmap_twice(impl->ptr, impl->size);
if (ftruncate(impl->fd, new_aligned) < 0) {
mpp_loge_f("resize ftruncate failed %s\n", strerror(errno));
/* rollback original buffer */
impl->ptr = mmap_twice(impl->fd, impl->size);
return impl->ptr;
}
new_ptr = mmap_twice(impl->fd, new_aligned);
if (new_ptr == MAP_FAILED) {
mpp_loge("resize mmap_twice failed %s\n", strerror(errno));
/* rollback original buffer */
if (ftruncate(impl->fd, impl->size_align) < 0) {
mpp_loge("resize rollback ftruncate failed %s\n", strerror(errno));
} else {
new_ptr = mmap_twice(impl->fd, impl->size);
new_aligned = impl->size;
}
}
ring_dbg_flow("mpp_ring_reisze %p:%d -> %p:%d\n",
impl->ptr, impl->size, new_ptr, new_aligned);
impl->ptr = new_ptr;
impl->size = new_size;
impl->size_align = new_aligned;
return new_ptr;
}