转载

uC/OS-II 函数之内存管理相关函数

> 上文主要介绍了邮箱管理相关的函数,本文介绍内存管理相关的函数:OSMemCreate()内存块创建函数,OSMemGet()函数,OSMemPut()函数,OSMemQuery()函数.以前用过的uC/OS-II笔记分享到这里。

内存管理介绍

在ANSI C中可以用malloc()和free()两个函数动态地分配内存和释放内存。但是,在嵌入式实时操作系统中,多次这样做会把原来很大的一块连续内存区域,逐渐地分割成许多非常小而且彼此又不相邻的内存区域,也就是内存碎片。由于这些碎片的大量存在,使得程序到后来连非常小的内存也分配不到。另外,由于内存管理算法的原因,malloc()和free()函数执行时间是不确定的。 在μC/OS-II中,操作系统把连续的大块内存按分区来管理。每个分区中包含有整数个大小相同的内存块。利用这种机制,μC/OS-II 对malloc()和free()函数进行了改进,使得它们可以分配和释放固定大小的内存块。这样一来,malloc()和free()函数的执行时间也是固定的了。 在一个系统中可以有多个内存分区。这样,用户的应用程序就可以从不同的内存分区中得到不同大小的内存块。但是,特定的内存块在释放时必须重新放回它以前所属于的内存分区。显然,采用这样的内存管理算法,上面的内存碎片问题就得到了解决。

为了便于内存的管理,在μC/OS-II中使用内存控制块(memory control blocks)的数据结构来跟踪每一个内存分区,系统中的每个内存分区都有它自己的内存控制块。 内存控制块的定义如下: typedef struct { void *OSMemAddr; //指向内存分区起始地址的指针 void *OSMemFreeList; //是指向下一个空闲内存控制块或者下一个空闲的内存块的指针 INT32U OSMemBlkSize; //是内存分区中内存块的大小 INT32U OSMemNBlks; //内存分区中总的内存块数量 INT32U OSMemNFree; //内存分区中当前可以得空闲内存块数量 } OS_MEM; 如果要在μC/OS-II中使用内存管理,需要在OS_CFG.H文件中将开关量OS_MEM_EN设置为1。这样μC/OS-II 在启动时就会对内存管理器进行初始化[由OSInit()调用OSMemInit()实现]。常数OS_MAX_MEM_PART(见文件OS_CFG.H)定义了最大的内存分区数,该常数值最小应为2。

注意的事项

使用内存管理模块需要做的工作还有: 1.打开配置文件OS_CFG.H,将开关量OS_MEM_EN设置为1: #define OS_MEM_EN 0 2.打开配置文件OS_CFG.H,设置系统要建立的任务分区的数量: #define OS_MAX_MEM_PART 2

OSMemCreate()内存块创建函数

1 主要作用: 该函数建立并初始化一个用于动态内存分配的区域,该内存区域包含指定数目的、大小确定的内存块。应用可以动态申请这些内存块并在用完后将其释放回这个内存区域。该函数的返回值就是指向这个内存区域控制块的指针,并作为OSMemGet(),OSMemPut(),OSMemQuery() 等相关调用的参数。 2函数原型:OS_MEM *OSMemCreate( void *addr, INT32U nblks, INT32U blksize, INT8U *err ); 3参数说明:addr 建立的内存区域的起始地址。可以使用静态数组或在系统初始化时使用 malloc() 函数来分配这个区域的空间。 nblks 内存块的数目。每一个内存区域最少需要定义两个内存块。 blksize 每个内存块的大小,最小应该能够容纳一个指针变量。 err 是指向包含错误码的变量的指针。Err可能是如下几种情况: OS_NO_ERR :成功建立内存区域。 OS_MEM_INVALID_ADDR :非法地址,即地址为空指针。 OS_MEM_INVALID_PART :没有空闲的内存区域。 OS_MEM_INVALID_BLKS :没有为内存区域建立至少两个内存块。 OS_MEM_INVALID_SIZE :内存块大小不足以容纳一个指针变量。 5、函数主体在os_men.c中 4返回值说明: OSMemCreate() 函数返回指向所创建的内存区域控制块的指针。如果创建失败,函数返回空指针。

OSMemGet()函数

1 主要作用: 该函数用于从内存区域分配一个内存块。用户程序必须知道所建立的内存块的大小,并必须在使用完内存块后释放它。可以多次调用 OSMemGet() 函数。它的返回值就是指向所分配内存块的指针,并作为 OSMemPut() 函数的参数。 2函数原型:void *OSMemGet(OS_MEM *pmem, INT8U *err); 3参数说明:pmem 是指向内存区域控制块的指针,可以从 OSMemCreate() 函数的返回值中得到。 err 是指向包含错误码的变量的指针。Err可能是如下情况: OS_NO_ERR :成功得到一个内存块。 OS_MEM_NO_FREE_BLKS :内存区域中已经没有足够的内存块。 4返回值说明: OSMemGet() 函数返回指向所分配内存块的指针。如果没有可分配的内存块,OSMemGet() 函数返回空指针。 5、函数主体在os_men.c中

OSMemPut()

1 主要作用:该函数用于释放一个内存块,内存块必须释放回它原先所在的内存区域,否则会造成系统错误。 2函数原型:INT8U OSMemPut (OS_MEM *pmem, void *pblk); 3参数说明:pmem 是指向内存区域控制块的指针,可以从 OSMemCreate() 函数的返回值中得到。 pblk 是指向将被释放的内存块的指针。 4返回值说明: OSMemPut() 函数的返回值为下述之一: OS_NO_ERR :成功释放内存块 OS_MEM_FULL :内存区域已满,不能再接受更多释放的内存块。这种情况说明用户程序出现了错误,释放了多于用 OSMemGet() 函数得到的内存块。 5、函数主体在os_men.c中

OSMemQuery()

1 主要作用:该函数用于得到内存区域的信息。 2函数原型:INT8U OSMemQuery(OS_MEM *pmem, OS_MEM_DATA pdata); 3参数说明:pmem 是指向内存区域控制块的指针,可以从 OSMemCreate() 函数的返回值中得到。 pdata 是一个指向 OS_MEM_DATA 数据结构的指针,该数据结构包含了以下的域: void OSAddr; / 指向内存区域起始地址的指针 / void OSFreeList; / 指向空闲内存块列表起始地址的指针 / INT32U OSBlkSize; / 每个内存块的大小 / INT32U OSNBlks; / 该内存区域中的内存块总数 / INT32U OSNFree; / 空闲的内存块数目 / INT32U OSNUsed; / 已使用的内存块数目 */ 4返回值说明:函数返回值总是OS_NO_ERR。 5、函数主体在os_men.c中

附os_men.c代码

/* ********************************************************************************************************* *            uC/OS-II *            The Real-Time Kernel *           MEMORY MANAGEMENT * *         (c) Copyright 1992-2013, Micrium, Weston, FL *             All Rights Reserved * * File : OS_MEM.C * By   : Jean J. Labrosse * Version : V2.92.08 * * LICENSING TERMS: * --------------- *   uC/OS-II is provided in source form for FREE evaluation, for educational use or for peaceful research. * If you plan on using  uC/OS-II  in a commercial product you need to contact Micrium to properly license * its use in your product. We provide ALL the source code for your convenience and to help you experience * uC/OS-II.   The fact that the  source is provided does  NOT  mean that you can use it without  paying a * licensing fee. ********************************************************************************************************* */ # define  MICRIUM_SOURCE # ifndef  OS_MASTER_FILE # include <ucos_ii.h> # endif # if (OS_MEM_EN >  0u) && (OS_MAX_MEM_PART >  0u) /* ********************************************************************************************************* *           CREATE A MEMORY PARTITION * * Description : Create a fixed-sized memory partition that will be managed by uC/OS-II. * * Arguments   : addr  is the starting address of the memory partition * *      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. * *      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 * 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  *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        /* Allocate storage for CPU status register   */  OS_CPU_SR  cpu_sr = 0u; # endif # ifdef OS_SAFETY_CRITICAL  if (perr == (INT8U *)0) {   OS_SAFETY_CRITICAL_EXCEPTION();   return ((OS_MEM *)0);  } # endif # ifdef OS_SAFETY_CRITICAL_IEC61508  if (OSSafetyCriticalStartFlag == OS_TRUE) {   OS_SAFETY_CRITICAL_EXCEPTION();   return ((OS_MEM *)0);  } # endif # if OS_ARG_CHK_EN >  0u  if (addr == (void *)0) {        /* Must pass a valid address for the memory part.*/   *perr = OS_ERR_MEM_INVALID_ADDR;   return ((OS_MEM *)0);  }  if (((INT32U)addr & (sizeof(void *) - 1u)) != 0u){  /* Must be pointer size aligned    */   *perr = OS_ERR_MEM_INVALID_ADDR;   return ((OS_MEM *)0);  }  if (nblks < 2u) {         /* Must have at least 2 blocks per partition  */   *perr = OS_ERR_MEM_INVALID_BLKS;   return ((OS_MEM *)0);  }  if (blksize < sizeof(void *)) {       /* Must contain space for at least a pointer  */   *perr = OS_ERR_MEM_INVALID_SIZE;   return ((OS_MEM *)0);  } # endif  OS_ENTER_CRITICAL();  pmem = OSMemFreeList;        /* Get next free memory partition    */  if (OSMemFreeList != (OS_MEM *)0) {      /* See if pool of free partitions was empty   */   OSMemFreeList = (OS_MEM *)OSMemFreeList-> OSMemFreeList;  }  OS_EXIT_CRITICAL();  if (pmem == (OS_MEM *)0) {      /* See if we have a memory partition    */   *perr = OS_ERR_MEM_INVALID_PART;   return ((OS_MEM *)0);  }  plink = (void **)addr;       /* Create linked list of free memory blocks   */  pblk  = (INT8U *)addr;  loops  = nblks - 1u;  for (i = 0u; i < loops; i++) {   pblk +=  blksize;        /* Point to the FOLLOWING block      */     *plink = (void  *)pblk;      /* Save pointer to NEXT block in CURRENT block   */   plink = (void **)pblk;      /* Position to  NEXT   block      */  }  *plink     = (void *)0;      /* Last memory block points to NULL     */  pmem-> OSMemAddr  = addr;        /* Store start address of memory partition    */  pmem-> OSMemFreeList = addr;        /* Initialize pointer to pool of free blocks  */  pmem-> OSMemNFree = nblks;       /* Store number of free blocks in MCB   */  pmem-> OSMemNBlks = nblks;  pmem-> OSMemBlkSize  = blksize;     /* Store block size of each memory blocks  */  *perr      = OS_ERR_NONE;  return (pmem); } /*$PAGE*/ /* ********************************************************************************************************* *           GET A MEMORY BLOCK * * Description : Get a memory block from a partition * * Arguments   : pmem is a pointer to the memory partition control block * *      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_NO_FREE_BLKS if there are no more free memory blocks to allocate to caller *        OS_ERR_MEM_INVALID_PMEM if you passed a NULL pointer for 'pmem' * * Returns  : A pointer to a memory block if no error is detected *      A pointer to NULL if an error is detected ********************************************************************************************************* */ void  *OSMemGet (OS_MEM  *pmem,      INT8U   *perr) {  void   *pblk; # if OS_CRITICAL_METHOD == 3u        /* Allocate storage for CPU status register   */  OS_CPU_SR  cpu_sr = 0u; # endif # ifdef OS_SAFETY_CRITICAL  if (perr == (INT8U *)0) {   OS_SAFETY_CRITICAL_EXCEPTION();   return ((void *)0);  } # endif # if OS_ARG_CHK_EN >  0u  if (pmem == (OS_MEM *)0) {      /* Must point to a valid memory partition  */   *perr = OS_ERR_MEM_INVALID_PMEM;   return ((void *)0);  } # endif  OS_ENTER_CRITICAL();  if (pmem-> OSMemNFree >  0u) {       /* See if there are any free memory blocks    */   pblk    = pmem-> OSMemFreeList; /* Yes, point to next free memory block    */   pmem-> OSMemFreeList = *(void **)pblk;   /*   Adjust pointer to new free list    */   pmem-> OSMemNFree--;         /*   One less memory block in this partition  */   OS_EXIT_CRITICAL();   *perr = OS_ERR_NONE;        /*   No error         */   return (pblk);        /*   Return memory block to caller   */  }  OS_EXIT_CRITICAL();  *perr = OS_ERR_MEM_NO_FREE_BLKS;      /* No,  Notify caller of empty memory partition  */  return ((void *)0);          /*   Return NULL pointer to caller   */ } /*$PAGE*/ /* ********************************************************************************************************* *         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 * *     pname  is a pointer to a pointer to an ASCII string that will receive the name of the memory partition. * *     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 * * Returns : The length of the string or 0 if 'pmem' is a NULL pointer. ********************************************************************************************************* */ # if OS_MEM_NAME_EN >  0u INT8U  OSMemNameGet (OS_MEM   *pmem,       INT8U   **pname,       INT8U *perr) {  INT8U   len; # if OS_CRITICAL_METHOD == 3u      /* Allocate storage for CPU status register     */  OS_CPU_SR  cpu_sr = 0u; # endif # ifdef OS_SAFETY_CRITICAL  if (perr == (INT8U *)0) {   OS_SAFETY_CRITICAL_EXCEPTION();   return (0u);  } # endif # if OS_ARG_CHK_EN >  0u  if (pmem == (OS_MEM *)0) {       /* Is 'pmem' a NULL pointer?        */   *perr = OS_ERR_MEM_INVALID_PMEM;   return (0u);  }  if (pname == (INT8U **)0) {      /* Is 'pname' a NULL pointer?       */   *perr = OS_ERR_PNAME_NULL;   return (0u);  } # endif  if (OSIntNesting >  0u) {      /* See if trying to call from an ISR      */   *perr = OS_ERR_NAME_GET_ISR;   return (0u);  }  OS_ENTER_CRITICAL();  *pname = pmem-> OSMemName;  len = OS_StrLen(*pname);  OS_EXIT_CRITICAL();  *perr  = OS_ERR_NONE;  return (len); } # endif /*$PAGE*/ /* ********************************************************************************************************* *         ASSIGN A NAME TO A MEMORY PARTITION * * Description: This function assigns a name to a memory partition. * * Arguments  : pmem   is a pointer to the memory partition * *     pname  is a pointer to an ASCII string that contains the name of the memory partition. * *     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_MEM_NAME_TOO_LONG   if the name doesn't fit in the storage area *      OS_ERR_NAME_SET_ISR  if you called this function from an ISR * * Returns : None ********************************************************************************************************* */ # if OS_MEM_NAME_EN >  0u void  OSMemNameSet (OS_MEM  *pmem,      INT8U   *pname,      INT8U   *perr) { # if OS_CRITICAL_METHOD == 3u      /* Allocate storage for CPU status register     */  OS_CPU_SR  cpu_sr = 0u; # endif # ifdef OS_SAFETY_CRITICAL  if (perr == (INT8U *)0) {   OS_SAFETY_CRITICAL_EXCEPTION();   return;  } # endif # if OS_ARG_CHK_EN >  0u  if (pmem == (OS_MEM *)0) {       /* Is 'pmem' a NULL pointer?        */   *perr = OS_ERR_MEM_INVALID_PMEM;   return;  }  if (pname == (INT8U *)0) {       /* Is 'pname' a NULL pointer?       */   *perr = OS_ERR_PNAME_NULL;   return;  } # endif  if (OSIntNesting >  0u) {      /* See if trying to call from an ISR      */   *perr = OS_ERR_NAME_SET_ISR;   return;  }  OS_ENTER_CRITICAL();  pmem-> OSMemName = pname;  OS_EXIT_CRITICAL();  *perr     = OS_ERR_NONE; } # endif /*$PAGE*/ /* ********************************************************************************************************* *            RELEASE A MEMORY BLOCK * * Description : Returns a memory block to a partition * * Arguments   : pmem is a pointer to the memory partition control block * *      pblk is a pointer to the memory block being released. * * Returns  : OS_ERR_NONE     if the memory block was inserted into the partition *      OS_ERR_MEM_FULL    if you are returning a memory block to an already FULL memory *          partition (You freed more blocks than you allocated!) *      OS_ERR_MEM_INVALID_PMEM  if you passed a NULL pointer for 'pmem' *      OS_ERR_MEM_INVALID_PBLK  if you passed a NULL pointer for the block to release. ********************************************************************************************************* */ INT8U  OSMemPut (OS_MEM  *pmem,      void *pblk) { # if OS_CRITICAL_METHOD == 3u      /* Allocate storage for CPU status register     */  OS_CPU_SR  cpu_sr = 0u; # endif # if OS_ARG_CHK_EN >  0u  if (pmem == (OS_MEM *)0) {       /* Must point to a valid memory partition    */   return (OS_ERR_MEM_INVALID_PMEM);  }  if (pblk == (void *)0) {      /* Must release a valid block       */   return (OS_ERR_MEM_INVALID_PBLK);  } # endif  OS_ENTER_CRITICAL();  if (pmem-> OSMemNFree > = pmem-> OSMemNBlks) {  /* Make sure all blocks not already returned    */   OS_EXIT_CRITICAL();   return (OS_ERR_MEM_FULL);  }  *(void **)pblk   = pmem-> OSMemFreeList;   /* Insert released block into free block list   */  pmem-> OSMemFreeList = pblk;  pmem-> OSMemNFree++;        /* One more memory block in this partition   */  OS_EXIT_CRITICAL();  return (OS_ERR_NONE);      /* Notify caller that memory block was released    */ } /*$PAGE*/ /* ********************************************************************************************************* *            QUERY MEMORY PARTITION * * Description : This function is used to determine the number of free memory blocks and the number of *      used memory blocks from a memory partition. * * Arguments   : pmem  is a pointer to the memory partition control block * *      p_mem_data  is a pointer to a structure that will contain information about the memory *         partition. * * Returns  : OS_ERR_NONE      if no errors were found. *      OS_ERR_MEM_INVALID_PMEM   if you passed a NULL pointer for 'pmem' *      OS_ERR_MEM_INVALID_PDATA  if you passed a NULL pointer to the data recipient. ********************************************************************************************************* */ # if OS_MEM_QUERY_EN >  0u INT8U  OSMemQuery (OS_MEM    *pmem,        OS_MEM_DATA  *p_mem_data) { # if OS_CRITICAL_METHOD == 3u      /* Allocate storage for CPU status register     */  OS_CPU_SR  cpu_sr = 0u; # endif # if OS_ARG_CHK_EN >  0u  if (pmem == (OS_MEM *)0) {       /* Must point to a valid memory partition    */   return (OS_ERR_MEM_INVALID_PMEM);  }  if (p_mem_data == (OS_MEM_DATA *)0) {  /* Must release a valid storage area for the data  */   return (OS_ERR_MEM_INVALID_PDATA);  } # endif  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;  return (OS_ERR_NONE); } # endif             /* OS_MEM_QUERY_EN         */ /*$PAGE*/ /* ********************************************************************************************************* *         INITIALIZE MEMORY PARTITION MANAGER * * Description : This function is called by uC/OS-II to initialize the memory partition manager.  Your *      application MUST NOT call this function. * * Arguments   : none * * Returns  : none * * Note(s) : This function is INTERNAL to uC/OS-II and your application should not call it. ********************************************************************************************************* */ void  OS_MemInit (void) { # if OS_MAX_MEM_PART == 1u  OS_MemClr((INT8U *)&OSMemTbl[0], sizeof(OSMemTbl));   /* Clear the memory partition table    */  OSMemFreeList      = (OS_MEM *)&OSMemTbl[0]; /* Point to beginning of free list     */ # if OS_MEM_NAME_EN >  0u  OSMemFreeList-> OSMemName = (INT8U *)"?";     /* Unknown name         */ # endif # endif # if OS_MAX_MEM_PART > = 2u  OS_MEM  *pmem;  INT16U   i;  OS_MemClr((INT8U *)&OSMemTbl[0], sizeof(OSMemTbl));   /* Clear the memory partition table    */  for (i = 0u; i < (OS_MAX_MEM_PART - 1u); i++) {    /* Init. list of free memory partitions   */   pmem    = &OSMemTbl[i];      /* Point to memory control block (MCB)    */   pmem-> OSMemFreeList = (void *)&OSMemTbl[i + 1u];  /* Chain list of free partitions    */ # if OS_MEM_NAME_EN >  0u   pmem-> OSMemName  = (INT8U *)(void *)"?"; # endif  }  pmem    = &OSMemTbl[i];  pmem-> OSMemFreeList = (void *)0;       /* Initialize last node       */ # if OS_MEM_NAME_EN >  0u  pmem-> OSMemName = (INT8U *)(void *)"?"; # endif  OSMemFreeList   = &OSMemTbl[0];        /* Point to beginning of free list     */ # endif } # endif             /* OS_MEM_EN         */  
正文到此结束
Loading...