/* ----------------------------------------------------------------------------
 * Copyright (c) Huawei Technologies Co., Ltd. 2013-2019. All rights reserved.
 * Description: LiteOS Mem Module Implementation
 * Author: Huawei LiteOS Team
 * Create: 2013-05-12
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * 1. Redistributions of source code must retain the above copyright notice, this list of
 * conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
 * of conditions and the following disclaimer in the documentation and/or other materials
 * provided with the distribution.
 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
 * to endorse or promote products derived from this software without specific prior written
 * permission.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * --------------------------------------------------------------------------- */

#include "los_memory_pri.h"
#include "los_memory_internal.h"

#include "string.h"
#include "securec.h"
#include "los_hwi.h"
#include "los_config.h"
#include "los_typedef.h"
#include "los_task_pri.h"
#include "los_exc.h"

#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */

#define HEAP_CAST(t, exp)   ((t)(exp))//这个宏定义是一个类型转换的快捷方式。它接受两个参数，t 表示目标类型，exp 是需要进行类型转换的表达式。这个宏最终会将 exp 转换为类型 t。
#define HEAP_ALIGN          sizeof(UINTPTR)//这个宏定义定义了 HEAP_ALIGN，它的值是 sizeof(UINTPTR)。sizeof 操作符用于返回其操作数的大小（以字节为单位），所以 HEAP_ALIGN 的值将取决于 UINTPTR 类型的大小。
#define MALLOC_MAXSIZE      (0xFFFFFFFF - HEAP_ALIGN + 1)//这个宏定义了 MALLOC_MAXSIZE，它的值是 0xFFFFFFFF - HEAP_ALIGN + 1。在这里，0xFFFFFFFF 表示一个32位无符号整数的最大值，HEAP_ALIGN 已经在上面定义过了。这个宏定义似乎是用来表示在分配内存时可能的最大尺寸。

/*
 * Description : look up the next memory node according to one memory node in the memory block list.
 * Input       : struct LosHeapManager *heapMan --- Pointer to the manager,to distinguish heap
 *               struct LosHeapNode *node --- Size of memory in bytes to allocate
 * Return      : Pointer to next memory node
 */
 /*这个函数的作用是获取下一个堆节点的指针。具体实现过程如下：
如果当前节点已经是最后一个节点（即 node 等于堆管理器的尾节点），则返回 NULL。
否则，计算出下一个节点的指针。根据结构体 LosHeapNode 的定义可知，每个节点都有一个 data 指针和一个 size 字段。为了得到下一个节点的指针，需要将当前节点的 data 指针加上当前节点的 size 字段。
这个结果是一个地址，需要将其转换成 struct LosHeapNode* 类型的指针。可以通过先将地址转换为 UINTPTR 类型，再强制转换为 struct LosHeapNode* 来实现这一点。
返回下一个节点的指针。*/
struct LosHeapNode* OsHeapPrvGetNext(struct LosHeapManager *heapMan, struct LosHeapNode *node)
{
    return (heapMan->tail == node) ? NULL : (struct LosHeapNode *)(UINTPTR)(node->data + node->size);
}

#ifdef LOSCFG_MEM_TASK_STAT
/*该函数接受两个参数：heapMan 表示堆管理器的指针，size 表示堆的初始大小。该函数的作用是初始化堆的统计信息，
即将 heapMan->stat 结构体清零，
并设置 heapMan->stat.memTotalUsed 和 heapMan->stat.memTotalPeak，表示内存使用情况的总量和峰值。
具体实现过程如下：
首先调用 memset_s 函数将 heapMan->stat 清零，确保所有字段的值都为 0。
接着，设置 heapMan->stat.memTotalUsed 的值为 sizeof(struct LosHeapNode) + sizeof(struct LosHeapManager)，即堆管理器结构体和堆节点结构体的大小之和，这是堆使用的总
将 heapMan->stat.memTotalPeak 的初始值也设为 heapMan->stat.memTotalUsed，表示在堆使用过程中的最高峰值。
这段代码的前提条件是 LOSCFG_MEM_TASK_STAT 宏定义已经被定义，否则该函数不会被编译。*/
VOID OsHeapStatInit(struct LosHeapManager *heapMan, UINT32 size)
{
    (VOID)memset_s(&heapMan->stat, sizeof(Memstat), 0, sizeof(Memstat));

    heapMan->stat.memTotalUsed = sizeof(struct LosHeapNode) + sizeof(struct LosHeapManager);
    heapMan->stat.memTotalPeak = heapMan->stat.memTotalUsed;
}
/*该函数的作用是向堆的统计信息中添加被使用的内存块。具体实现过程如下：
首先定义了两个变量 taskId 和 blockSize。taskId 用于记录当前任务的 ID，blockSize 表示要添加的内存块的大小，
包括堆节点结构体和节点存储的数据大小。
然后，通过条件判断来确定 taskId 的值。如果当前任务不为空且处于非中断状态（OS_INT_INACTIVE），
则将 taskId 设置为当前任务的 ID（通过 LOS_CurTaskIDGet 函数获取）。否则，将 taskId 设置为 TASK_NUM - 1，
表示该内存块属于最后一个任务。
将节点的 taskId 字段设置为 taskId，以便记录该内存块所属的任务。
最后，调用 OS_MEM_ADD_USED 宏来更新堆的统计信息。该宏会将 blockSize 和 taskId 传递给堆管理器的 stat 结构体，
以便记录已使用内存的总量和各任务的内存使用情况。
该函数的目的是在堆的统计信息中记录每个内存块的使用情况，以便进行内存管理和监控。*/
VOID OsHeapStatAddUsed(struct LosHeapManager *heapMan, struct LosHeapNode *node)
{
    UINT32 taskId;
    UINT32 blockSize = sizeof(struct LosHeapNode) + node->size;

    if ((OsCurrTaskGet() != NULL) && OS_INT_INACTIVE) {
        /*
         * after OsTaskInit, OsCurrTaskGet() is not null, but id is the same
         * as (LOSCFG_BASE_CORE_TSK_LIMIT + 1), so it will be recorded into
         * the last one of the array.
         */
        taskId = LOS_CurTaskIDGet();
    } else {
        taskId = TASK_NUM - 1;
    }

    node->taskId = taskId;
    OS_MEM_ADD_USED(&heapMan->stat, blockSize, taskId);
}
/*该函数的作用是从堆的统计信息中减少被使用的内存块。具体实现过程如下：
首先定义了两个变量 taskId 和 blockSize。taskId 用于记录当前节点所属的任务 ID，该值在添加内存块时被设置；
blockSize 表示要减少的内存块的大小，包括堆节点结构体和节点存储的数据大小。
调用 OS_MEM_REDUCE_USED 宏来更新堆的统计信息。该宏会将 blockSize 和 taskId 传递给堆管理器的 stat 结构体，
以便记录已使用内存的总量和各任务的内存使用情况。
该函数的目的是在堆的统计信息中记录每个内存块的使用情况，以便进行内存管理和监控。和 OsHeapStatAddUsed 函数相反，
该函数的作用是将内存块从使用中状态转变为未使用状态。*/
VOID OsHeapStatDecUsed(struct LosHeapManager *heapMan, struct LosHeapNode *node)
{
    UINT32 taskId = node->taskId;
    UINT32 blockSize = sizeof(struct LosHeapNode) + node->size;

    OS_MEM_REDUCE_USED(&heapMan->stat, blockSize, taskId);
}

#else /* LOSCFG_MEM_TASK_STAT */
//函数用于初始化堆管理器的内存统计信息。它接受两个参数：heapMan 表示堆管理器的指针，size 表示堆的总大小。在这个备选实现中，该函数没有任何具体的实现操作，直接返回。
VOID OsHeapStatInit(struct LosHeapManager *heapMan, UINT32 size) { }
//函数用于向堆的统计信息中添加被使用的内存块。它接受两个参数：heapMan 表示堆管理器的指针，node 表示要添加到统计信息中的堆节点指针。在这个备选实现中，该函数没有任何具体的实现操作，什么也不做。
VOID OsHeapStatAddUsed(struct LosHeapManager *heapMan, struct LosHeapNode *node) { }
//函数用于从堆的统计信息中减少被使用的内存块。它接受两个参数：heapMan 表示堆管理器的指针，node 表示要从统计信息中减少使用的堆节点指针。在这个备选实现中，该函数没有任何具体的实现操作，什么也不做。
VOID OsHeapStatDecUsed(struct LosHeapManager *heapMan, struct LosHeapNode *node) { }

#endif /* LOSCFG_MEM_TASK_STAT */

#ifdef LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK
/*这段代码实现了一个堆完整性检查的函数 OsHeapIntegrityCheck，用于检查堆内存的完整性，
以确保堆管理器中的内存块没有被破坏或越界。让我逐步解释这段代码的功能：
首先，通过 (struct LosHeapNode *)(heap + 1) 的方式来获取第一个堆节点的地址，其中 heap 是指向堆管理器结构体的指针。
然后，计算出堆的起始地址和结束地址，其中 heapStart 表示堆的起始地址，heapEnd 表示堆的结束地址。
接下来进入循环，遍历堆中的每个节点。在循环内部，首先检查当前节点的地址是否位于堆的范围内，如果节点地址小于堆的起始地址或大于堆的结束地址，
则说明堆节点已经被破坏或越界，此时触发错误处理并返回 LOS_NOK 表示检查失败。
如果当前节点的地址在合法范围内，则通过 OsHeapPrvGetNext 函数获取下一个节点的地址，继续进行下一轮的检查。
当所有节点都通过合法性检查后，函数返回 LOS_OK 表示堆的完整性检查通过。
总之，这段代码实现了对堆内存完整性的检查，避免了堆内存被破坏或越界，确保了堆管理器中的内存块的正确性。*/
UINT32 OsHeapIntegrityCheck(struct LosHeapManager *heap)
{
    struct LosHeapNode *node = (struct LosHeapNode *)(heap + 1);
    UINTPTR heapStart = (UINTPTR)heap;
    UINTPTR heapEnd = (UINTPTR)node + heap->size;

    while (node != NULL) {
        if ((UINTPTR)node < heapStart || (UINTPTR)node > heapEnd) {
            LOS_Panic("node %p has been corrupted.\n", node);
            return LOS_NOK;
        }

        node = OsHeapPrvGetNext(heap, node);
    }

    return LOS_OK;
}

#else /* LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK */
//这段代码实现了一个名为 OsHeapIntegrityCheck 的函数，它接受一个指向 LosHeapManager 结构体的指针作为参数，并直接返回 LOS_OK。
UINT32 OsHeapIntegrityCheck(struct LosHeapManager *heap)
{
    return LOS_OK;
}

#endif /* LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK */

#ifdef LOSCFG_KERNEL_MEM_SLAB_EXTENTION
/*接受一个指向内存池的指针 pool 和一个表示需要分配内存大小的参数 size。
在函数内部，调用 OsHeapAlloc 函数将内存分配操作委托给堆内存管理器进行处理。
最终将堆内存管理器返回的内存分配结果直接返回给调用者。*/
VOID *OsMemAlloc(VOID *pool, UINT32 size)
{
    return OsHeapAlloc(pool, size);
}
/*接受一个指向内存池的指针 pool 和一个指向待释放内存块的指针 ptr。
在函数内部，调用 OsHeapFree 函数将内存释放操作委托给堆内存管理器进行处理。
检查堆内存管理器的释放操作是否成功，如果成功则返回 LOS_OK 表示释放成功，否则返回 LOS_NOK 表示释放失败。*/
UINT32 OsMemFree(VOID *pool, const VOID *ptr)
{
    if (OsHeapFree(pool, ptr) == TRUE) {
        return LOS_OK;
    } else {
        return LOS_NOK;
    }
}

#endif /* LOSCFG_KERNEL_MEM_SLAB_EXTENTION */

/*
 * Description : To initialize the heap memory and get the begin address and size of heap memory,
 *               then initialize LosHeapManager.
 * Input       : VOID *pool  --- begin address of the heap memory pool
 *               UITN32 size --- size of the heap memory pool
 * Return      : 1:success 0:error
 */
/*这段代码实现了一个名为 OsHeapInit 的函数，用于初始化堆内存管理器。让我逐步解释这段代码的功能：
首先，函数接受一个指向内存池的指针 pool 和表示内存池大小的参数 size。
接着，代码将 pool 指针强制类型转换为 struct LosHeapManager 类型的指针 heapMan，以便后续对堆管理器结构体成员的操作。
然后，代码执行了一系列的条件检查：
检查 heapMan 是否为 NULL，或者内存池的大小是否小于等于堆管理器结构体和堆节点结构体所需的空间大小之和。
如果满足其中任何一个条件，函数将返回 FALSE。
如果条件检查通过，接下来的操作包括：
使用 memset_s 函数将整个内存池的内容初始化为 0。
设置堆管理器结构体中的 size 成员为 size - sizeof(struct LosHeapManager)。
将 head 和 tail 指针指向内存池中的起始位置，并初始化堆节点的相关属性，如 used、prev 和 size。
调用 OsHeapStatInit 函数对堆内存管理器进行统计信息的初始化。
最后，函数返回 TRUE 表示堆内存管理器初始化成功。
总之，这段代码实现了对堆内存管理器的初始化操作，包括内存池的清零、设置管理器结构体的各个成员值，以及进行统计信息的初始化。这是堆内存分配器在启动阶段需要执行的关键操作，以确保后续的内存分配和释放能够正常进行。*/
BOOL OsHeapInit(VOID *pool, UINT32 size)
{
    struct LosHeapNode *node = NULL;
    struct LosHeapManager *heapMan = HEAP_CAST(struct LosHeapManager *, pool);

    if ((heapMan == NULL) || (size <= (sizeof(struct LosHeapNode) + sizeof(struct LosHeapManager)))) {
        return FALSE;
    }

    (VOID)memset_s(pool, size, 0, size);

    heapMan->size = size - sizeof(struct LosHeapManager);

    node = heapMan->head = (struct LosHeapNode *)((UINT8*)pool + sizeof(struct LosHeapManager));

    heapMan->tail = node;

    node->used = 0;
    node->prev = NULL;
    node->size = heapMan->size - sizeof(struct LosHeapNode);

    OsHeapStatInit(heapMan, size);

    return TRUE;
}

/*
 * Description : To alloc memory block from the heap memory poll
 * Input       : VOID *pool --- Pointer to the manager,to distinguish heap
 *               UINT32 size --- size of the heap memory pool
 * Return      : NULL:error, other value:the address of the memory we alloced
 */
/*这段代码实现了一个名为 OsHeapAlloc 的函数，用于在堆内存管理器中分配指定大小的内存块。让我逐步解释这段代码的功能：

首先，函数接受一个指向内存池的指针 pool 和表示要分配的内存块大小的参数 size。

接着，代码定义了一些局部变量，包括 node、next、best、ptr 和 alignSize，用于记录堆节点和其他临时数据。

heapMan 是将 pool 指针强制类型转换为 struct LosHeapManager 类型的指针，以便后续对堆管理器结构体成员的操作。

然后，代码执行了一系列的条件检查：

检查 heapMan 是否为 NULL，或者要分配的内存块大小是否超过了最大允许的大小 MALLOC_MAXSIZE。如果满足其中任何一个条件，函数将返回 NULL。
如果条件检查通过，接下来的操作包括：

调用 OsHeapIntegrityCheck 函数对堆内存管理器进行完整性检查。如果检查失败（返回值不等于 LOS_OK），函数将返回 NULL。
然后，代码从堆内存管理器的尾部开始遍历堆节点，寻找合适的空闲节点来分配内存块。具体过程如下：

判断当前节点是否未被使用（node->used == 0）且大小足够容纳请求的对齐后的大小（node->size >= alignSize）。
如果是，则更新 best 指针，选择找到的第一个合适的节点。
如果找到的节点大小正好与请求的对齐后的大小相等（best->size == alignSize），跳转到 SIZE_MATCH 标签处。
循环遍历完所有节点后，函数将根据找到的最佳节点进行不同的处理：

如果找到了合适的节点（best != NULL），则继续下面的操作。
如果找到的节点大小与对齐后的大小完全匹配（即跳转到 SIZE_MATCH 标签处），直接执行后续处理操作。
否则，函数将在找到的节点上分割出一个大小为 alignSize 的内存块，并更新相关节点和管理器的属性值。
最后，函数返回分配的内存块的起始地址 ptr。

总之，这段代码实现了在堆内存管理器中分配指定大小的内存块的功能。它会遍历堆节点，寻找满足条件的空闲节点，并根据需要进行内存分割，以满足对齐要求。如果分配失败或出现错误，函数将返回 NULL。*/
VOID *OsHeapAlloc(VOID *pool, UINT32 size)
{
    struct LosHeapNode *node = NULL;
    struct LosHeapNode *next = NULL;
    struct LosHeapNode *best = NULL;
    VOID *ptr = NULL;
    UINT32 alignSize = ALIGNE(size);

    struct LosHeapManager *heapMan = HEAP_CAST(struct LosHeapManager *, pool);
    if ((heapMan == NULL) || (size > MALLOC_MAXSIZE)) {
        return NULL;
    }

    if (OsHeapIntegrityCheck(heapMan) != LOS_OK) {
        return NULL;
    }

    node = heapMan->tail;
    while (node != NULL) {
        if ((node->used == 0) && (node->size >= alignSize) &&
            ((best == NULL) || (best->size > node->size))) {
            best = node;
            if (best->size == alignSize) {
                goto SIZE_MATCH;
            }
        }
        node = node->prev;
    }

    /* alloc failed */
    /*这是一个条件判断语句，如果找到的最佳节点为空（即没有足够大小的空闲节点），则执行花括号中的代码块。*/
    if (best == NULL) {
        PRINT_ERR("there's not enough mem to alloc 0x%x Bytes!\n", alignSize);//在没有足够空闲内存来分配请求大小的内存块时，打印错误信息，提示用户无法分配指定大小的内存。
        goto OUT;//跳转到标签 OUT 处，这通常是用于执行清理和释放资源的操作。
    }
    /*这是另一个条件判断语句，用于判断是否有足够的空间将找到的节点分割为两部分，以满足请求的大小，并且保留一个足够大的空洞来放置下一个节点的元数据。*/
    /*node = (struct LosHeapNode*)(UINTPTR)(best->data + alignSize);：计算出新的节点的地址，该节点位于原节点的空闲空间之后，用于存放剩余的内存块。
node->used = 0;：将新节点标记为未使用。
node->size = best->size - alignSize - sizeof(struct LosHeapNode);：设置新节点的大小为原节点大小减去已分配内存大小和节点元数据大小的剩余空间。
node->prev = best;：设置新节点的前驱节点为原节点。
接下来的条件判断和操作用于更新堆管理器中的节点关系，确保堆的连续性。
最后，best->size = alignSize;：更新原节点的大小为已分配大小，表示原节点存放了分配的内存块。*/
    if ((best->size - alignSize) > sizeof(struct LosHeapNode)) {
        /* hole divide into 2 */
        node = (struct LosHeapNode*)(UINTPTR)(best->data + alignSize);

        node->used = 0;
        node->size = best->size - alignSize - sizeof(struct LosHeapNode);
        node->prev = best;

        if (best != heapMan->tail) {
            next = OsHeapPrvGetNext(heapMan, node);
            if (next != NULL) {
                next->prev = node;
            }
        } else {
            heapMan->tail = node;
        }

        best->size = alignSize;
    }
/*这段代码可能是用于实现动态内存分配器的代码。具体来说，函数名称 SIZE_MATCH 可能代表了一种内存分配策略，即在进行内存分配时，选择最能够匹配请求大小的空闲内存块进行分配。

其中，代码中的 best 变量可能表示了符合请求大小的、最佳匹配的空闲内存块。代码将 best 的 align 属性设为 0，used 属性设为 1，表示该内存块已被使用。然后，代码通过指针 ptr 返回了该内存块的起始地址。最后，代码调用了 OsHeapStatAddUsed 函数，可能是用于统计内存分配情况的函数，将该内存块的使用信息记录到内存分配器的统计数据中。

值得注意的是，代码中可能存在一些未给出的上下文信息，因此具体含义可能需要根据上下文和相关代码进行推断和理解。*/
SIZE_MATCH:
    best->align = 0;
    best->used = 1;
    ptr = best->data;

    OsHeapStatAddUsed(heapMan, best);
OUT:
    return ptr;
}

/*
 * Description : To alloc memory block from the heap memory poll with
 * Input       : VOID *pool   --- Pointer to the manager,to distinguish heap
 *               UINT32 size   --- size of the heap memory pool
 *               UINT32 boundary --- boundary the heap needs align
 * Return      : NULL:error, other value:the address of the memory we alloced
 */
/*这段代码是一个用于分配指定大小、指定对齐边界（alignment boundary）的内存块的函数。该函数的名称为 OsHeapAllocAlign。

代码首先进行了一些错误检查，确保传入的参数 pool 不为空、size 大于 0、boundary 大于等于 sizeof(VOID*)（VOID* 的大小，即指针大小），且 boundary 是对齐的。如果有任何一个条件不满足，则返回 NULL，表示内存分配失败。

接着，代码计算了需要分配的内存块的大小 useSize，并使用 OsHeapAlloc 函数在内存池 pool 中分配了 useSize 大小的内存块，并将其赋值给指针变量 ptr。

如果内存分配成功，则代码通过 OS_MEM_ALIGN 宏将 ptr 指针对齐到指定的边界 boundary。如果对齐后的指针地址与原始指针地址相同，则说明原始指针已经对齐，直接跳转到 OUT 标签处并返回 ptr 指针即可。否则，说明原始指针未对齐，需要在原始指针和对齐后的指针间填补一定的空隙（gap），并将 gap 的大小信息存储在对齐后的指针前 sizeof(UINTPTR) 个字节的位置。最后，代码返回对齐后的指针 alignedPtr。

需要注意的是，代码中可能存在一些未给出的宏定义和类型定义，具体含义可能需要根据上下文和相关代码进行推断和理解。*/
VOID* OsHeapAllocAlign(VOID *pool, UINT32 size, UINT32 boundary)
{
    UINT32 useSize;
    UINT32 gapSize;
    VOID *ptr = NULL;
    VOID *alignedPtr = NULL;

    if ((pool == NULL) || (size == 0) || (boundary < sizeof(VOID *)) || !IS_ALIGNED(boundary, boundary)) {
        return NULL;
    }

    /* worst case is that the node happen to be 4 bytes ahead of the boundary */
    useSize = (size + boundary) - sizeof(VOID*);
    if (useSize < size) {
        return NULL;
    }

    ptr = OsHeapAlloc(pool, useSize);
    if (ptr != NULL) {
        alignedPtr = (VOID *)(UINTPTR)OS_MEM_ALIGN(ptr, boundary);
        if (alignedPtr == ptr) {
            goto OUT;
        }

        gapSize = (UINTPTR)alignedPtr - (UINTPTR)ptr;
        OS_MEM_SET_ALIGN_FLAG(gapSize);
        *((UINT32 *)((UINTPTR)alignedPtr - sizeof(UINTPTR))) = gapSize;

        ptr = alignedPtr;
    }
OUT:
    return ptr;
}
/*这段代码是一个用于释放内存的函数，名称为 OsHeapDoFree。该函数接收两个参数：一个是 LosHeapManager 结构体指针 heapMan，代表内存池管理器；另一个是 LosHeapNode 结构体指针 curNode，代表需要释放的内存块对应的内存池节点。

代码首先将 curNode 赋值给 node 变量，并将其 used 属性设为 0，表示该节点为未使用状态。

接着，代码使用 while 循环向前遍历链表，查找前面的空闲节点。具体来说，如果当前节点 node 的前一个节点存在且未被使用，则将 node 更新为前一个节点。这一步的目的是将 node 扩展到尽可能大的空闲区域。

然后，代码使用 while 循环向后遍历链表，查找后面的空闲节点。具体来说，代码使用 OsHeapPrvGetNext 函数获取 node 的下一个节点 next，如果 next 存在且未被使用，则将 node 和 next 合并为一个新的节点，并更新 node 的 size 属性。如果合并后的节点是链表中的最后一个节点（也就是 heapMan->tail 指向该节点），则更新 heapMan->tail 为合并后的新节点。如果 next 不存在或已经被使用，则结束循环。

需要注意的是，代码中使用了 LosHeapManager 和 LosHeapNode 两个结构体，具体属性和方法的含义可能需要根据上下文和相关代码进行推断和理解。*/
STATIC VOID OsHeapDoFree(struct LosHeapManager *heapMan, struct LosHeapNode *curNode)
{
    struct LosHeapNode *node = curNode;
    struct LosHeapNode *next = NULL;
    /* set to unused status */
    node->used = 0;

    /* unused region before and after combination */
    while ((node->prev) && (!node->prev->used)) {
        node = node->prev;
    }

    next = OsHeapPrvGetNext(heapMan, node);
    while (next != NULL) {
        if (next->used) {
            next->prev = node;
            break;
        }
        node->size += (sizeof(struct LosHeapNode) + next->size);
        if (heapMan->tail == next) {
            heapMan->tail = node;
        }
        next = OsHeapPrvGetNext(heapMan, node);
    }
}

/*
 * Description : To free the  memory block from  heap memory poll
 * Input       : VOID* pool --- Pointer to the manager,to distinguish heap
 *               VOID* ptr --- the pointer of heap memory we want to free
 * Return      : 1:success 0:error
 */
/*这段代码是用于释放指定内存块的函数 OsHeapFree。该函数接收两个参数：一个是 VOID 类型指针 pool，代表内存池；另一个是 const VOID 类型指针 ptr，代表需要释放的内存块的起始地址。

代码首先声明了一些变量和结构体指针，其中 node 是一个 LosHeapNode 结构体指针，用于表示需要释放的内存块对应的内存池节点。gapSize 是一个 UINT32 类型变量，用于记录内存块前面的空隙大小，ret 是一个 BOOL 类型变量，用于表示内存是否成功释放。

接着，代码通过将传入的 ptr 指针往前移动 sizeof(UINTPTR) 个字节，找到真正的内存块地址，并将其赋值给 ptr 变量。然后，代码判断 ptr 所指向的内存块地址是否在内存池的范围内，如果不在范围内，则返回 FALSE。

接下来，代码使用 ((struct LosHeapNode *)ptr) - 1 计算出内存块对应的内存池节点的地址，并将其赋值给 node 变量。然后，代码检查该节点是否已经被使用，以及它是否是链表中的一个节点。如果检查不通过，则将 ret 设置为 FALSE，并跳转到 OUT 标签处。

最后，代码调用 OsHeapStatDecUsed 函数将内存池管理器中 used 字段减一，然后调用 OsHeapDoFree 函数将 node 对应的内存块释放，并更新内存池管理器中的相关参数。最终返回 ret 表示操作是否成功。*/
BOOL OsHeapFree(VOID *pool, const VOID *ptr)
{
    struct LosHeapNode *node = NULL;

    UINT32 gapSize;
    BOOL ret = TRUE;

    struct LosHeapManager *heapMan = HEAP_CAST(struct LosHeapManager *, pool);
    if ((heapMan == NULL) || (ptr == NULL)) {
        return LOS_NOK;
    }

    /* find the real ptr through gap size */
    gapSize = *((UINT32 *)((UINTPTR)ptr - sizeof(UINTPTR)));
    if (OS_MEM_GET_ALIGN_FLAG(gapSize)) {
        gapSize = OS_MEM_GET_ALIGN_GAPSIZE(gapSize);
        ptr = (VOID *)((UINTPTR)ptr - gapSize);
    }

    if (((UINTPTR)ptr < (UINTPTR)heapMan->head) ||
        ((UINTPTR)ptr > ((UINTPTR)heapMan->tail + sizeof(struct LosHeapNode)))) {
        PRINT_ERR("0x%lx out of range!\n", (UINTPTR)ptr);
        return FALSE;
    }

    node = ((struct LosHeapNode *)ptr) - 1;
    /* check if the address is a node of the heap memory list */
    if ((node->used == 0) || (!((UINTPTR)node == (UINTPTR)heapMan->head) &&
        (((UINTPTR)node->prev < (UINTPTR)heapMan->head) ||
        ((UINTPTR)node->prev > ((UINTPTR)heapMan->tail + sizeof(struct LosHeapNode))) ||
        ((UINTPTR)OsHeapPrvGetNext(heapMan, node->prev) != (UINTPTR)node)))) {
        ret = FALSE;
        goto OUT;
    }

    OsHeapStatDecUsed(heapMan, node);
    OsHeapDoFree(heapMan, node);

OUT:
    return ret;
}

/*
 * Description : collect heap statistics
 * Input       : pool --- Pointer to the manager, to distinguish heap
 * Output      : status --- heap statistics
 * Return      : LOS_OK on success or error code on failure
 */
/*这段代码是用于获取指定内存池的统计信息的函数 OsHeapStatisticsGet。该函数接收两个参数：一个是 VOID 类型指针 pool，代表内存池；另一个是 LosHeapStatus 结构体指针 status，用于保存内存池的统计信息。

函数中首先声明了一些变量，包括 heapUsed、maxFreeNodeSize、freeNodeNum、usedNodeNum 以及结构体指针 node 和 ramHeap。其中 heapUsed 表示已用内存大小，maxFreeNodeSize 表示最大可用内存块大小，freeNodeNum 表示空闲节点数量，usedNodeNum 表示已用节点数量。

然后，代码检查传入的内存池指针是否为空，如果为空，则返回 LOS_NOK。接着，代码检查传入的结构体指针 status 是否为空，如果为空，则返回 LOS_NOK。

之后，代码使用 sizeof(struct LosHeapManager) 计算出内存池管理器头部占用的空间大小，并将其加到 heapUsed 变量中。

接下来，代码使用指针 node 遍历整个内存池的节点链表，对每个节点进行处理。如果该节点已被使用，则将其大小和节点头部大小相加，并将结果累加到 heapUsed 中，并将 usedNodeNum 加一。否则，如果该节点未被使用，则更新 maxFreeNodeSize 和 freeNodeNum 的值。

最后，代码检查 heapUsed 是否超过了内存池总大小，如果超过，则返回 LOS_NOK。否则，将统计信息保存到结构体指针 status 中，并返回 LOS_OK。

需要注意的是，如果系统开启了 LOSCFG_MEM_TASK_STAT 宏定义，则代码还会更新 usageWaterLine 字段的值。*/
UINT32 OsHeapStatisticsGet(VOID *pool, LosHeapStatus *status)
{
    UINT32 heapUsed = 0;
    UINT32 maxFreeNodeSize = 0;
    UINT32 freeNodeNum = 0;
    UINT32 usedNodeNum = 0;

    struct LosHeapNode *node = NULL;
    struct LosHeapManager *ramHeap = HEAP_CAST(struct LosHeapManager *, pool);

    if (ramHeap == NULL) {
        return LOS_NOK;
    }

    if (status == NULL) {
        return LOS_NOK;
    }

    /* heap manager header use heap space */
    heapUsed += sizeof(struct LosHeapManager);

    node = ramHeap->tail;
    while (node != NULL) {
        if (node->used) {
            heapUsed += (node->size + sizeof(struct LosHeapNode));
            usedNodeNum++;
        } else {
            if (node->size > maxFreeNodeSize) {
                maxFreeNodeSize = node->size;
            }
            freeNodeNum++;
        }
        node = node->prev;
    }

    if (ramHeap->size < heapUsed) {
        return LOS_NOK;
    }

    status->totalUsedSize = heapUsed;
    status->maxFreeNodeSize = maxFreeNodeSize;
    status->totalFreeSize = ramHeap->size - status->totalUsedSize;
    status->usedNodeNum = usedNodeNum;
    status->freeNodeNum = freeNodeNum;

#ifdef LOSCFG_MEM_TASK_STAT
    status->usageWaterLine = ramHeap->stat.memTotalPeak;
#endif

    return LOS_OK;
}

/*
 * Description : get max free block size
 * Input       : pool --- Pointer to the manager, to distinguish heap
 * Return      : max free block size
 */
/*这段代码是用于获取指定内存池中最大可用块大小的函数 OsHeapGetMaxFreeBlkSize。该函数接收一个参数：一个 VOID 类型指针 pool，代表内存池。

函数中首先声明了一些变量，包括 size、temp、结构体指针 node 和 ramHeap。其中 size 表示最大可用块大小，temp 是一个临时变量，用于保存当前节点的大小。

然后，代码检查传入的内存池指针是否为空，如果为空，则返回 LOS_NOK。

之后，代码使用指针 node 遍历整个内存池的节点链表，对每个节点进行处理。如果该节点未被使用，则将其大小保存到 temp 变量中。如果 temp 的值比 size 大，则更新 size 的值为 temp。

最后，函数返回 size 变量的值，即内存池中最大可用块的大小。*/
UINT32 OsHeapGetMaxFreeBlkSize(VOID *pool)
{
    UINT32 size = 0;
    UINT32 temp;
    struct LosHeapNode *node = NULL;
    struct LosHeapManager *ramHeap = HEAP_CAST(struct LosHeapManager *, pool);

    if (ramHeap == NULL) {
        return LOS_NOK;
    }

    node = ramHeap->tail;
    while (node != NULL) {
        if (!(node->used)) {
            temp = node->size;
            if (temp > size) {
                size = temp;
            }
        }
        node = node->prev;
    }
    return size;
}

#ifdef __cplusplus
#if __cplusplus
}
#endif /* __cplusplus */
#endif /* __cplusplus */
