Files
xiuos/Ubiquitous/XiZi_IIoT/board/rzg2ul-m33/amp/src/shm.c
树数在变干 2e11a31da3 support amp
2024-05-22 17:37:23 +08:00

477 lines
18 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS 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.
*/
#include "../include/shm.h"
#include "../include/spinlock.h"
#if PROTOCOL_CHOICE == PROTOCOL_AMP && (PLATFORM_CHOICE == PLATFORM_LINUX_USER || PLATFORM_CHOICE == PLATFORM_RTOS_XIUOS)
/* 共享内存管理信息 */
static struct Shm shm = { 0 };
/* 初始化相关标记信息 */
static volatile uint32_t shm_init_mark = INIT_MARK_RAW_STATE;
static MarkFlag shm_init_lock = ATOMIC_FLAG_INIT;
static int32_t shm_addr_to_offset(void* ptr)
{
/* 指针范围不对 */
if (ptr < shm.shm_total_start || ptr > shm.shm_total_start + shm.shm_cfg->total_shm->len)
{
INFOS("shm_addr_to_offset_error: error range\n");
return -1;
}
return ptr - shm.shm_total_start;
}
static void* shm_offset_to_addr(uint32_t offset)
{
if (offset > shm.shm_cfg->total_shm->len)
{
INFOS("shm_offset_to_addr_error: error range\n");
return NULL;
}
return (void*)(shm.shm_total_start + offset);
}
#if PLATFORM_CHOICE == PLATFORM_LINUX_USER
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <signal.h>
/* SHM模块、内存映射相关数据 */
static int mem_fd = -1;
static int shm_fd = -1;
#endif /* #if PLATFORM_CHOICE == PLATFORM_LINUX_USER */
#if PLATFORM_CHOICE == PLATFORM_RTOS_XIUOS
/* XiUOS的直接放在这里 */
static struct ShmInfos shm_infos = { 0 };
#endif /* PLATFORM_CHOICE == PLATFORM_RTOS_XIUOS */
static int32_t malloc_from_volatile_block(int start_index,int end_index,int size)
{
for (int i = start_index; i < end_index; i++)
{
if (shm.shm_infos->vblock_infos[i].state == VBLOCK_STATE_ENABLE) /* 当前区块还可以尝试继续进行分配 */
{
if (size <= shm.shm_infos->vblock_infos[i].available_size) /* 当前块可以满足此次内存分配请求 */
{
int32_t result = shm.shm_infos->vblock_infos[i].next_alloc_offset;
shm.shm_infos->vblock_infos[i].available_size -= size;
shm.shm_infos->vblock_infos[i].alloc_count += 1;
shm.shm_infos->vblock_infos[i].next_alloc_offset += size;
shm.shm_infos->vblock_current = i;
return result;
}
else /* 当前块无法满足分配要求 */
{
shm.shm_infos->vblock_infos[i].state = VBLOCK_STATE_DISENABLE; /* 当前块弃用,开始启用下一块 */
}
}
else /* 查看当前块能不能重新加入分配 */
{
if (shm.shm_infos->vblock_infos[i].free_count == shm.shm_infos->vblock_infos[i].alloc_count)
{
shm.shm_infos->vblock_infos[i].next_alloc_offset = shm.shm_infos->vblock_infos[i].alloc_start_offset;
shm.shm_infos->vblock_infos[i].available_size = shm.shm_infos->vblock_infos[i].total_length;
shm.shm_infos->vblock_infos[i].free_count = 0;
shm.shm_infos->vblock_infos[i].alloc_count = 0;
shm.shm_infos->vblock_infos[i].state = VBLOCK_STATE_ENABLE;
i --; /* 当前块重新加入分配 */
}
}
}
return -1; /* 分配未成功 */
}
static int32_t shm_init(void)
{
mark_flag_ops.lock(&shm_init_lock); /* 这个锁在RTOS上可以锁全部线程但是在Linux只能锁同一个进程内的线程 */
if (shm_init_mark == INIT_MARK_INITIALIZED) /* 已初始化过了 */
{
mark_flag_ops.unlock(&shm_init_lock);
LOGINFO("shm_init_info: shm init before\n");
return 0;
}
if (shm_init_mark == INIT_MARK_DESTORYED) /* 已经初始化损坏 */
{
mark_flag_ops.unlock(&shm_init_lock);
INFOS("shm_init_error: shm init error before\n");
return -1;
}
struct ShmCfg* shm_cfg = shm_cfg_ops.get_by_id(core_info->id); /* 获取当前核心的共享内存配置信息 */
if (shm_cfg == NULL)
{
shm_init_mark = INIT_MARK_DESTORYED;
mark_flag_ops.unlock(&shm_init_lock);
INFOS("shm_init_error: have no shm cfg for core = %u\n",core_info->id);
return -1;
}
shm.shm_cfg = shm_cfg;
if (shm_cfg->total_shm == NULL)
{
shm_init_mark = INIT_MARK_DESTORYED;
mark_flag_ops.unlock(&shm_init_lock);
INFOS("shm_init_error: must have total shm addr info even have no core shm\n");
return -1;
}
/* 提取各项共享内存配置信息 */
uint64_t total_shm_start = shm_cfg->total_shm->start;
uint32_t total_shm_length = shm_cfg->total_shm->len;
uint64_t total_shm_end = total_shm_start + total_shm_length;
INFOS("shm_init_info: total_shm [start = %p, length = %u KB]\n",(void*)total_shm_start,total_shm_length / KB);
uint64_t core_shm_start = 0U;
uint32_t core_shm_length = 0U;
uint64_t core_shm_end = 0U;
if (shm_cfg->core_shm == NULL) /* 当前节点没有共享内存 */
{
LOGINFO("shm_init_warn: have no core shm\n");
}
else /* 当前节点存在共享内存 */
{
core_shm_start = shm_cfg->core_shm->start;
core_shm_length = shm_cfg->core_shm->len;
core_shm_end = core_shm_start + core_shm_length;
LOGINFO("shm_init_info: core_shm [start = %p, length = %u KB]\n",(void*)core_shm_start,core_shm_length / KB);
}
/* 初始化共享内存管理指针 */
#if PLATFORM_CHOICE == PLATFORM_LINUX_USER
mem_fd = open(MEM_DRIVER, O_RDWR | O_SYNC); /* 打开全映射驱动 */
if (mem_fd < 0)
{
shm_init_mark = INIT_MARK_DESTORYED;
mark_flag_ops.unlock(&shm_init_lock);
INFOS("shm_init_error: open mem dev fail %d\n", mem_fd);
return -1;
}
LOGINFO("shm_init_info: open mem dev success %d\n", mem_fd);
shm_fd = open(SHM_DRIVER_NAME, O_RDWR | O_SYNC); /* 打开SHM模块 */
if (shm_fd < 0)
{
shm_init_mark = INIT_MARK_DESTORYED;
mark_flag_ops.unlock(&shm_init_lock);
INFOS("shm_init_error: open shm dev fail %d\n", shm_fd);
return -1;
}
LOGINFO("shm_init_info: open shm dev success %d\n", shm_fd);
/* 将内核中的共有管理信息映射到用户空间 */
shm.shm_infos = mmap(NULL, MEM_PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
if (shm.shm_infos == NULL)
{
shm_init_mark = INIT_MARK_DESTORYED;
mark_flag_ops.unlock(&shm_init_lock);
INFOS("shm_init_error: mmap shm manage info fail\n");
return -1;
}
/* 映射出内核中的管理信息块 */
shm.shm_total_start = mmap(NULL, total_shm_length, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, total_shm_start);
shm.shm_core_start = shm.shm_total_start + (core_shm_start - total_shm_start);
if (shm.shm_total_start == NULL)
{
shm_init_mark = INIT_MARK_DESTORYED;
mark_flag_ops.unlock(&shm_init_lock);
INFOS("shm_init_error: mmap shm fail\n");
return -1;
}
LOGINFO("shm_init_info: virtual addr [total_start = %p, core_start = %p]\n",shm.shm_total_start,shm.shm_core_start);
#endif /* #if PLATFORM_CHOICE == PLATFORM_LINUX_USER */
#if PLATFORM_CHOICE == PLATFORM_RTOS_XIUOS
shm.shm_infos = &shm_infos;
shm.shm_total_start = (void *)total_shm_start;
shm.shm_core_start = (void *)core_shm_start;
#endif /* PLATFORM_CHOICE == PLATFORM_RTOS_XIUOS */
if (atomic_load(&shm.shm_infos->block_init_mark) == INIT_MARK_INITIALIZED) /* 在整个节点内存探测是否已经被初始化过了 */
{
shm_init_mark = INIT_MARK_INITIALIZED;
mark_flag_ops.unlock(&shm_init_lock);
LOGINFO("shm_init_info: shm init before 2\n");
return 0;
}
uint32_t except_state = INIT_MARK_RAW_STATE; /* 假定该共享内存还未被初始化 */
/* 试图获取初始化权 */
if (!atomic_compare_exchange_strong(&shm.shm_infos->block_init_mark,&except_state,INIT_MARK_INITIALIZING))
{
while (1)
{
uint8_t init_state = atomic_load(&shm.shm_infos->block_init_mark);
if (init_state == INIT_MARK_INITIALIZING)
{
LOGINFO("shm_init_info: wait others shm init over\n");
}
else if (init_state == INIT_MARK_INITIALIZED)
{
shm_init_mark = INIT_MARK_INITIALIZED;
mark_flag_ops.unlock(&shm_init_lock);
LOGINFO("shm_init_info: init by others\n");
return 0;
}
else if (init_state == INIT_MARK_DESTORYED)
{
shm_init_mark = INIT_MARK_DESTORYED;
mark_flag_ops.unlock(&shm_init_lock);
INFOS("shm_init_error: init shm error by others or init mark error\n");
return -1;
}
}
}
/* 开始进行共享内存的初始化 */
shm.shm_infos->block_state_info = BLOCK_STATE_UNUSED; /* 初始共享内存状态 */
if (core_shm_length == 0) /* 当前节点没有共享内存 */
{
atomic_store(&shm.shm_infos->block_init_mark,INIT_MARK_INITIALIZED); /* 通知其他线程共享内存初始化完毕 */
shm_init_mark = INIT_MARK_INITIALIZED;
mark_flag_ops.unlock(&shm_init_lock);
LOGINFO("shm_init_info: init success ,but have no core shm\n");
return 0;
}
/* 初始化当前节点的共享内存 */
uint32_t min_block_size = shm_cfg->min_block_size < MEMORY_ALIGN_SIZE ? MEMORY_ALIGN_SIZE : shm_cfg->min_block_size; /* 短期区块最小区块大小 */
uint32_t pblock_size = shm_cfg->pblock_size > min_block_size ? shm_cfg->pblock_size : 0; /* 长期区块总大小 */
if (pblock_size > 0)
{
shm.shm_infos->block_state_info = shm.shm_infos->block_state_info | BLOCK_STATE_PERSISTENT; /* 共享内存里面有长期块 */
}
uint32_t vblock_size = shm_cfg->vblock_size > min_block_size ? shm_cfg->vblock_size : 0; /* 短期区块总大小 */
uint32_t vblock_each_size = 0U;
if (vblock_size > 0 && SHM_VBLOCK_CNT > 0)
{
shm.shm_infos->block_state_info = shm.shm_infos->block_state_info | BLOCK_STATE_VOLATILE; /* 共享内存里面有短期块 */
vblock_each_size = vblock_size / SHM_VBLOCK_CNT;
if (vblock_each_size < min_block_size) /* 查看内存配置是否合理 */
{
atomic_store(&shm.shm_infos->block_init_mark,INIT_MARK_DESTORYED); /* 告知其他线程共享内存初始化失败 */
shm_init_mark = INIT_MARK_DESTORYED;
mark_flag_ops.unlock(&shm_init_lock);
INFOS("shm_init_error: each vblock is too small vblock_each_size =%u, min_block_size = %u, vblock_size = %u, vblock_count = %u\n",vblock_each_size, min_block_size, vblock_size, SHM_VBLOCK_CNT);
return -1;
}
shm.shm_infos->vblock_each_size = vblock_each_size;
}
INFOS("shm_init_info: pblock_size = %u KB, vblock_size = %u KB, vblock_each_size = %u KB, min_block_size = %u B\n", pblock_size / KB, vblock_size / KB, vblock_each_size / KB, min_block_size);
/* 初始化互斥标记 */
byte_flag_ops.init(&shm.shm_infos->pblock_lock);
byte_flag_ops.init(&shm.shm_infos->vblock_lock);
uint32_t init_offset = core_shm_start - total_shm_start; /* 开始初始化共享内存的管理信息 */
/* 先初始化长期区 */
shm.shm_infos->pblock_info.next_alloc_offset = init_offset;
shm.shm_infos->pblock_info.available_size = pblock_size;
init_offset += pblock_size;
/* 初始化短期区 */
if (vblock_each_size > min_block_size) /* 存在短期区 */
{
for (int i = 0; i < SHM_VBLOCK_CNT; i++)
{
shm.shm_infos->vblock_infos[i].state = VBLOCK_STATE_ENABLE;
shm.shm_infos->vblock_infos[i].alloc_count = 0U;
shm.shm_infos->vblock_infos[i].free_count = 0U;
shm.shm_infos->vblock_infos[i].alloc_start_offset = init_offset;
shm.shm_infos->vblock_infos[i].next_alloc_offset = init_offset;
if (i != SHM_VBLOCK_CNT - 1) /* 非最后一个短期块 */
{
shm.shm_infos->vblock_infos[i].total_length = vblock_each_size;
shm.shm_infos->vblock_infos[i].available_size = vblock_each_size;
init_offset += vblock_each_size;
}
else /* 最后一个短期块 */
{
shm.shm_infos->vblock_infos[i].total_length = vblock_each_size + vblock_size % SHM_VBLOCK_CNT;
shm.shm_infos->vblock_infos[i].available_size = shm.shm_infos->vblock_infos[i].total_length;
init_offset += shm.shm_infos->vblock_infos[i].total_length;
}
INFOS("shm_init_info: index = %d, start_offset = %u, total_length = %u KB\n", i, shm.shm_infos->vblock_infos[i].alloc_start_offset, shm.shm_infos->vblock_infos[i].total_length / KB);
}
if (init_offset != core_shm_end - total_shm_start) /* 是否正确初始化 */
{
atomic_store(&shm.shm_infos->block_init_mark,INIT_MARK_DESTORYED);
shm_init_mark = INIT_MARK_DESTORYED;
mark_flag_ops.unlock(&shm_init_lock);
INFOS("shm_init_error: core_shm_end = %u, init_offset = %u\n", core_shm_end, init_offset);
return -1;
}
}
atomic_store(&shm.shm_infos->block_init_mark,INIT_MARK_INITIALIZED); /* 通知其他线程共享内存初始化完毕 */
shm_init_mark = INIT_MARK_INITIALIZED;
mark_flag_ops.unlock(&shm_init_lock);
LOGINFO("shm_init_success: init shm success\n");
return 0;
}
static void* shm_malloc(uint32_t size,enum MallocType type)
{
if (shm_init_mark != INIT_MARK_INITIALIZED)
{
INFOS("shm_malloc_error: init shm before use\n");
return NULL;
}
if (size == 0 || (shm.shm_infos->block_state_info & type) == 0)
{
INFOS("shm_malloc_warn: malloc size = 0 or unsupport malloc type\n");
return NULL;
}
/* 按照配置信息进行字节对齐 */
size = (size + shm.shm_cfg->bit_align -1) & (~(shm.shm_cfg->bit_align - 1));
switch (type)
{
case MALLOC_TYPE_P:
{
byte_flag_ops.lock(&shm.shm_infos->pblock_lock); /* 长期区锁 */
if (size > shm.shm_infos->pblock_info.available_size) /* 申请的内存大小超过了最大内存限制 */
{
byte_flag_ops.unlock(&shm.shm_infos->pblock_lock); /* 解锁 */
INFOS("shm_malloc_warn: the size is large than max avi size, size = %d, avi size = %d\n", size, shm.shm_infos->pblock_info.available_size);
return NULL;
}
void* result = shm.shm_total_start + shm.shm_infos->pblock_info.next_alloc_offset; /* 记录下需要返回的地址 */
shm.shm_infos->pblock_info.available_size -= size; /* 减去已经被分配的空间大小 */
shm.shm_infos->pblock_info.next_alloc_offset += size; /* 将待分配地址指向下一个位置 */
byte_flag_ops.unlock(&shm.shm_infos->pblock_lock); /* 解锁 */
LOGINFO("shm_malloc_success: MALLOC_TYPE_P [start address: %p, length = %d B]\n", result, size);
return result;
}
case MALLOC_TYPE_V:
{
byte_flag_ops.lock(&shm.shm_infos->vblock_lock); /* 短期锁 */
uint32_t current_volatile_block_index = shm.shm_infos->vblock_current; /* 记录开始查找前短期块的当前位置下标 */
int32_t result = malloc_from_volatile_block(current_volatile_block_index,SHM_VBLOCK_CNT,size); /* 从当前位置往后找 */
if (result < 0) /* 没找到 */
{
result = malloc_from_volatile_block(0,current_volatile_block_index,size); /* 从前往当前位置找 */
}
if (result < 0) /* 无法分配空间 */
{
byte_flag_ops.unlock(&shm.shm_infos->vblock_lock); /* 解锁 */
INFOS("shm_malloc_warn: have no such size space free now!\n");
return NULL;
}
byte_flag_ops.unlock(&shm.shm_infos->vblock_lock); /* 解锁 */
LOGINFO("shm_malloc_success: MALLOC_TYPE_V [start address: %p, length = %d B]\n", shm.shm_total_start + result, size);
return shm.shm_total_start + result;
}
default:
{
INFOS("shm_malloc_warn: not suported alloc type!\n");
return NULL;
}
}
}
static void shm_free(void* ptr)
{
if (shm_init_mark != INIT_MARK_INITIALIZED)
{
INFOS("shm_free: shm not init\n");
return ;
}
if (shm.shm_infos->block_state_info & BLOCK_STATE_VOLATILE == 0)
{
INFOS("shm_free_error: have no volatile blocks\n");
return;
}
if (ptr < shm.shm_core_start || ptr >= shm.shm_core_start + shm.shm_cfg->core_shm->len)
{
INFOS("shm_free_error: not such shm\n");
return ;
}
uint32_t data_offset = ptr - shm.shm_core_start - shm.shm_cfg->pblock_size;
uint32_t block_index = data_offset / shm.shm_infos->vblock_each_size; /* 读取短期块的控制信息 */
byte_flag_ops.lock(&shm.shm_infos->vblock_lock);
shm.shm_infos->vblock_infos[block_index].free_count += 1;
LOGINFO("shm_free_success: start = %p, index = %u, free_count = %u\n",ptr ,block_index, shm.shm_infos->vblock_infos[block_index].free_count);
byte_flag_ops.unlock(&shm.shm_infos->vblock_lock);
}
struct ShmOps shm_ops =
{
.addr_to_offset = shm_addr_to_offset,
.offset_to_addr = shm_offset_to_addr,
.shm_init = shm_init,
.shm_malloc = shm_malloc,
.shm_free = shm_free
};
#endif /* PROTOCOL_CHOICE == PROTOCOL_AMP && (PLATFORM_CHOICE == PLATFORM_LINUX_USER || PLATFORM_CHOICE == PLATFORM_RTOS_XIUOS) */