os_mem.c(全)
- 簡單介紹內存管理
- 新建內存單元OS_MEM ?*OSMemCreate (void *addr,INT32U nblks,INT32U ?blksize,INT8U ?*perr)
- 獲得內存塊void ?*OSMemGet (OS_MEM ?*pmem,INT8U *perr)
- 得到內存分區名稱INT8U ?OSMemNameGet (OS_MEM ? *pmem,INT8U ? **pname,INT8U ? ?*perr)
- 給內存分區設置名稱
- 釋放內存塊INT8U ?OSMemPut (OS_MEM ?*pmem,void ?*pblk)
- 查詢內存分區信息INT8U ?OSMemQuery (OS_MEM *pmem,OS_MEM_DATA ?*p_mem_data)
- 初始化內存分區管理void ?OS_MemInit (void)
內存管理介紹:
????我們都知道可以用malloc()和free()兩個函數動態地分配內存和釋放內存。但是,在嵌入式實時操作系統中,多次這樣做會把原來很大的一塊連續內存區域,逐漸地分割成許多非常小而且彼此又不相鄰的內存區域,即內存碎片。內存碎片的大量存在不利于我們后續再分配內存。
? ? 所以,在μC/OS-II中,操作系統把連續的大塊內存按分區來管理。每個分區中包含有整數個大小相同的內存塊。利用這種機制,μC/OS-II 對malloc()和free()函數進行了改進,使得它們可以分配和釋放固定大小的內存塊。這樣還有一個好處就是malloc()和free()函數的執行時間是固定的。
????在一個系統中可以有多個內存分區。這樣,用戶的應用程序就可以從不同的內存分區中得到不同大小的內存塊。但是,特定的內存塊在釋放時必須重新放回它以前所屬于的內存分區。顯然,采用這樣的內存管理算法,上面的內存碎片問題就得到了解決。
????為了便于內存的管理,在μC/OS-II中使用內存控制塊(memory control blocks)的數據結構來跟蹤每一個內存分區,系統中的每個內存分區都有它自己的內存控制塊。內存控制塊的定義如下(uc/os-ii中):
新建內存分區OS_MEM ?*OSMemCreate (void ? *addr,?INT32U ?nblks,INT32U ?blksize,INT8U ?*perr):
源代碼如下:
#if (OS_MEM_EN > 0u) && (OS_MAX_MEM_PART > 0u) /*2018/2/23 ********************************************************************************************************* * CREATE A MEMORY PARTITION * 新建內存單元 * Description : Create a fixed-sized memory partition that will be managed by uC/OS-II. *描述:建立一個大小可調節的內存單元,uc/os-ii管理該單元 * Arguments : addr is the starting address of the memory partition *參數: --addr:內存單元的起始地址。內存區可以使用靜態數組或在初始化時使用malloc()函數建立 * nblks is the number of memory blocks to create from the partition.blksize is the size (in bytes) of each block in the memory partition. * --nblks:需要的內存塊的數目。塊的大小是內存分區每一塊的大小(字節為單位) * perr is a pointer to a variable containing an error message which will be set by * this function to either: * OS_ERR_NONE if the memory partition has been created correctly. * OS_ERR_MEM_INVALID_ADDR if you are specifying an invalid address for the memory * storage of the partition or, the block does not align * on a pointer boundary * OS_ERR_MEM_INVALID_PART no free partitions available * OS_ERR_MEM_INVALID_BLKS user specified an invalid number of blocks (must be >= 2) * OS_ERR_MEM_INVALID_SIZE user specified an invalid block size * - must be greater than the size of a pointer * - must be able to hold an integral number of pointers * --perr:指向錯誤碼的指針。可以設置為以下值:OS_ERR_NONE:內存分區成功建立。OS_ERR_MEM_INVALID_ADDR:指定了非法地址或者為空指針OS_ERR_MEM_INVALID_PART:沒有空閑的分區可以使用。OS_ERR_MEM_INVALID_BLKS:使用者指定了無效的內存塊(內存塊數要>=2)OS_ERR_MEM_INVALID_SIZE:使用者指定了無效的塊大小:-必須比指針大;-指針為整數值 * Returns : != (OS_MEM *)0 is the partition was created * == (OS_MEM *)0 if the partition was not created because of invalid arguments or, no * free partition is available.返回值:!= (OS_MEM *)0:內存分區成功創建。== (OS_MEM *)0:內存分區沒有被創建因為參數無效或者沒有可用的空閑分區。 ********************************************************************************************************* */OS_MEM *OSMemCreate (void *addr,INT32U nblks,INT32U blksize,INT8U *perr) {OS_MEM *pmem;/*指向內存控制塊的指針*/INT8U *pblk;/*每塊內存塊的起始地址*/void **plink;/*鏈接起始地址*/INT32U loops;INT32U i;/*內存包含的內存區數量*/#if OS_CRITICAL_METHOD == 3u OS_CPU_SR cpu_sr = 0u;#endif#ifdef OS_SAFETY_CRITICALif (perr == (INT8U *)0) {OS_SAFETY_CRITICAL_EXCEPTION();}#endif#ifdef OS_SAFETY_CRITICAL_IEC61508if (OSSafetyCriticalStartFlag == OS_TRUE) {OS_SAFETY_CRITICAL_EXCEPTION();}#endif#if OS_ARG_CHK_EN > 0uif (addr == (void *)0) { /*當內存起始地址為0時*/ *perr = OS_ERR_MEM_INVALID_ADDR;/*錯誤顯示為(非法地址,即地址為空指針,無效)*/return ((OS_MEM *)0);}if (((INT32U)addr & (sizeof(void *) - 1u)) != 0u){ *perr = OS_ERR_MEM_INVALID_ADDR;return ((OS_MEM *)0);}if (nblks < 2u) { /*內存塊至少為2*/ *perr = OS_ERR_MEM_INVALID_BLKS;return ((OS_MEM *)0);}if (blksize < sizeof(void *)) { /*每個內存塊至少容得一個指針(鏈接指針)*/ *perr = OS_ERR_MEM_INVALID_SIZE;/*否則顯示(內存塊大小不足以容納一個指針變量)*/return ((OS_MEM *)0);}#endifOS_ENTER_CRITICAL();/*進入中斷*/pmem = OSMemFreeList; /*得到空閑的內存分區*/if (OSMemFreeList != (OS_MEM *)0)/*有空閑的內存分區*/{ OSMemFreeList = (OS_MEM *)OSMemFreeList->OSMemFreeList;/*指向下一個空余鏈接控制塊*/}OS_EXIT_CRITICAL();/*退出中斷*/if (pmem == (OS_MEM *)0) /*沒有獲得內存分區*/{ *perr = OS_ERR_MEM_INVALID_PART;return ((OS_MEM *)0);}/*獲得了內存分區*/plink = (void **)addr;/*/鏈接起始地址=內存分區起始地址*/pblk = (INT8U *)addr;loops = nblks - 1u;/*循環次數*/for (i = 0u; i < loops; i++) {pblk += blksize; /*每塊內存的起始地址=內存分區起始地址+每塊內存塊大小 */*plink = (void *)pblk;plink = (void **)pblk;}*plink = (void *)0;/*最后一個鏈接指針指為空 */pmem->OSMemAddr = addr; /* 存儲內存分區開始地址 */pmem->OSMemFreeList = addr; /*內存空閑列表指向內存分區起始地址*/pmem->OSMemNFree = nblks;/* 分區中空閑內存塊數量=需要的內存塊數目 */pmem->OSMemNBlks = nblks;/*總的內存塊數量=需要的內存塊數目*/pmem->OSMemBlkSize = blksize;/*內存塊大小 */*perr = OS_ERR_NONE;return (pmem); }其中一些語句解釋如下:(個人理解)
1.
pmem = OSMemFreeList; /*得到空閑的內存分區*/if (OSMemFreeList != (OS_MEM *)0)/*有空閑的內存分區*/{ OSMemFreeList = (OS_MEM *)OSMemFreeList->OSMemFreeList;/*更新空閑內存列表*/}OS_EXIT_CRITICAL();/*退出中斷*/if (pmem == (OS_MEM *)0) /*沒有獲得內存分區*/{ *perr = OS_ERR_MEM_INVALID_PART;return ((OS_MEM *)0);}這里想說一下:我們看到判斷了兩次,第一次是判斷有沒有空閑的內存分區。這個是為了更新空閑列表設置的。第二次是判斷有沒有獲得內存分區。有空閑分區我們不一定會獲得,所以需要進行確認。
2.for循環中:
for (i = 0u; i < loops; i++) {pblk += blksize; /*每塊內存的起始地址=內存分區起始地址+每塊內存塊大小 */*plink = (void *)pblk;plink = (void **)pblk;}這里兩行語句沒有注釋,因為覺得說不清楚。個人理解是:
1).pblk每次進行計算,保存的是下一個內存塊起始地址。
2)plink指向pblk指向的那個地址;
3)plink本身作為下一個塊的鏈接。
獲得內存塊void ?*OSMemGet (OS_MEM ?*pmem,INT8U ? *perr):
得到內存分區名稱INT8U ?OSMemNameGet (OS_MEM ? *pmem,INT8U ? **pname,INT8U ? ?*perr):
/*$PAGE*/ /*2018/2/23 ********************************************************************************************************* * GET THE NAME OF A MEMORY PARTITION * 得到內存分區名稱 * Description: This function is used to obtain the name assigned to a memory partition. *描述:該函數是用來獲得內存分區的名稱 * Arguments : pmem is a pointer to the memory partition *參數: --pmem:指向內存分區的指針 * pname is a pointer to a pointer to an ASCII string that will receive the name of the memory partition. * --pname:指向內存分區名稱的指針 * perr is a pointer to an error code that can contain one of the following values: * OS_ERR_NONE if the name was copied to 'pname' * OS_ERR_MEM_INVALID_PMEM if you passed a NULL pointer for 'pmem' * OS_ERR_PNAME_NULL You passed a NULL pointer for 'pname' * OS_ERR_NAME_GET_ISR You called this function from an ISR * --perr:指向錯誤碼的指針:OS_ERR_NONE:名字被復制到了pname;OS_ERR_MEM_INVALID_PMEM:pmem為空指針OS_ERR_PNAME_NULL:pname為空指針OS_ERR_NAME_GET_ISR:從中斷服務子程序中調用該函數 * Returns : The length of the string or 0 if 'pmem' is a NULL pointer. 返回值:如果pname為空指針返回0,否則返回名稱的長度 ********************************************************************************************************* */#if OS_MEM_NAME_EN > 0u INT8U OSMemNameGet (OS_MEM *pmem,INT8U **pname,INT8U *perr) {INT8U len;/*存儲名稱的長度*/#if OS_CRITICAL_METHOD == 3u OS_CPU_SR cpu_sr = 0u;#endif#ifdef OS_SAFETY_CRITICALif (perr == (INT8U *)0) {OS_SAFETY_CRITICAL_EXCEPTION();}#endif#if OS_ARG_CHK_EN > 0uif (pmem == (OS_MEM *)0) { *perr = OS_ERR_MEM_INVALID_PMEM;return (0u);}if (pname == (INT8U **)0) { *perr = OS_ERR_PNAME_NULL;return (0u);}#endifif (OSIntNesting > 0u) { *perr = OS_ERR_NAME_GET_ISR;return (0u);}OS_ENTER_CRITICAL();/(進入中斷*pname = pmem->OSMemName;/*將名稱賦給pname*/len = OS_StrLen(*pname);/*求出名稱的長度*/OS_EXIT_CRITICAL();/*退出中斷*/*perr = OS_ERR_NONE;return (len);/*返回長度*/ } #endif給中斷分區設置名稱void ?OSMemNameSet (OS_MEM ?*pmem,INT8U ? *pname,INT8U ? *perr):(部分)
OS_ENTER_CRITICAL();/*進入中斷*/pmem->OSMemName = pname;/*設置名稱*/OS_EXIT_CRITICAL();/*退出中斷*/*perr = OS_ERR_NONE;釋放內存塊INT8U ?OSMemPut (OS_MEM ?*pmem,?void ?*pblk)(部分):
OS_ENTER_CRITICAL();/*進入中斷*/if (pmem->OSMemNFree >= pmem->OSMemNBlks)/*釋放的塊數大于分配的塊數*/{ OS_EXIT_CRITICAL();/*退出中斷*/return (OS_ERR_MEM_FULL);/*返回錯誤類型*/}/*釋放的塊數小于分配的塊數,可以釋放*/*(void **)pblk = pmem->OSMemFreeList; /*將釋放的塊插入到空閑內存列表中*/pmem->OSMemFreeList = pblk;pmem->OSMemNFree++;/* 將空閑塊數目加1 */OS_EXIT_CRITICAL();/*退出中斷*/return (OS_ERR_NONE);查詢內存分區信息INT8U ?OSMemQuery (OS_MEM *pmem,OS_MEM_DATA ?*p_mem_data):(部分)
OS_ENTER_CRITICAL();/*進入中斷*/p_mem_data->OSAddr = pmem->OSMemAddr;p_mem_data->OSFreeList = pmem->OSMemFreeList;p_mem_data->OSBlkSize = pmem->OSMemBlkSize;p_mem_data->OSNBlks = pmem->OSMemNBlks;p_mem_data->OSNFree = pmem->OSMemNFree;OS_EXIT_CRITICAL();p_mem_data->OSNUsed = p_mem_data->OSNBlks - p_mem_data->OSNFree;其實就是進行了最上面兩個結構體內容的賦值。
初始化內存分區管理void ?OS_MemInit (void):
到這里os_mem.c文件就讀完了。
===============================================================
===============================================================
總結
以上是生活随笔為你收集整理的os_mem.c(全)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: OS_Q.C(全)
- 下一篇: uc/os-ii中最高优先级计算(如何查