//作用:固定大小内存管理器的代码,内存分区代码
/*
*********************************************************************************************************
* uC/OS-III
* The Real-Time Kernel
*
* Copyright 2009-2022 Silicon Laboratories Inc. www.silabs.com
*
* SPDX-License-Identifier: APACHE-2.0
*
* This software is subject to an open source license and is distributed by
* Silicon Laboratories Inc. pursuant to the terms of the Apache License,
* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0.
*
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* 内存分区管理
*
* 文件: os_mem.c
* 版本: V3.08.02
*********************************************************************************************************
*/
#define MICRIUM_SOURCE
#include "os.h"
#ifdef VSC_INCLUDE_SOURCE_FILE_NAMES
const CPU_CHAR *os_mem__c = "$Id: $";
#endif
#if (OS_CFG_MEM_EN > 0u)
/*
************************************************************************************************************************
* 创建内存分区
*
* 描述: 创建一个由 uC/OS-III 管理的固定大小的内存分区。
*
* 参数: p_mem 是指向用户内存空间中分配的内存分区控制块的指针。
*
* p_name 是指向 ASCII 字符串的指针,用于为内存分区提供名称。
*
* p_addr 是内存分区的起始地址。
*
* n_blks 是从分区中创建的内存块数量。
*
* blk_size 是内存分区中每个块的大小(以字节为单位)。
*
* p_err 是指向包含错误消息的变量的指针,此函数会将其设置为以下之一:
*
* OS_ERR_NONE 如果内存分区已正确创建
* OS_ERR_ILLEGAL_CREATE_RUN_TIME 如果在调用 OSSafetyCriticalStart() 之后尝试创建内存分区
* OS_ERR_MEM_CREATE_ISR 如果从 ISR 中调用此函数
* OS_ERR_MEM_INVALID_BLKS 用户指定的块数无效(必须 >= 2)
* OS_ERR_MEM_INVALID_P_ADDR 如果指定的内存分区存储地址无效,或者块未对齐到指针边界
* OS_ERR_MEM_INVALID_SIZE 用户指定的块大小无效
* - 必须大于指针的大小
* - 必须能够容纳整数个指针
* OS_ERR_OBJ_CREATED 如果内存分区已创建
* 返回: 无
*
* 注意: 无
************************************************************************************************************************
*/
void OSMemCreate(OS_MEM *p_mem, CPU_CHAR *p_name, void *p_addr, OS_MEM_QTY n_blks, OS_MEM_SIZE blk_size, OS_ERR *p_err)
{
#if (OS_CFG_ARG_CHK_EN > 0u)
CPU_DATA align_msk;
#endif
OS_MEM_QTY i;
OS_MEM_QTY loops;
CPU_INT08U *p_blk;
void **p_link;
CPU_SR_ALLOC();
#ifdef OS_SAFETY_CRITICAL
if (p_err == (OS_ERR *)0) {
OS_SAFETY_CRITICAL_EXCEPTION();
return;
}
#endif
#ifdef OS_SAFETY_CRITICAL_IEC61508
if (OSSafetyCriticalStartFlag == OS_TRUE) {
*p_err = OS_ERR_ILLEGAL_CREATE_RUN_TIME;
return;
}
#endif
#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u)
if (OSIntNestingCtr > 0u) { /* 不允许从 ISR 调用 */
*p_err = OS_ERR_MEM_CREATE_ISR;
return;
}
#endif
#if (OS_CFG_ARG_CHK_EN > 0u)
if (p_addr == (void *)0) { /* 必须传递有效的内存分区地址 */
*p_err = OS_ERR_MEM_INVALID_P_ADDR;
return;
}
if (n_blks < 2u) { /* 每个分区至少需要 2 个块 */
*p_err = OS_ERR_MEM_INVALID_BLKS;
return;
}
if (blk_size < sizeof(void *)) { /* 必须包含至少一个指针的空间 */
*p_err = OS_ERR_MEM_INVALID_SIZE;
return;
}
align_msk = sizeof(void *) - 1u;
if (align_msk > 0u) {
if (((CPU_ADDR)p_addr & align_msk) != 0u) { /* 必须对齐到指针大小 */
*p_err = OS_ERR_MEM_INVALID_P_ADDR;
return;
}
if ((blk_size & align_msk) != 0u) { /* 块大小必须是地址大小的倍数 */
*p_err = OS_ERR_MEM_INVALID_SIZE;
return;
}
}
#endif
p_link = (void **)p_addr; /* 创建空闲内存块的链表 */
p_blk = (CPU_INT08U *)p_addr;
loops = n_blks - 1u;
for (i = 0u; i < loops; i++) {
p_blk += blk_size;
*p_link = (void *)p_blk; /* 在当前块中保存指向下一个块的指针 */
p_link = (void **)(void *)p_blk; /* 定位到下一个块 */
}
*p_link = (void *)0; /* 最后一个内存块指向 NULL */
CPU_CRITICAL_ENTER();
#if (OS_OBJ_TYPE_REQ > 0u)
#if (OS_CFG_OBJ_CREATED_CHK_EN > 0u)
if (p_mem->Type == OS_OBJ_TYPE_MEM) {
CPU_CRITICAL_EXIT();
*p_err = OS_ERR_OBJ_CREATED;
return;
}
#endif
p_mem->Type = OS_OBJ_TYPE_MEM; /* 设置对象类型 */
#endif
#if (OS_CFG_DBG_EN > 0u)
p_mem->NamePtr = p_name; /* 保存内存分区的名称 */
#else
(void)p_name;
#endif
p_mem->AddrPtr = p_addr; /* 存储内存分区的起始地址 */
p_mem->FreeListPtr = p_addr; /* 初始化指向空闲块池的指针 */
p_mem->NbrFree = n_blks; /* 存储 MCB 中的空闲块数量 */
p_mem->NbrMax = n_blks;
p_mem->BlkSize = blk_size; /* 存储每个内存块的大小 */
#if (OS_CFG_DBG_EN > 0u)
OS_MemDbgListAdd(p_mem);
OSMemQty++;
#endif
OS_TRACE_MEM_CREATE(p_mem, p_name);
CPU_CRITICAL_EXIT();
*p_err = OS_ERR_NONE;
}
/*
************************************************************************************************************************
* 获取内存块
*
* 描述: 从内存分区中获取一个内存块。
*
* 参数: p_mem 是指向内存分区控制块的指针
*
* p_err 是指向包含错误消息的变量的指针,此函数会将其设置为以下之一:
*
* OS_ERR_NONE 如果内存分区已正确创建
* OS_ERR_MEM_INVALID_P_MEM 如果传递了 NULL 指针作为 'p_mem'
* OS_ERR_MEM_NO_FREE_BLKS 如果没有更多的空闲内存块可以分配给调用者
* OS_ERR_OBJ_TYPE 如果 'p_mem' 指向的不是一个内存分区
*
* 返回: 如果没有检测到错误,返回指向内存块的指针
* 如果检测到错误,返回指向 NULL 的指针
*
* 注意: 无
************************************************************************************************************************
*/
void *OSMemGet(OS_MEM *p_mem, OS_ERR *p_err)
{
void *p_blk;
CPU_SR_ALLOC();
#ifdef OS_SAFETY_CRITICAL
if (p_err == (OS_ERR *)0) {
OS_SAFETY_CRITICAL_EXCEPTION();
return ((void *)0);
}
#endif
OS_TRACE_MEM_GET_ENTER(p_mem);
#if (OS_CFG_ARG_CHK_EN > 0u)
if (p_mem == (OS_MEM *)0) { /* 必须指向一个有效的内存分区 */
OS_TRACE_MEM_GET_FAILED(p_mem);
OS_TRACE_MEM_GET_EXIT(OS_ERR_MEM_INVALID_P_MEM);
*p_err = OS_ERR_MEM_INVALID_P_MEM;
return ((void *)0);
}
#endif
#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u)
if (p_mem->Type != OS_OBJ_TYPE_MEM) { /* 确保内存块已创建 */
OS_TRACE_MEM_GET_EXIT(OS_ERR_OBJ_TYPE);
*p_err = OS_ERR_OBJ_TYPE;
return ((void *)0);
}
#endif
CPU_CRITICAL_ENTER();
if (p_mem->NbrFree == 0u) { /* 检查是否有空闲的内存块 */
CPU_CRITICAL_EXIT();
OS_TRACE_MEM_GET_FAILED(p_mem);
OS_TRACE_MEM_GET_EXIT(OS_ERR_MEM_NO_FREE_BLKS);
*p_err = OS_ERR_MEM_NO_FREE_BLKS; /* 通知调用者内存分区为空 */
return ((void *)0); /* 返回 NULL 指针给调用者 */
}
p_blk = p_mem->FreeListPtr; /* 指向下一个空闲的内存块 */
p_mem->FreeListPtr = *(void **)p_blk; /* 调整指针到新的空闲列表 */
p_mem->NbrFree--; /* 该分区中的内存块数量减少一个 */
CPU_CRITICAL_EXIT();
OS_TRACE_MEM_GET(p_mem);
OS_TRACE_MEM_GET_EXIT(OS_ERR_NONE);
*p_err = OS_ERR_NONE; /* 没有错误 */
return (p_blk); /* 返回内存块给调用者 */
}
/*
************************************************************************************************************************
* 释放内存块
*
* 描述: 将一个内存块返回到内存分区。
*
* 参数: p_mem 是指向内存分区控制块的指针
*
* p_blk 是指向要释放的内存块的指针
*
* p_err 是指向包含此函数返回的错误代码的变量的指针。
*
* OS_ERR_NONE 如果内存块已插入到分区中
* OS_ERR_MEM_FULL 如果将内存块返回到一个已经满的内存分区(释放的块比分配的多!)
* OS_ERR_MEM_INVALID_P_BLK 如果传递了 NULL 指针作为要释放的块
* OS_ERR_MEM_INVALID_P_MEM 如果传递了 NULL 指针作为 'p_mem'
* OS_ERR_OBJ_TYPE 如果 'p_mem' 指向的不是一个内存分区
*
* 返回: 无
*
* 注意: 无
************************************************************************************************************************
*/
void OSMemPut(OS_MEM *p_mem, void *p_blk, OS_ERR *p_err)
{
CPU_SR_ALLOC();
#ifdef OS_SAFETY_CRITICAL
if (p_err == (OS_ERR *)0) {
OS_SAFETY_CRITICAL_EXCEPTION();
return;
}
#endif
OS_TRACE_MEM_PUT_ENTER(p_mem, p_blk);
#if (OS_CFG_ARG_CHK_EN > 0u)
if (p_mem == (OS_MEM *)0) { /* 必须指向一个有效的内存分区 */
OS_TRACE_MEM_PUT_FAILED(p_mem);
OS_TRACE_MEM_PUT_EXIT(OS_ERR_MEM_INVALID_P_MEM);
*p_err = OS_ERR_MEM_INVALID_P_MEM;
return;
}
if (p_blk == (void *)0) { /* 必须释放一个有效的块 */
OS_TRACE_MEM_PUT_FAILED(p_mem);
OS_TRACE_MEM_PUT_EXIT(OS_ERR_MEM_INVALID_P_BLK);
*p_err = OS_ERR_MEM_INVALID_P_BLK;
return;
}
#endif
#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u)
if (p_mem->Type != OS_OBJ_TYPE_MEM) { /* 确保内存块已创建 */
OS_TRACE_MEM_PUT_EXIT(OS_ERR_OBJ_TYPE);
*p_err = OS_ERR_OBJ_TYPE;
return;
}
#endif
CPU_CRITICAL_ENTER();
if (p_mem->NbrFree >= p_mem->NbrMax) { /* 确保所有块未全部返回 */
CPU_CRITICAL_EXIT();
OS_TRACE_MEM_PUT_FAILED(p_mem);
OS_TRACE_MEM_PUT_EXIT(OS_ERR_MEM_FULL);
*p_err = OS_ERR_MEM_FULL;
return;
}
*(void **)p_blk = p_mem->FreeListPtr; /* 将释放的块插入到空闲块列表中 */
p_mem->FreeListPtr = p_blk;
p_mem->NbrFree++; /* 该分区中的内存块数量增加一个 */
CPU_CRITICAL_EXIT();
OS_TRACE_MEM_PUT(p_mem);
OS_TRACE_MEM_PUT_EXIT(OS_ERR_NONE);
*p_err = OS_ERR_NONE; /* 通知调用者内存块已释放 */
}
/*
************************************************************************************************************************
* 将内存分区添加到调试列表
*
* 描述: 此函数由 OSMemCreate() 调用,将内存分区添加到调试表中。
*
* 参数: p_mem 是指向内存分区的指针
*
* 返回: 无
*
* 注意: 此函数是 uC/OS-III 的内部函数,您的应用程序不应调用它。
************************************************************************************************************************
*/
#if (OS_CFG_DBG_EN > 0u)
void OS_MemDbgListAdd (OS_MEM *p_mem)
{
p_mem->DbgPrevPtr = (OS_MEM *)0;
if (OSMemDbgListPtr == (OS_MEM *)0) {
p_mem->DbgNextPtr = (OS_MEM *)0;
} else {
p_mem->DbgNextPtr = OSMemDbgListPtr;
OSMemDbgListPtr->DbgPrevPtr = p_mem;
}
OSMemDbgListPtr = p_mem;
}
#endif
/*
************************************************************************************************************************
* 初始化内存分区管理器
*
* 描述: 此函数由 uC/OS-III 调用,用于初始化内存分区管理器。您的应用程序必须不调用此函数。
*
* 参数: 无
*
* 返回: 无
*
* 注意: 此函数是 uC/OS-III 的内部函数,您的应用程序不应调用它。
************************************************************************************************************************
*/
void OS_MemInit (OS_ERR *p_err)
{
#if (OS_CFG_DBG_EN > 0u)
OSMemDbgListPtr = (OS_MEM *)0;
OSMemQty = 0u;
#endif
*p_err = OS_ERR_NONE;
}
#endif
标签:err,UcOs,ERR,mem,MEM,源码,内存,OS
From: https://www.cnblogs.com/lanlincmos/p/18518570