Abstract:This article led us to analyze the source code of the dynamic memory module of the HongMeng light kernel, including the structure of the dynamic memory, the dynamic memory pool initialization, the dynamic memory application, release, etc.

This article is shared from the Huawei cloud community “HongMeng light kernel M kernel source analysis series nine Dynamic Memory”, the original author: Zhushy.

The memory management module manages the memory resources of the system. It is one of the core modules of the operating system, including the initialization, allocation and release of the memory.

During the operation of the system, the memory management module manages the use of memory by users and OS through the application/release of memory, so as to optimize the utilization and efficiency of memory and solve the memory fragmentation problem of the system to the greatest extent.

The memory management of Hongmeng light kernel is divided into static memory management and dynamic memory management, which provides memory initialization, allocation, release and other functions.

  • Dynamic memory: Allocates a user-specified chunk of memory in a dynamic memory pool. Advantages: Distribution according to needs. Disadvantages: Possible fragmentation in the memory pool.
  • Static memory: Allocates a block of memory in the static memory pool that is the preset (fixed) size at the time of user initialization. Advantages: High allocation and release efficiency, no fragmentation in static memory pool. Disadvantage: can only apply to the initialization of the preset size of the memory block, can not apply on demand.

After analyzing static memory in the previous series, we started analyzing dynamic memory. Dynamic memory management is mainly used in scenarios where users need to work with blocks of memory of varying sizes. When users need to use memory, they can request memory blocks of specified size through the dynamic memory request function of the operating system. Once the memory is used up, the memory occupied can be returned through the dynamic memory release function, so that it can be reused.

Based on the TLSF algorithm of OpenHarmony LEOS-M dynamic memory, the interval partition is optimized to obtain better performance and reduce fragmentation rate. Dynamic memory core algorithm block diagram is as follows:

According to the size of the free memory block, use multiple free linked lists to manage. According to the size of free blocks, it is divided into two parts: [4, 127] and [27, 231], as shown in the figure above:

  • The memory of the interval [4,127] is bisected, as shown in green in the figure above, into 31 cells, and each cell corresponds to a multiple of 4 bytes of memory block size. Each cell corresponds to a free memory linked list and a bit used to mark whether the corresponding free memory linked list is empty. When the value is 1, the free list is not empty. The memory of the [4,127] interval is marked with a 32-bit unsigned integer bitmap.
  • Free memory blocks larger than 127 bytes, according to the power of 2 interval size for free linked list management. It is divided into 24 cells in total, and each cell is equally divided into 8 secondary cells, as shown in the blue part of Size Class and Size Subclass in the figure above. Each secondary cell corresponds to a free list and a bit to mark whether the corresponding free memory list is empty. A total of 24*8=192 secondary cells, corresponding to 192 free linked lists and 192/32=6 32-bit unsigned integer bitmap tokens.

For example, when there is 40 bytes of free memory to be inserted into the free list, corresponding to the cell [40,43], the 10th free list, the 10th bit of the bitmap mark. Mount 40 bytes of free memory on the 10th free list, and determine if the bitmap token needs to be updated. When it is necessary to apply for 40 bytes of memory, the free linked list with memory blocks meeting the application size is obtained according to the bitmap mark, and the free memory nodes are obtained from the free linked list. If the allocated node is larger than the required memory size, split the node operation and mount the remaining nodes to the corresponding free linked list again. When 580 bytes of free memory need to be inserted into the free list, corresponding to the level 2 cells [2^9,2^9+2^6], 31+2*8=47 free linked lists, the second bitmap marked the 17th bit. Mount 580 bytes of free memory on the 47th free linked list and determine if the bitmap token needs to be updated. When 580 bytes of memory is required to be applied, free memory nodes are obtained from the free linked list according to bitmap markers that exist memory blocks that meet the application size. If the allocated node is larger than the required memory size, split the node operation and mount the remaining nodes to the corresponding free linked list again. If the corresponding free linked list is empty, it will query the larger memory interval to see if there is any free linked list that meets the conditions. In actual calculation, it will find the free linked list that meets the application size once.

The dynamic memory management structure is shown below:

  • The header portion of the memory pool

The memory pool pool header section contains memory pool information and an array of bitmap tags and an array of free linked lists. The memory pool information includes the memory pool starting address, the total size of the heap area, and the memory pool properties. The bitmap tag array consists of seven 32-bit unsigned integers. Each bit marks whether the corresponding free linked list mounts a free memory block node. The free memory linked list contains 223 free memory head node information. Each free memory head node information maintains the memory node nods and the precursor and successor free memory nodes in the free linked list.

  • The memory pool node part

Contains three types of nodes, unused free memory node, used memory node, tail node. Each memory node maintains a pre-order pointer to the previous memory node in the memory pool, maintains size and usage markers, marking the size of the memory node and whether it is used, etc. The data field behind the free memory node and the used memory node. The tail node has no data field.

This article through the analysis of the dynamic memory module source code, to help readers master the use of dynamic memory. In this article the source involved in OpenHarmony LiteOS -m kernel, for example, can be in the open source site https://gitee.com/openharmony… To obtain. Next, we look at the structure of dynamic memory, dynamic memory initialization, dynamic memory common operation source code.

1. Dynamic memory structure definition and common macro definition

1.1 Dynamic memory structure definition

Dynamic memory structures are dynamic memory pool information structure OsMemPoolInfo, dynamic memory pool header structure OsMemPoolHead, dynamic memory node nods structure OsMemNodeHead, used memory node structure osmemusedNodehead, dynamic memory memory information structure osmemusedNodehead, The free memory node structure OSMEMFreenodeHead. These structures are defined in the file kernel\ SRC \mm\los_memory.c. The member variables of each structure are described below in combination with the dynamic memory management structure schematic above.

1.1.1 Dynamic memory pool header related structure

The dynamic memory pool information structure OSMEMPoolInfo maintains the starting address and size information of the memory pool. The three main members are the memory pool start address.pool, the memory pool size.poolsize, and the memory value attribute.attr. If the LOSCFG_MEM_WATERLINE macro is turned on, the waterline value of the memory pool is also maintained.

struct OsMemPoolInfo { VOID *pool; /* The memory start address of the memory pool */ UINT32 TotalSize; /* total size of memory pool */ UINT32 attr; */ #if (LOSCFG_MEM_WATERLINE == 1) UINT32 waterLine; /* Maximum memory usage in the pool */ UINT32 curusedSize; /* The current size of the memory pool used */ #endif};

Struct OsMemPoolInfo (struct OsMemPoolInfo, struct OsMemPoolInfo, struct OsMemPoolInfo, struct OsMemPoolInfo, struct OsMemPoolInfo, struct OsMemPoolInfo, struct OsMemPoolInfo, struct OsMemPoolInfo, struct OsMemPoolInfo, struct OsMemPoolInfo, struct OsMemPoolInfo, One is the free memory linked list array freeList[]. The macro definitions OS_MEM_BITMAP_WORDS and OS_MEM_FREE_LIST_COUNT are described later.

struct OsMemPoolHead {
    struct OsMemPoolInfo info;
    UINT32 freeListBitmap[OS_MEM_BITMAP_WORDS];
    struct OsMemFreeNodeHead *freeList[OS_MEM_FREE_LIST_COUNT];
#if (LOSCFG_MEM_MUL_POOL == 1)
    VOID *nextPool;
#endif
};

1.1.2 Dynamic memory pool memory node related structure

(1) If the memory node integrity check macro LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK is turned on, the magic word will be maintained. Magic check. (2) If the memory leak checking macro is enabled, the link register array linkReg[] is maintained. (3) The member variable at (3) is a combination of Pointers. Each memory node in the memory pool maintains a pointer to the previous memory node. The size and marking information of the memory node are maintained.

Struct OsMemNodeHead {#if (LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK == 1) ⑴ UINT32 magic; #endif #if (LOSCFG_MEM_LEAKCHECK == 1) ⑵ UINTPTR linkReg[LOSCFG_MEM_RECORD_LR_CNT]; #endif union { struct OsMemNodeHead *prev; /* The prev is used for current node points to the previous node */ struct OsMemNodeHead *next; /* The next is used for sentinel node points to The expand node */ ⑶} PTR; #if (LOSCFG_MEM_FREE_BY_TASKID == 1) ⑷ (5) UINT32 sizeAndFlag : 26; #else UINT32 sizeAndFlag; #endif };

Next, let’s look at the used memory node structure OsMemusedNodeHead. This structure is relatively simple and directly takes the dynamic memory node nodding structure OsMemNodeHead as the only member.

struct OsMemUsedNodeHead {
    struct OsMemNodeHead header;
};

We also look at the free memory node structure osmemFreeNodeHead. In addition to the dynamic memory node nodding member osmemNodeHead, there are two Pointers to the previous and the next free memory node.

struct OsMemFreeNodeHead {
    struct OsMemNodeHead header;
    struct OsMemFreeNodeHead *prev;
    struct OsMemFreeNodeHead *next;
};

1.2 Dynamic memory core algorithm related macros and functions

Dynamic memory also provides a number of macro definitions and inline functions related to the TLSF algorithm. These macros are very important and need to be familiar with the definition of these macros before analyzing the source code. Can be combined with the above dynamic memory core algorithm block diagram for learning. ⑴ The macro pair is in [2^n,2^(n+1)], where (n =7,8… 30) interval of large memory block 2^3=8 equal. The small memory block defined in the interval [4,127] is divided into 31 segments, i.e., 4,8,12… , 124. (3) defines the upper bound of small memory. Considering memory alignment and granularity, the maximum value can only reach 124.

The macros at four are in [2^n,2^(n+1)], where (n =7,8… The size of the memory is divided into 24 cells, where n=7 is the macro OS_MEM_LARGE_START_BUCKET defined by ⑺. The ⑻ place corresponds to the length of the free memory linked list. The margin is the length of the free list bitmap array. The 31 small amounts of memory use 1 bitmap word, so the margin is incremented by 1. We will define a bitmap mask, each bitmap word is a 32-bit unsigned integer.

Let’s move on to inline functions. (11) The function looks for the first bit of 1 in the bitmap word. This function is similar to the built-in function __builtin_ctz. This function is used to get the first free memory list with the free memory block mounted in the corresponding bitmap word of the free memory list. (12) Get the last 1 bit in the bitmap word (from left to right from the 32-bit binary value 0,1… , 31). The Log in the name of the l function is an abbreviation for the logarithm. The function is used to calculate the integer part of the logarithm base 2. The number of the size level of the memory interval is obtained at the bread interval, in 31 levels for < 128 bytes, in [2^n,2^(n+1)], where (n =7,8… 30) interval of memory, with 24 levels. (15) Acquisition the number between secondary cells according to the size of memory and the first level number of memory interval. The number between secondary cells is located in [2^n,2^(n+1)], where (n =7,8… 30) interval of memory, there are 8 secondary cells between.

/* The following is the macro definition and interface implementation related to the TLSF. */ /* Supposing a Second Level Index: SLI = 1. */ ⑴ #define OS_MEM_SLI 3 /* Giving 1 free list for each small bucket: 4, 8, 12, Up to 1. */ ⑵ #define OS_MEM_SMALL_BUCKET_COUNT 31 ⑶ #define OS_MEM_SMALL_BUCKET_MAX_SIZE 128 /* Giving 2 Free lists for each large bucket. */ ⑷ #define OS_MEM_LARGE_BUCKET_COUNT 24 /* OS_MEM_SMALL_BUCKET_MAX_SIZE to the power Of 2 is 7. */ ⑺ #define OS_MEM_LARGE_START_BUCKET 7 /* The count of free list. */ ⑻ #define OS_MEM_FREE_LIST_COUNT (OS_MEM_SMALL_BUCKET_COUNT + (OS_MEM_LARGE_BUCKET_COUNT << OS_MEM_SLI)) /* The bitmap is used to indicate whether the free list is empty, 1: not empty, 0: #define OS_mem_bitmap_words ((OS_mem_free_list_count >> 5) + 1) → #define OS_mem_bitmap_mask 0x1FU /* Used. #define OS_mem_bitmap_words ((OS_mem_free_list_count >> 5) + 1) → #define OS_mem_bitmap_mask 0x1FU /* Used (11) to find the first bit of 1 in bitmap. */ STATIC INLINE UINT16 OsMemFFS(UINT32 bitmap) {bitmap &= ~bitmap + 1; return (OS_MEM_BITMAP_MASK - CLZ(bitmap)); } /* Used to find the last bit of 1 in bitmap. */ (12) STATIC INLINE UINT16 OsMemFLS(UINT32 bitmap) {return (STATIC INLINE UINT16 OsMemFLS(UINT32 bitmap) (OS_MEM_BITMAP_MASK - CLZ(bitmap)); } l STATIC INLINE UINT32 OsMemLog2(UINT32 size) {return (size > 0)? OsMemFLS(size) : 0; } /* Get the first level: F = log2(size). */ STATIC INLINE UINT32 OsMemFlGet(UINT32 size) {if (size < OS_MEM_SMALL_BUCKET_MAX_SIZE) {return INLINE (size < OS_MEM_SMALL_BUCKET_MAX_SIZE) {return INLINE (size < OS_MEM_SMALL_BUCKET_MAX_SIZE) ((size >> 2) - 1); / * 2: The small bucket setup is 4. */ } return (OsMemLog2(size) - OS_MEM_LARGE_START_BUCKET + OS_MEM_SMALL_BUCKET_COUNT); } /* Get the second level: S = (size - 15 ^f) * 15 ^f. */ participant size = 15 (15 ^ 15) UINT32 fl) { if ((fl < OS_MEM_SMALL_BUCKET_COUNT) || (size < OS_MEM_SMALL_BUCKET_MAX_SIZE)) { PRINT_ERR("fl or size is too small, fl = %u, size = %u\n", fl, size); return 0; } UINT32 sl = (size << OS_MEM_SLI) >> (fl - OS_MEM_SMALL_BUCKET_COUNT + OS_MEM_LARGE_START_BUCKET); return (sl - (1 << OS_MEM_SLI)); }

2, dynamic memory common operation

Dynamic memory management module provides users with initialization and deletion of memory pool, application, release of dynamic memory and other operations, let’s analyze the interface source code. Before we look at memory manipulation interfaces, let’s take a look at the commonly used internal interfaces.

2.1 Dynamic Internal Memory Interface

2.1.1 Set and clean up free memory linked list marker bits

(1) The function osmemsetFreelistBit takes two arguments, the head of the memory pool and the index of the free memory linked list. When the free memory block is attached to the free memory list, the corresponding bit of the bitmap word needs to be set to 1. (1) The function osmemClearFreelistBit does the opposite. When the free memory block is no longer mounted on the free memory list, the corresponding bit should be cleared to zero.

STATIC INLINE VOID OsMemSetFreeListBit(struct OsMemPoolHead *head, UINT32 index) {(1) the head - > freeListBitmap [index > > 5) | = 1 u < < (index & 0 x1f); } STATIC INLINE VOID OsMemClearFreeListBit(struct OsMemPoolHead *head, UINT32 index) {⑵ head-> freelistBitmap [index >> 5] &= ~(1U << (index & 0x1f)); }

2.1.2 Merge memory nodes

The function VOID osmemmerGenode (struct OsMemNodeHead node) merges the given node, struct OsMemNodeHead node, with its previous free node. (1) Add the size of the previous node to the size of the node to be joined. ⑵ gets the next node of the given node, and then executes ⑶ to point its previous node to the previous node of the given node to complete the node merge. The macro OS_MEM_NODE_GET_LAST_FLAG is used to determine whether the node is the last node. The default value is 0. You can see the definition of this macro for yourself.

STATIC INLINE VOID OsMemMergeNode(struct OsMemNodeHead *node) { struct OsMemNodeHead *nextNode = NULL; (1) node - > PTR. Prev - > sizeAndFlag + = node - > sizeAndFlag; ⑵ nextNode = (struct OsMemNodeHead *)((UINTPTR)node + node-> sizeandFlag); if (! OS_MEM_NODE_GET_LAST_FLAG(nextNode-> sizeandFlag)) {⑶ nextNode->ptr.prev = node->ptr.prev; }}

2.1.3 Split memory nodes

VOID osmemSplitNode (VOID pool, struct OsMemNodeHead allocNode, UINT32 allocSize) is used to split memory nodes. It takes three parameters. VOID pool (struct OsMemNodeHead allocNode) VOID pool (struct OsMemNodeHead allocNode) VOID pool (struct OsMemNodeHead allocNode) The remainder of the split, if the next node is free, is merged together. The nodes left over from the split are mounted on the free memory linked list.

(1) indicates that newFreeNode is the free memory node left after allocation, sets its previous node to the allocated node, and sets the size of the remaining memory. ⑶ fetches the next node. Then execute (4) to set the previous node of the next node to the newFreeNode, newFreeNode. — check whether the next node is used or not. If not, delete the next node from the linked list and merge it with the idle node newFreeNode. The rest of the free memory nodes that are partitioned are mounted on the linked list.

STATIC INLINE VOID OsMemSplitNode(VOID *pool, struct OsMemNodeHead *allocNode, UINT32 allocSize) { struct OsMemFreeNodeHead *newFreeNode = NULL; struct OsMemNodeHead *nextNode = NULL; ⑴ newFreeNode = (struct osmemFreeNodeHead *)(VOID *)((UINT8 *)allocNode + allocSize); newFreeNode->header.ptr.prev = allocNode; newFreeNode->header.sizeAndFlag = allocNode->sizeAndFlag - allocSize; 2 allocNode - > sizeAndFlag = allocSize; (3) nextNode = OS_MEM_NEXT_NODE (& newFreeNode - > header); if (! OS_MEM_NODE_GET_LAST_FLAG(nextNode-> sizeandFlag) {⑷ nextNode-> PTR. Prev = &newFreeNode->header; if (! OS_MEM_NODE_GET_USED_FLAG(nextNode-> sizeandFlag)) {⑸ osmemFreenodeDelete (pool, (struct osmemFreenodehead *)nextNode); OsMemMergeNode(nextNode); }} ⑹ osmemFreenodeAdd (pool, newFreenode); }

2.1.4 Reapply memory

The osMemRealLocalizer () function is used to reclaim a smaller chunk of memory from a larger chunk. It takes four arguments: VOID pool is the starting address of the memory pool, UINT32 allocSize is the size of the reapplied memory, struct OsMemNodeHead node is the size of the memory node that needs to be reallocated, UINT32 nodeSize is the size of the current node. ⑴ Set the actual size of the memory node selfNode. sizeandFlag after removing the mark; ⑵ split the node as needed; ⑶ split the node as used to complete the application memory.

STATIC INLINE VOID OsMemReAllocSmaller(VOID *pool, UINT32 allocSize, struct OsMemNodeHead *node, UINT32 nodeSize) { #if (LOSCFG_MEM_WATERLINE == 1) struct OsMemPoolHead *poolInfo = (struct OsMemPoolHead *)pool; #endif ⑴ node-> sizeandFlag = nodeSize; If ((allocSize + OS_MEM_MIN_LEFT_SIZE) <= nodeSize) {⑵ osmemSplitNode (pool, node, allocSize); #if (LOSCFG_MEM_WATERLINE == 1) poolInfo->info.curUsedSize -= nodeSize - allocSize; # endif} (3) OS_MEM_NODE_SET_USED_FLAG (node - > sizeAndFlag); #if (LOSCFG_MEM_LEAKCHECK == 1) OsMemLinkRegisterRecord(node); #endif }

2.1.5 Merge nodes to reapply memory

Finally, under the look at function OsMemMergeNodeForReAllocBigger (), is used to merge the memory node, redistribute more memory space. VOID pool is the initial address of the memory pool, UINT32 allocSize is the size of the reapplied memory, struct OsMemNodeHead node is the size of the memory node that needs to be reallocated, UINT32 nodeSize is the size of the current node, Struct OsMemNodeHead *nextNode is the next memory node. ⑴ Set the size of the memory node to the actual size after removing the marker, ⑵ remove the next node from the linked list, and then merge the nodes. ⑶ If the size of the merged node exceeds the size to be redistributed, the node is split. (4) The applied memory node is marked as used, and the applied memory is completed

STATIC INLINE VOID OsMemMergeNodeForReAllocBigger(VOID *pool, UINT32 allocSize, struct OsMemNodeHead *node, UINT32 nodeSize, struct OsMemNodeHead *nextNode) {⑴ node-> sizeandFlag = nodeSize; ⑵ osmemFreenodedelete (pool, (struct osmemFreenodehead *)nextNode); OsMemMergeNode(nextNode); If ((allocSize + OS_MEM_MIN_LEFT_SIZE) <= node-> sizeandFflag) {⑶ osmemsplitNode (pool, node, allocSize); } (4) OS_MEM_NODE_SET_USED_FLAG (node - > sizeAndFlag); OsMemWaterUsedRecord((struct OsMemPoolHead *)pool, node->sizeAndFlag - nodeSize); #if (LOSCFG_MEM_LEAKCHECK == 1) OsMemLinkRegisterRecord(node); #endif }

2.1.6 Free memory linked list related operations

Dynamic memory provides several operations for a linked list of free memory. Let’s examine the code for each of these operations in turn. First look at the function osMemFreelistIndexGet, which gets the index of the free memory linked list based on the size of the memory node. (⑴) Obtain a first-level index, (⑵) obtain a second-level index, and then calculate the index of the free linked list and return it.

STATIC INLINE UINT32 osMemFreelListIndexGet (UINT32 size) {⑴ UINT32 fl = osMemFlget (size); if (fl < OS_MEM_SMALL_BUCKET_COUNT) { return fl; } ⑵ uint32sl = OsMemSlGet(size, fl); return (OS_MEM_SMALL_BUCKET_COUNT + ((fl - OS_MEM_SMALL_BUCKET_COUNT) << OS_MEM_SLI) + sl); }

Next, let’s look at the function osmemListAdd, which inserts free memory nodes into the free memory linked list. (1) Gets the first node of the free linked list. If the node is not empty, set the precursor node as the node to be inserted. (2) Set the prior and subsequent nodes of the node to be inserted, and assign this node to the freeList pool->freeList[listIndex]. Finally execute the ⑶ code, set the idle list bitmap word, and set the magic word.

STATIC INLINE VOID OsMemListAdd(struct OsMemPoolHead *pool, UINT32 listIndex, Struct osmemFreenodehead *node) {⑴ struct osmemFreenodehead *firstNode = pool-> Freelist [listIndex]; if (firstNode ! = NULL) { firstNode->prev = node; } ⑵ node->prev = NULL;} ⑵ node->prev = NULL; node->next = firstNode; pool->freeList[listIndex] = node; (3) OsMemSetFreeListBit (pool, listIndex); OS_MEM_SET_MAGIC(&node->header); }

Finally, examine how the function osMemListDelete deletes the specified free memory node from the free memory linked list. (1) If the deleted node is the first node in the free memory list, then the free list needs to execute the next node of the node to be deleted. If the next node is empty, you need to execute the ⑵ to clear the bitmap word of the free list. Otherwise execution ⑶ sets the precursor node of the next node to null. If the node to be deleted is not the first node in the free linked list, execute ⑷ to set the subsequent node of the predecessor node to be the successor node of the node to be deleted. If the node to be deleted is not the last node, you need to execute ⑸ to set the precursor node of the successor node to be the precursor node of the node to be deleted. Finally, we need to set up the magic word.

STATIC INLINE VOID OsMemListDelete(struct OsMemPoolHead *pool, UINT32 listIndex, Struct osmemFreenodehead *node) {⑴ if (node == pool-> Freelist [listIndex]) {pool-> Freelist [listIndex] = node->next; If (node->next == NULL) {⑵ osmemClearFreelistBit (pool, listIndex); } else {⑶ node->next->prev = NULL; } else {⑷ node->prev->next = node->next; if (node->next ! = NULL) {⑸ node->next->prev = node->prev; } } OS_MEM_SET_MAGIC(&node->header); }

2.1.7 Operation related to free memory nodes

Dynamic memory provides several operations for free memory, such as OSMemFreenodeAdd, OSMemFreenodeDelete, and OSMemFreenodeGet.

The function osMemFreenodeAdd is used to add a free memory node to the corresponding free memory linked list. ⑴ call the function to get the index of the free memory linked list, and then execute the function to add the free memory node to the free linked list.

STATIC INLINE VOID OsMemFreeNodeAdd(VOID *pool, Struct osmemFreenodehead *node) {⑴ UINT32 index = osmemFreelanceIndexGet (node->header. sizeandFflag); if (index >= OS_MEM_FREE_LIST_COUNT) { LOS_Panic("The index of free lists is error, index = %u\n", index); } ⑵ osmemListAdd (pool, index, node); }

The function osMemFreenodeDelete is used to remove a free memory node from the corresponding free memory linked list. The code is simple, get the index of the free memory linked list, and then call the function osMemListDelete to delete.

STATIC INLINE VOID OsMemFreeNodeDelete(VOID *pool, struct OsMemFreeNodeHead *node)
{
    UINT32 index = OsMemFreeListIndexGet(node->header.sizeAndFlag);
    OsMemListDelete(pool, index, node);
}

The function osMemFreenodeGet gets the free memory blocks that meet the size criteria based on the memory pool address and the required memory size. (1) call the function to obtain the memory block that meets the size condition, and then execute the function to remove the acquired memory block from the free memory linked list and return the memory node address.

STATIC INLINE struct OsMemNodeHead *OsMemFreeNodeGet(VOID *pool, UINT32 size) { struct OsMemPoolHead *poolHead = (struct OsMemPoolHead *)pool; UINT32 index; (1) struct OsMemFreeNodeHead * firstNode = OsMemFindNextSuitableBlock (pool, the size, & index); if (firstNode == NULL) { return NULL; } ⑵ osMemListDelete (poolHead, index, firstNode); return &firstNode->header; }

Finally, analysis the function OsMemFindNextSuitableBlock. (1) Get the number of the first level interval according to the size of the required memory block. If the applied memory is in the interval [4,127], execute (⑵) to record the index of the free memory linked list. If you need to request a large amount of memory, execute the code at ⑶. First get the second level interval index, and then calculate the index value of the free memory linked list index. The free memory block may not be mounted under the free memory list calculated in this way. Call the function osmemNotemptyIndexGet to get the index value of the free memory linked list mounted on the free memory block. If the free memory block is successfully obtained, return the free list index value, otherwise continue to execute the following code. It will traverse the idle list bitmap word, and the increment variable index in the loop corresponds to the first-level interval number. If the bitmap word is not empty, we perform ⑺ to retrieve the largest free memory list index corresponding to the bitmap word.

If the execution reaches the ⑻ place, the appropriate block of memory was not matched. A null pointer is returned. ‘levies department said there meet the free memory size list, call a function OsMemFindCurSuitableBlock the proper memory block and return. We will get the appropriate free memory linked list index, return free memory linked list.

STATIC INLINE struct OsMemFreeNodeHead *OsMemFindNextSuitableBlock(VOID *pool, UINT32 size, UINT32 *outIndex) { struct OsMemPoolHead *poolHead = (struct OsMemPoolHead *)pool; ⑴ UINT32 fl = osMemFlget (size); UINT32 sl; UINT32 index, tmp; UINT32 curIndex = OS_MEM_FREE_LIST_COUNT; UINT32 mask; Do {if (fl < OS_MEM_SMALL_BUCKET_COUNT) {⑵ index = fl; } else {⑶ sl = osMemslGet (size, fl); curIndex = ((fl - OS_MEM_SMALL_BUCKET_COUNT) << OS_MEM_SLI) + sl + OS_MEM_SMALL_BUCKET_COUNT; index = curIndex + 1; } ⑷ TMP = osMemNotTemptyIndexGet (poolHead, index); if (tmp ! = OS_MEM_FREE_LIST_COUNT) {⑸ = TMP; goto DONE; } ⑹ for (index = LOS_Align(index + 1, 32); index < OS_MEM_FREE_LIST_COUNT; index += 32) { mask = poolHead->freeListBitmap[index >> 5]; /* 5: Divide by 32 to calculate the index of the bitmap array. */ if (mask ! = 0) {struct struct struct + index; goto DONE; } } } while (0); ⑻ if (curIndex == OS_MEM_FREE_LIST_COUNT) {return NULL; ⑻ if (curIndex == OS_MEM_FREE_LIST_COUNT) {return NULL; } margin * OutIndex = CurIndex; return OsMemFindCurSuitableBlock(poolHead, curIndex, size); DONE: *outIndex = index; ⑽ return poolHead - > freeList [index]; }

Let’s take a closer look at the source code for the function OSMEMNTemptyIndexGet. (1) obtain bitmap words according to the free memory linked list index, and (2) judge whether there is a free memory block in the secondary small memory interval corresponding to the first level memory interval corresponding to the free memory linked list index that meets the conditions. For example, if the index is 39, the index & OS_MEM_BITMAP_MASK is equal to 7, corresponding to the 7th bit of the bitmap word. The expression ~((1 << (index&os_mem_bitmap_mask)) -1) is used to represent the bitmap word corresponding to the index value greater than the index of the free memory linked list. The value of the mask indicates that the value of the free list index is greater than the value of the bitmap word corresponding to the index of the linked list. When the mask is not 0, it indicates that there is a free memory block that meets the memory size. Then the code at ⑶ is executed, where OsMemFFS(mask) obtains the first bit bit of 1 in the bitmap word, which corresponds to the linked list of the free memory block to be mounted. (INDEX & ~OS_MEM_BITMAP_MASK) corresponds to the high value of the linked list index, plus the bitmap word number to calculate the index value of the free memory linked list mounted to meet the application conditions.

STATIC INLINE UINT32 OsMemNotEmptyIndexGet(struct OsMemPoolHead *poolHead, UINT32 Index) {⑴ UINT32 Mask = poolhead-> FreelistBitmap [index >> 5]; /* 5: calculate the bitmap array by 32 to calculate the index. */ ⑵ Mask &= ~((1 << (Index & os_mem_bitmap_array)) - 1); if (mask ! (⑶ index = OsMemFFS(mask) + (index & ~OS_MEM_BITMAP_MASK); return index; } return OS_MEM_FREE_LIST_COUNT; }

Finally, look at the function OsMemFindCurSuitableBlock again. ⑴ loop through the memory block mounted on the free memory list. If the size of the memory block traversed is larger than the required size, then execute the ⑵ return the free memory block. Otherwise, the null pointer is returned.

STATIC INLINE struct OsMemFreeNodeHead *OsMemFindCurSuitableBlock(struct OsMemPoolHead *poolHead, UINT32 index, UINT32 size) { struct OsMemFreeNodeHead *node = NULL; ⑴ for (node = poolhead-> freeList[index]; node ! = NULL; Node = node->next) {if (node-> header.sizeandFlag >= size) {⑵ return node; } } return NULL; }

2.2 Initialize the dynamic memory pool

Let’s examine the code that initializes the dynamic memory pool function uint32los_meminit (VOID pool, uint32size). VOID pool is the starting address of the dynamic memory pool, UINT32 size is the total size of the initialized dynamic memory pool, size must be less than or equal to the size of the memory area at the beginning of *pool, otherwise it will affect the following memory areas. You also need a minimum value of OS_MEM_MIN_POOL_SIZE greater than the dynamic memory pool. [pool, pool + size] cannot conflict with other memory pools.

(1) and (2); (2) and (2); (3) and (3); (3) and (3); (4) and (3); (4) and (4) and (4) and (4) and (4) and (4) and (4) and (4) and (4). (3) call osmemPoolInit () to initialize the memory pool, which is the core function for initializing memory. (4) When the macro LOSCFG_MEM_MUL_POOL support is turned on, it will execute.

UINT32 LOS_MemInit(VOID *pool, UINT32 size) {(1) if ((pool = = NULL) | | (size < = OS_MEM_MIN_POOL_SIZE)) {return OS_ERROR; } [2] the if (((UINTPTR) pool & (OS_MEM_ALIGN_SIZE - 1)) | | \ (size & (OS_MEM_ALIGN_SIZE - 1))) {PRINT_ERR (" LiteOS heap memory  address or size configured not aligned:address:0x%x,size:0x%x, alignsize:%d\n", \ (UINTPTR)pool, size, OS_MEM_ALIGN_SIZE); return OS_ERROR; } ⑶ if (osmemPoolInit (pool, size)) {return OS_ERROR; } #if (LOSCFG_MEM_MUL_POOL == 1) ⑷ if (osMemPoolAdd (pool, size)) {VOID osMemPoolDeInit (pool); return OS_ERROR; } #endif #if OS_MEM_TRACE LOS_TraceReg(LOS_TRACE_MEM_TIME, OsMemTimeTrace, LOS_TRACE_MEM_TIME_NAME, LOS_TRACE_ENABLE); LOS_TraceReg(LOS_TRACE_MEM_INFO, OsMemInfoTrace, LOS_TRACE_MEM_INFO_NAME, LOS_TRACE_ENABLE); #endif OsHookCall(LOS_HOOK_TYPE_MEM_INIT, pool, size); return LOS_OK; }

Let’s move on to the function osMemPoolInit (). (1) struct OsMemPoolHead *poolHead (struct OsMemPoolHead *poolHead); ⑶ Gets the first memory control node of the memory pool, and then sets its size, which is equal to the total size of the memory pool minus the size of the memory pool header and the size of one memory node node. Then set the previous node of the memory node to the last node of the memory pool, OS_MEM_END_NODE(pool, size).

(4) Call the macro to set the magic word to the node, and then insert the memory node into the free memory linked list. (⑸) get the tail node of the memory pool, set the magic word, and then do the setting of the tail node size to 0, set the previous node, and set the used marker. If the macro LOSCFG_MEM_WATERLINE is turned on, there are a few other actions you can do. Read them yourself.

STATIC UINT32 OsMemPoolInit(VOID *pool, UINT32 size) { struct OsMemPoolHead *poolHead = (struct OsMemPoolHead *)pool; struct OsMemNodeHead *newNode = NULL; struct OsMemNodeHead *endNode = NULL; (VOID)memset_s(poolHead, sizeof(struct OsMemPoolHead), 0, sizeof(struct OsMemPoolHead)); (1) poolHead - > info. Pool = pool; poolHead->info.totalSize = size; poolHead->info.attr &= ~(OS_MEM_POOL_UNLOCK_ENABLE | OS_MEM_POOL_EXPAND_ENABLE); /* default attr: lock, not expand. */ ⑶ newNode = OS_MEM_FIRST_NODE(pool); newNode->sizeAndFlag = (size - sizeof(struct OsMemPoolHead) - OS_MEM_NODE_HEAD_SIZE); newNode->ptr.prev = OS_MEM_END_NODE(pool, size); (4) OS_MEM_SET_MAGIC (newNode); OsMemFreeNodeAdd(pool, (struct OsMemFreeNodeHead *)newNode); /* The last mem node */ ⑸ endNode = OS_MEM_END_NODE(pool, size); OS_MEM_SET_MAGIC(endNode); #if OS_MEM_EXPAND_ENABLE endNode->ptr.next = NULL; OsMemSentinelNodeSet(endNode, NULL, 0); #else ⑹ endNode->sizeAndFlag = 0; endNode->ptr.prev = newNode; OS_MEM_NODE_SET_USED_FLAG(endNode->sizeAndFlag); #endif #if (LOSCFG_MEM_WATERLINE == 1) poolHead->info.curUsedSize = sizeof(struct OsMemPoolHead) + OS_MEM_NODE_HEAD_SIZE; poolHead->info.waterLine = poolHead->info.curUsedSize; #endif return LOS_OK; }

2.3 Request dynamic memory

After initializing the dynamic memory pool, we can use the function VOID LOS_MemAlloc(VOID pool, UINT32 size) to claim the dynamic memory.

(1) Check the parameters, the memory pool address can not be empty, the applied memory size can not be 0. (2) Determines whether the requested memory size has been marked for use or memory alignment. (3) call OsMemAlloc(poolHead, size, intSave) to apply for a block of memory.

VOID *LOS_MemAlloc(VOID *pool, UINT32 size) { #if OS_MEM_TRACE UINT64 start = HalClockGetCycles(); # endif (1) if ((pool = = NULL) | | (size = = 0)) {return NULL; } if (size < OS_MEM_MIN_ALLOC_SIZE) { size = OS_MEM_MIN_ALLOC_SIZE; } struct OsMemPoolHead *poolHead = (struct OsMemPoolHead *)pool; VOID *ptr = NULL; UINT32 intSave; MEM_LOCK(poolHead, intSave); Do {2 if (OS_MEM_NODE_GET_USED_FLAG (size) | | OS_MEM_NODE_GET_ALIGNED_FLAG (size)) {break; } ⑶ PTR = OsMemAlloc(poolHead, size, intSave); } while (0); MEM_UNLOCK(poolHead, intSave); #if OS_MEM_TRACE UINT64 end = HalClockGetCycles(); UINT32 timeUsed = MEM_TRACE_CYCLE_TO_US(end - start); LOS_Trace(LOS_TRACE_MEM_TIME, (UINTPTR)pool & MEM_POOL_ADDR_MASK, MEM_TRACE_MALLOC, timeUsed); LOS_MEM_POOL_STATUS poolStatus = {0}; (VOID)LOS_MemInfoGet(pool, &poolStatus); UINT8 fragment = 100 - poolStatus.maxFreeNodeSize * 100 / poolStatus.totalFreeSize; /* 100: percent denominator. */ UINT8 usage = LOS_MemTotalUsedGet(pool) * 100 / LOS_MemPoolSizeGet(pool); / * 100: percent denominator. */ LOS_Trace(LOS_TRACE_MEM_INFO, (UINTPTR)pool & MEM_POOL_ADDR_MASK, fragment, usage, poolStatus.totalFreeSize, poolStatus.maxFreeNodeSize, poolStatus.usedNodeNum, poolStatus.freeNodeNum); #endif OsHookCall(LOS_HOOK_TYPE_MEM_ALLOC, pool, size); return ptr; }

Let’s move on to the function osMemAlloc (). ⑴ add the size of the applied memory to the size of the head node and align the memory; ⑵ get a free memory block from the free memory linked list that meets the size of the application. If the application fails, an error message will be printed. (3) If the memory block found is larger than the required memory size, the split operation is performed. (4) Mark the allocated memory nodes as used, and update the waterline record. ⑸ returns the address of the data area of the memory block. This is done by adding 1 to the address of the memory node to locate the memory address of the data area. The memory claim is complete, and the memory claim can now be used in the call to the memory claim function.

STATIC INLINE VOID *OsMemAlloc(struct OsMemPoolHead *pool, UINT32 size, UINT32 intSave) { struct OsMemNodeHead *allocNode = NULL; #if (LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK == 1) if (OsMemAllocCheck(pool, intSave) == LOS_NOK) { return NULL; } #endif UINT32 allocSize = OS_MEM_ALIGN(size + OS_MEM_NODE_HEAD_SIZE, OS_MEM_ALIGN_SIZE); #if OS_MEM_EXPAND_ENABLE retry: #endif ⑵ allocNode = osmemFreenodeGet (pool, allocSize); if (allocNode == NULL) { #if OS_MEM_EXPAND_ENABLE if (pool->info.attr & OS_MEM_POOL_EXPAND_ENABLE) { INT32 ret = OsMemPoolExpand(pool, allocSize, intSave); if (ret == 0) { goto retry; } } #endif PRINT_ERR("---------------------------------------------------" "--------------------------------------------------------\n"); MEM_UNLOCK(pool, intSave); OsMemInfoPrint(pool); MEM_LOCK(pool, intSave); PRINT_ERR("[%s] No suitable free block, require free node size: 0x%x\n", __FUNCTION__, allocSize); PRINT_ERR("----------------------------------------------------" "-------------------------------------------------------\n"); return NULL; } ⑶ if ((allocSize + OS_MEM_MIN_LEFT_SIZE) <= allocNode-> sizeandFflag) {osmemSplitNode (pool, allocNode, allocSize); } (4) OS_MEM_NODE_SET_USED_FLAG (allocNode - > sizeAndFlag); OsMemWaterUsedRecord(pool, OS_MEM_NODE_GET_SIZE(allocNode->sizeAndFlag)); #if (LOSCFG_MEM_LEAKCHECK == 1) OsMemLinkRegisterRecord(allocNode); #endif ⑸ return osmemCreateUseNode ((VOID *)allocNode); }

2.4 Request dynamic memory according to specified byte alignment

We can also use the function VOID LOS_MemAllocAlign(VOID pool, UINT32 size, UINT32 boundary) to claim memory of size and boundary byte alignment from the specified dynamic memory pool. This function takes three parameters: VOID pool is the starting address of the memory pool, UINT32 size is the memory size to be applied, and UINT32 boundary memory alignment is the value. VOID *alignedPtr = VOID *alignedPtr = VOID *alignedPtr = VOID *alignedPtr = VOID *alignedPtr = VOID *alignedPtr Because the memory alignment is OS_MEM_ALIGN_SIZE, the maximum offset is boundary – OS_MEM_ALIGN_SIZE. Let’s analyze the source code.

(1) Check the parameters. The memory pool address cannot be empty, the applied memory size cannot be 0, the aligned byte boundary cannot be 0, and it also needs to be a power of 2. The requested memory size must be greater than the minimum request value OS_MEM_MIN_ALLOC_SIZE. (2) Check whether there is data overflow after memory alignment. ⑶ calculates the memory size that needs to be applied after alignment, and then determines that there is no used or aligned memory size value. (4) Call the function to apply to memory VOID PTR, then calculate the aligned memory address VOID alignedPtr, and return if the two are equal. Calculate the offset value of aligned memory at ⑸, and get the header node of applied memory at ⑹, and set the aligned marker. He sets the alignment flag on the offset and stores the offset in the first 4 bytes of VOID *alignedPtr in memory. The ⑻ place redirects the pointer to return, completing the claim to align the memory.

VOID *LOS_MemAllocAlign(VOID *pool, UINT32 size, UINT32 boundary) { #if OS_MEM_TRACE UINT64 start = HalClockGetCycles(); #endif UINT32 gapSize; (1) if ((pool = = NULL) | | (size = = 0) | | (boundary = = 0) | |! OS_MEM_IS_POW_TWO(boundary) || ! OS_MEM_IS_ALIGNED(boundary, sizeof(VOID *))) { return NULL; } if (size < OS_MEM_MIN_ALLOC_SIZE) { size = OS_MEM_MIN_ALLOC_SIZE; } if ((border-sizeof (gapSize)) > ((UINT32)(-1) -size)) {return NULL; } ⑶ UINT32 useSize = (size + boundary) -sizeof (gapSize); if (OS_MEM_NODE_GET_USED_FLAG(useSize) || OS_MEM_NODE_GET_ALIGNED_FLAG(useSize)) { return NULL; } struct OsMemPoolHead *poolHead = (struct OsMemPoolHead *)pool; UINT32 intSave; VOID *ptr = NULL; VOID *alignedPtr = NULL; MEM_LOCK(poolHead, intSave); Do {⑷ Ptr = OsMemAlloc(pool, useSize, intSave); alignedPtr = (VOID *)OS_MEM_ALIGN(ptr, boundary); if (ptr == alignedPtr) { break; } /* store gapSize in address (ptr - 4), It will be checked while free */ ⑸ = (UINT32)((UINTPTR)alignedPtr - (UINTPTR) PTR); ⑹ struct osmemusedNodehead *allocNode = (struct osmemusedNodehead *) ptr-1; OS_MEM_NODE_SET_ALIGNED_FLAG(allocNode->header.sizeAndFlag); Once OS_MEM_SET_GAPSIZE_ALIGNED_FLAG (gapSize); *(UINT32 *)((UINTPTR)alignedPtr - sizeof(gapSize)) = gapSize; Being PTR = alignedPtr; } while (0); MEM_UNLOCK(poolHead, intSave); #if OS_MEM_TRACE UINT64 end = HalClockGetCycles(); UINT32 timeUsed = MEM_TRACE_CYCLE_TO_US(end - start); LOS_Trace(LOS_TRACE_MEM_TIME, (UINTPTR)pool & MEM_POOL_ADDR_MASK, MEM_TRACE_MEMALIGN, timeUsed); #endif OsHookCall(LOS_HOOK_TYPE_MEM_ALLOCALIGN, pool, size, boundary); return ptr; }

2.5 Free dynamic memory

We can use the function uint32los_memfree (VOID pool, VOID PTR) to free the dynamic memory, taking 2 arguments. VOID pool is the initialized dynamic memory pool address. VOID PTR is the starting address of the data area of the dynamic memory block that needs to be freed. Note that this is not the address of the memory control node. The following analysis of the source code, the first parameter of the incoming calibration. ⑵ get the real memory address after the alignment of memory, and then get the memory node nodding address. (3) The function osmemFree (pool, PTR) is called to complete the memory release.

UINT32 LOS_MemFree(VOID *pool, VOID *ptr) { #if OS_MEM_TRACE UINT64 start = HalClockGetCycles(); # endif (1) if ((pool = = NULL) | | (PTR = = NULL) | |! OS_MEM_IS_ALIGNED(pool, sizeof(VOID *)) || ! OS_MEM_IS_ALIGNED(ptr, sizeof(VOID *))) { return LOS_NOK; } UINT32 ret = LOS_NOK; struct OsMemPoolHead *poolHead = (struct OsMemPoolHead *)pool; struct OsMemNodeHead *node = NULL; UINT32 intSave; MEM_LOCK(poolHead, intSave); Do {⑵ PTR = osGetRealptr (pool, PTR); if (ptr == NULL) { break; } node = (struct OsMemNodeHead *)((UINTPTR)ptr - OS_MEM_NODE_HEAD_SIZE); ⑶ ret = OsMemFree(poolHead, node); } while (0); MEM_UNLOCK(poolHead, intSave); #if OS_MEM_TRACE UINT64 end = HalClockGetCycles(); UINT32 timeUsed = MEM_TRACE_CYCLE_TO_US(end - start); LOS_Trace(LOS_TRACE_MEM_TIME, (UINTPTR)pool & MEM_POOL_ADDR_MASK, MEM_TRACE_FREE, timeUsed); #endif OsHookCall(LOS_HOOK_TYPE_MEM_FREE, pool, ptr); return ret; }

Let’s go back to the function osGetRealPtr (). ⑴ Gets the memory-aligned offset; ⑵ Returns an error if the offset is marked both used and aligned. ⑶ If the offset is marked as aligned, then execute ⑷ to remove the alignment marker and get the unmarked offset. Then execute ⑸ to get the memory address of the data area before memory alignment.

STATIC INLINE VOID *OsGetRealPtr(const VOID *pool, VOID *ptr) { VOID *realPtr = ptr; ⑴ UINT32 gapSize = *((UINT32 *)((UINTPTR) ptr-sizeof (UINT32))); ⑴ UINT32 gapSize = *((UINT32 *)); ⑵ if (OS_MEM_GAPSIZE_CHECK(gapSize)) {PRINT_ERR("[%s:%d]gapSize:0x%x error\n", __FUNCTION__, __LINE__, gapSize); ⑵ if (OS_MEM_GAPSIZE_CHECK(gapSize)) {PRINT_ERR("[%s:%d]gapSize:0x%x error\n", __FUNCTION__, __LINE__, gapSize); return NULL; ⑶ if (OS_MEM_GET_GAPSIZE_ALIGNED_FLAG(gapSize)) {⑷ gapSize = OS_MEM_GET_ALIGNED_GAPSIZE(gapSize)); if ((gapSize & (OS_MEM_ALIGN_SIZE - 1)) || (gapSize > ((UINTPTR)ptr - OS_MEM_NODE_HEAD_SIZE - (UINTPTR)pool))) { PRINT_ERR("[%s:%d]gapSize:0x%x error\n", __FUNCTION__, __LINE__, gapSize); return NULL; } ⑸ realPtr = (VOID *)((uintPtr) PTR - (uintPtr)gapSize); } return realPtr; }

2.6 Reapply dynamic memory

We can also use the function VOID LOS_MemRealloc(VOID pool, VOID PTR, UINT32 size) to reallocate the memory block at the specified size and copy the contents of the original memory block to the new memory block. If the request for a new memory block is successful, the original memory block is released. VOID * PTR VOID * PTR VOID * PTR VOID * PTR VOID * PTR VOID * PTR VOID * PTR Returns the address of the new memory block, or NULL. Let’s analyze the source code.

(1). The memory pool address cannot be empty, and the memory size cannot contain used and aligned flags. ⑵ If the memory address passed in is null, it is equivalent to LOS_MemAlloc(). ⑶ If we pass in size 0, this is equivalent to LOS_MemFree(). (4) Ensure that the applied memory block size is at least the minimum allowed by the system OS_MEM_MIN_ALLOC_SIZE. (⑸) to get the memory address before memory alignment. The function osGetRealPtr () was analyzed above. It calculates the memory address of the memory control node by the memory address of the data domain, and then performs the ⑺ function to reapply for memory.

VOID *LOS_MemRealloc(VOID *pool, VOID *ptr, UINT32 size) { #if OS_MEM_TRACE UINT64 start = HalClockGetCycles(); # endif (1) if ((pool = = NULL) | | OS_MEM_NODE_GET_USED_FLAG (size) | | OS_MEM_NODE_GET_ALIGNED_FLAG (size)) {return NULL; } OsHookCall(LOS_HOOK_TYPE_MEM_REALLOC, pool, ptr, size); ⑵ if (PTR == NULL) {return LOS_MemAlloc(pool, size); ⑵ if (pool, size) {return LOS_MemAlloc(pool, size); } ⑶ if (size == 0) {(VOID)LOS_MemFree(pool, PTR); return NULL; If (size < OS_MEM_MIN_ALLOC_SIZE) {size = OS_MEM_MIN_ALLOC_SIZE; } struct OsMemPoolHead *poolHead = (struct OsMemPoolHead *)pool; struct OsMemNodeHead *node = NULL; VOID *newPtr = NULL; UINT32 intSave; MEM_LOCK(poolHead, intSave); Do {⑸ ⑸ Ptr = OsGetRealPtr(pool, Ptr); if (ptr == NULL) { break; } ⑹ node = (struct OsMemNodeHead *)((UINTPTR) ptr-os_mem_node_head_size); if (OsMemCheckUsedNode(pool, node) ! = LOS_OK) { break; } ⑺ newPtr = osMemRealLoc (pool, PTR, node, size, intSave); } while (0); MEM_UNLOCK(poolHead, intSave); #if OS_MEM_TRACE UINT64 end = HalClockGetCycles(); UINT32 timeUsed = MEM_TRACE_CYCLE_TO_US(end - start); LOS_Trace(LOS_TRACE_MEM_TIME, (UINTPTR)pool & MEM_POOL_ADDR_MASK, MEM_TRACE_REALLOC, timeUsed); #endif return newPtr; }

Let’s move on to the function OsMemRealLoc. (1) If the reapplied memory is less than or equal to the existing memory, call osMemRealLocsmaller () to split it, and return (VOID *) PTR after the split. If you reapply for more memory, execute the code at ⑵ to get the next node, and then execute ⑶ to process that the next node is available and that the sum of the two nodes is greater than or equal to the size of the reapply memory, allocSize. Execute the function at four, merge nodes and redistribute memory.

If the size of contiguous nodes is not sufficient to reapply the memory, then execute the function (⑸) to reapply the memory. After the success of the application, the execution of the previous memory data copy to the new application memory area, if the copy failed, the new application memory release, and return NULL, exit the function. If the copy is successful, proceed with ⑺ to free the previous node.

STATIC INLINE VOID *OsMemRealloc(struct OsMemPoolHead *pool, const VOID *ptr, struct OsMemNodeHead *node, UINT32 size, UINT32 intSave) { struct OsMemNodeHead *nextNode = NULL; UINT32 allocSize = OS_MEM_ALIGN(size + OS_MEM_NODE_HEAD_SIZE, OS_MEM_ALIGN_SIZE); UINT32 nodeSize = OS_MEM_NODE_GET_SIZE(node->sizeAndFlag); VOID *tmpPtr = NULL; ⑴ if (nodeSize >= allocSize) {smaller (pool, allocSize, node, nodeSize); return (VOID *)ptr; } ⑵ nextNode = OS_MEM_NEXT_NODE(node); (3) if (! OS_MEM_NODE_GET_USED_FLAG(nextNode-> sizeandFflag) &&((nextNode-> sizeandFflag + nodeSize) >= allocSize)) {⑷ OsMemMergeNodeForReAllocBigger(pool, allocSize, node, nodeSize, nextNode); return (VOID *)ptr; } ⑸ ⑸ TMPPTR = osMemalloc (pool, size, intSave); if (tmpPtr ! = NULL) {⑹ memcpy_s(tmpPtr, size, PTR, (nodesize-os_mem_node_head_size))! = EOK) { MEM_UNLOCK(pool, intSave); (VOID)LOS_MemFree((VOID *)pool, (VOID *)tmpPtr); MEM_LOCK(pool, intSave); return NULL; } once (VOID) OsMemFree (pool, node); } return tmpPtr; }

summary

This article led us to analyze the HongMeng light kernel static memory module source code, including the structure of dynamic memory, dynamic memory pool initialization, dynamic memory application, release, etc. Thanks for reading, if you have any question, advice, can leave a message to us: https://gitee.com/openharmony… . In order to more easily find HongMeng kernel code warehouse, suggest to https://gitee.com/openharmony… , follow Watch, thumb up Star, and Fork to your account, thank you.

Click on the attention, the first time to understand Huawei cloud fresh technology ~