os_mem.c
上传用户:dongxin
上传日期:2022-06-22
资源大小:370k
文件大小:19k
源码类别:

uCOS

开发平台:

Others

  1. /*
  2. *********************************************************************************************************
  3. *                                                uC/OS-II
  4. *                                          The Real-Time Kernel
  5. *                                            MEMORY MANAGEMENT
  6. *
  7. *                              (c) Copyright 1992-2007, Micrium, Weston, FL
  8. *                                           All Rights Reserved
  9. *
  10. * File    : OS_MEM.C
  11. * By      : Jean J. Labrosse
  12. * Version : V2.86
  13. *
  14. * LICENSING TERMS:
  15. * ---------------
  16. *   uC/OS-II is provided in source form for FREE evaluation, for educational use or for peaceful research.  
  17. * If you plan on using  uC/OS-II  in a commercial product you need to contact Micri祄 to properly license 
  18. * its use in your product. We provide ALL the source code for your convenience and to help you experience 
  19. * uC/OS-II.   The fact that the  source is provided does  NOT  mean that you can use it without  paying a 
  20. * licensing fee.
  21. *********************************************************************************************************
  22. */
  23. #ifndef  OS_MASTER_FILE
  24. #include <ucos_ii.h>
  25. #endif
  26. #if (OS_MEM_EN > 0) && (OS_MAX_MEM_PART > 0)
  27. /*
  28. *********************************************************************************************************
  29. *                                        CREATE A MEMORY PARTITION
  30. *
  31. * Description : Create a fixed-sized memory partition that will be managed by uC/OS-II.
  32. *
  33. * Arguments   : addr     is the starting address of the memory partition
  34. *
  35. *               nblks    is the number of memory blocks to create from the partition.
  36. *
  37. *               blksize  is the size (in bytes) of each block in the memory partition.
  38. *
  39. *               perr     is a pointer to a variable containing an error message which will be set by
  40. *                        this function to either:
  41. *
  42. *                        OS_ERR_NONE              if the memory partition has been created correctly.
  43. *                        OS_ERR_MEM_INVALID_ADDR  if you are specifying an invalid address for the memory
  44. *                                                 storage of the partition or, the block does not align
  45. *                                                 on a pointer boundary
  46. *                        OS_ERR_MEM_INVALID_PART  no free partitions available
  47. *                        OS_ERR_MEM_INVALID_BLKS  user specified an invalid number of blocks (must be >= 2)
  48. *                        OS_ERR_MEM_INVALID_SIZE  user specified an invalid block size
  49. *                                                   - must be greater than the size of a pointer
  50. *                                                   - must be able to hold an integral number of pointers
  51. * Returns    : != (OS_MEM *)0  is the partition was created
  52. *              == (OS_MEM *)0  if the partition was not created because of invalid arguments or, no
  53. *                              free partition is available.
  54. *********************************************************************************************************
  55. */
  56. OS_MEM  *OSMemCreate (void *addr, INT32U nblks, INT32U blksize, INT8U *perr)
  57. {
  58.     OS_MEM    *pmem;
  59.     INT8U     *pblk;
  60.     void     **plink;
  61.     INT32U     i;
  62. #if OS_CRITICAL_METHOD == 3                           /* Allocate storage for CPU status register      */
  63.     OS_CPU_SR  cpu_sr = 0;
  64. #endif
  65. #if OS_ARG_CHK_EN > 0              
  66.     if (perr == (INT8U *)0) {                         /* Validate 'perr'                               */
  67.         return ((OS_MEM *)0);
  68.     }
  69.     if (addr == (void *)0) {                          /* Must pass a valid address for the memory part.*/
  70.         *perr = OS_ERR_MEM_INVALID_ADDR;
  71.         return ((OS_MEM *)0);
  72.     }
  73.     if (((INT32U)addr & (sizeof(void *) - 1)) != 0){  /* Must be pointer size aligned                  */
  74.         *perr = OS_ERR_MEM_INVALID_ADDR;
  75.         return ((OS_MEM *)0);
  76.     }
  77.     if (nblks < 2) {                                  /* Must have at least 2 blocks per partition     */
  78.         *perr = OS_ERR_MEM_INVALID_BLKS;
  79.         return ((OS_MEM *)0);
  80.     }
  81.     if (blksize < sizeof(void *)) {                   /* Must contain space for at least a pointer     */
  82.         *perr = OS_ERR_MEM_INVALID_SIZE;
  83.         return ((OS_MEM *)0);
  84.     }
  85. #endif
  86.     OS_ENTER_CRITICAL();
  87.     pmem = OSMemFreeList;                             /* Get next free memory partition                */
  88.     if (OSMemFreeList != (OS_MEM *)0) {               /* See if pool of free partitions was empty      */
  89.         OSMemFreeList = (OS_MEM *)OSMemFreeList->OSMemFreeList;
  90.     }
  91.     OS_EXIT_CRITICAL();
  92.     if (pmem == (OS_MEM *)0) {                        /* See if we have a memory partition             */
  93.         *perr = OS_ERR_MEM_INVALID_PART;
  94.         return ((OS_MEM *)0);
  95.     }
  96.     plink = (void **)addr;                            /* Create linked list of free memory blocks      */
  97.     pblk  = (INT8U *)((INT32U)addr + blksize);
  98.     for (i = 0; i < (nblks - 1); i++) {
  99.        *plink = (void *)pblk;                         /* Save pointer to NEXT block in CURRENT block   */
  100.         plink = (void **)pblk;                        /* Position to  NEXT      block                  */
  101.         pblk  = (INT8U *)((INT32U)pblk + blksize);    /* Point to the FOLLOWING block                  */
  102.     }
  103.     *plink              = (void *)0;                  /* Last memory block points to NULL              */
  104.     pmem->OSMemAddr     = addr;                       /* Store start address of memory partition       */
  105.     pmem->OSMemFreeList = addr;                       /* Initialize pointer to pool of free blocks     */
  106.     pmem->OSMemNFree    = nblks;                      /* Store number of free blocks in MCB            */
  107.     pmem->OSMemNBlks    = nblks;
  108.     pmem->OSMemBlkSize  = blksize;                    /* Store block size of each memory blocks        */
  109.     *perr               = OS_ERR_NONE;
  110.     return (pmem);
  111. }
  112. /*$PAGE*/
  113. /*
  114. *********************************************************************************************************
  115. *                                          GET A MEMORY BLOCK
  116. *
  117. * Description : Get a memory block from a partition
  118. *
  119. * Arguments   : pmem    is a pointer to the memory partition control block
  120. *
  121. *               perr    is a pointer to a variable containing an error message which will be set by this
  122. *                       function to either:
  123. *
  124. *                       OS_ERR_NONE             if the memory partition has been created correctly.
  125. *                       OS_ERR_MEM_NO_FREE_BLKS if there are no more free memory blocks to allocate to caller
  126. *                       OS_ERR_MEM_INVALID_PMEM if you passed a NULL pointer for 'pmem'
  127. *
  128. * Returns     : A pointer to a memory block if no error is detected
  129. *               A pointer to NULL if an error is detected
  130. *********************************************************************************************************
  131. */
  132. void  *OSMemGet (OS_MEM *pmem, INT8U *perr)
  133. {
  134.     void      *pblk;
  135. #if OS_CRITICAL_METHOD == 3                           /* Allocate storage for CPU status register      */
  136.     OS_CPU_SR  cpu_sr = 0;
  137. #endif
  138. #if OS_ARG_CHK_EN > 0
  139.     if (perr == (INT8U *)0) {                         /* Validate 'perr'                               */
  140.         return ((void *)0);
  141.     }
  142.     if (pmem == (OS_MEM *)0) {                        /* Must point to a valid memory partition        */
  143.         *perr = OS_ERR_MEM_INVALID_PMEM;
  144.         return ((void *)0);
  145.     }
  146. #endif
  147.     OS_ENTER_CRITICAL();
  148.     if (pmem->OSMemNFree > 0) {                       /* See if there are any free memory blocks       */
  149.         pblk                = pmem->OSMemFreeList;    /* Yes, point to next free memory block          */
  150.         pmem->OSMemFreeList = *(void **)pblk;         /*      Adjust pointer to new free list          */
  151.         pmem->OSMemNFree--;                           /*      One less memory block in this partition  */
  152.         OS_EXIT_CRITICAL();
  153.         *perr = OS_ERR_NONE;                          /*      No error                                 */
  154.         return (pblk);                                /*      Return memory block to caller            */
  155.     }
  156.     OS_EXIT_CRITICAL();
  157.     *perr = OS_ERR_MEM_NO_FREE_BLKS;                  /* No,  Notify caller of empty memory partition  */
  158.     return ((void *)0);                               /*      Return NULL pointer to caller            */
  159. }
  160. /*$PAGE*/
  161. /*
  162. *********************************************************************************************************
  163. *                                   GET THE NAME OF A MEMORY PARTITION
  164. *
  165. * Description: This function is used to obtain the name assigned to a memory partition.
  166. *
  167. * Arguments  : pmem      is a pointer to the memory partition
  168. *
  169. *              pname     is a pointer to an ASCII string that will receive the name of the memory partition.
  170. *
  171. *              perr      is a pointer to an error code that can contain one of the following values:
  172. *
  173. *                        OS_ERR_NONE                if the name was copied to 'pname'
  174. *                        OS_ERR_MEM_INVALID_PMEM    if you passed a NULL pointer for 'pmem'
  175. *                        OS_ERR_PNAME_NULL          You passed a NULL pointer for 'pname'
  176. *                        OS_ERR_NAME_GET_ISR        You called this function from an ISR
  177. *
  178. * Returns    : The length of the string or 0 if 'pmem' is a NULL pointer.
  179. *********************************************************************************************************
  180. */
  181. #if OS_MEM_NAME_SIZE > 1
  182. INT8U  OSMemNameGet (OS_MEM *pmem, INT8U *pname, INT8U *perr)
  183. {
  184.     INT8U      len;
  185. #if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
  186.     OS_CPU_SR  cpu_sr = 0;
  187. #endif
  188. #if OS_ARG_CHK_EN > 0
  189.     if (perr == (INT8U *)0) {                    /* Validate 'perr'                                    */
  190.         return (0);
  191.     }
  192.     if (pmem == (OS_MEM *)0) {                   /* Is 'pmem' a NULL pointer?                          */
  193.         *perr = OS_ERR_MEM_INVALID_PMEM;
  194.         return (0);
  195.     }
  196.     if (pname == (INT8U *)0) {                   /* Is 'pname' a NULL pointer?                         */
  197.         *perr = OS_ERR_PNAME_NULL;
  198.         return (0);
  199.     }
  200. #endif
  201.     if (OSIntNesting > 0) {                      /* See if trying to call from an ISR                  */
  202.         *perr = OS_ERR_NAME_GET_ISR;
  203.         return (0);
  204.     }
  205.     OS_ENTER_CRITICAL();
  206.     len   = OS_StrCopy(pname, pmem->OSMemName);  /* Copy name from OS_MEM                              */
  207.     OS_EXIT_CRITICAL();
  208.     *perr = OS_ERR_NONE;
  209.     return (len);
  210. }
  211. #endif
  212. /*$PAGE*/
  213. /*
  214. *********************************************************************************************************
  215. *                                 ASSIGN A NAME TO A MEMORY PARTITION
  216. *
  217. * Description: This function assigns a name to a memory partition.
  218. *
  219. * Arguments  : pmem      is a pointer to the memory partition
  220. *
  221. *              pname     is a pointer to an ASCII string that contains the name of the memory partition.
  222. *
  223. *              perr      is a pointer to an error code that can contain one of the following values:
  224. *
  225. *                        OS_ERR_NONE                if the name was copied to 'pname'
  226. *                        OS_ERR_MEM_INVALID_PMEM    if you passed a NULL pointer for 'pmem'
  227. *                        OS_ERR_PNAME_NULL          You passed a NULL pointer for 'pname'
  228. *                        OS_ERR_MEM_NAME_TOO_LONG   if the name doesn't fit in the storage area
  229. *                        OS_ERR_NAME_SET_ISR        if you called this function from an ISR
  230. *
  231. * Returns    : None
  232. *********************************************************************************************************
  233. */
  234. #if OS_MEM_NAME_SIZE > 1
  235. void  OSMemNameSet (OS_MEM *pmem, INT8U *pname, INT8U *perr)
  236. {
  237.     INT8U      len;
  238. #if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
  239.     OS_CPU_SR  cpu_sr = 0;
  240. #endif
  241. #if OS_ARG_CHK_EN > 0
  242.     if (perr == (INT8U *)0) {                    /* Validate 'perr'                                    */
  243.         return;
  244.     }
  245.     if (pmem == (OS_MEM *)0) {                   /* Is 'pmem' a NULL pointer?                          */
  246.         *perr = OS_ERR_MEM_INVALID_PMEM;
  247.         return;
  248.     }
  249.     if (pname == (INT8U *)0) {                   /* Is 'pname' a NULL pointer?                         */
  250.         *perr = OS_ERR_PNAME_NULL;
  251.         return;
  252.     }
  253. #endif
  254.     if (OSIntNesting > 0) {                      /* See if trying to call from an ISR                  */
  255.         *perr = OS_ERR_NAME_SET_ISR;
  256.         return;
  257.     }
  258.     OS_ENTER_CRITICAL();
  259.     len = OS_StrLen(pname);                      /* Can we fit the string in the storage area?         */
  260.     if (len > (OS_MEM_NAME_SIZE - 1)) {          /* No                                                 */
  261.         OS_EXIT_CRITICAL();
  262.         *perr = OS_ERR_MEM_NAME_TOO_LONG;
  263.         return;
  264.     }
  265.     (void)OS_StrCopy(pmem->OSMemName, pname);    /* Yes, copy name to the memory partition header      */
  266.     OS_EXIT_CRITICAL();
  267.     *perr = OS_ERR_NONE;
  268. }
  269. #endif
  270. /*$PAGE*/
  271. /*
  272. *********************************************************************************************************
  273. *                                         RELEASE A MEMORY BLOCK
  274. *
  275. * Description : Returns a memory block to a partition
  276. *
  277. * Arguments   : pmem    is a pointer to the memory partition control block
  278. *
  279. *               pblk    is a pointer to the memory block being released.
  280. *
  281. * Returns     : OS_ERR_NONE              if the memory block was inserted into the partition
  282. *               OS_ERR_MEM_FULL          if you are returning a memory block to an already FULL memory
  283. *                                        partition (You freed more blocks than you allocated!)
  284. *               OS_ERR_MEM_INVALID_PMEM  if you passed a NULL pointer for 'pmem'
  285. *               OS_ERR_MEM_INVALID_PBLK  if you passed a NULL pointer for the block to release.
  286. *********************************************************************************************************
  287. */
  288. INT8U  OSMemPut (OS_MEM *pmem, void *pblk)
  289. {
  290. #if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
  291.     OS_CPU_SR  cpu_sr = 0;
  292. #endif
  293. #if OS_ARG_CHK_EN > 0
  294.     if (pmem == (OS_MEM *)0) {                   /* Must point to a valid memory partition             */
  295.         return (OS_ERR_MEM_INVALID_PMEM);
  296.     }
  297.     if (pblk == (void *)0) {                     /* Must release a valid block                         */
  298.         return (OS_ERR_MEM_INVALID_PBLK);
  299.     }
  300. #endif
  301.     OS_ENTER_CRITICAL();
  302.     if (pmem->OSMemNFree >= pmem->OSMemNBlks) {  /* Make sure all blocks not already returned          */
  303.         OS_EXIT_CRITICAL();
  304.         return (OS_ERR_MEM_FULL);
  305.     }
  306.     *(void **)pblk      = pmem->OSMemFreeList;   /* Insert released block into free block list         */
  307.     pmem->OSMemFreeList = pblk;
  308.     pmem->OSMemNFree++;                          /* One more memory block in this partition            */
  309.     OS_EXIT_CRITICAL();
  310.     return (OS_ERR_NONE);                        /* Notify caller that memory block was released       */
  311. }
  312. /*$PAGE*/
  313. /*
  314. *********************************************************************************************************
  315. *                                          QUERY MEMORY PARTITION
  316. *
  317. * Description : This function is used to determine the number of free memory blocks and the number of
  318. *               used memory blocks from a memory partition.
  319. *
  320. * Arguments   : pmem        is a pointer to the memory partition control block
  321. *
  322. *               p_mem_data  is a pointer to a structure that will contain information about the memory
  323. *                           partition.
  324. *
  325. * Returns     : OS_ERR_NONE               if no errors were found.
  326. *               OS_ERR_MEM_INVALID_PMEM   if you passed a NULL pointer for 'pmem'
  327. *               OS_ERR_MEM_INVALID_PDATA  if you passed a NULL pointer to the data recipient.
  328. *********************************************************************************************************
  329. */
  330. #if OS_MEM_QUERY_EN > 0
  331. INT8U  OSMemQuery (OS_MEM *pmem, OS_MEM_DATA *p_mem_data)
  332. {
  333. #if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
  334.     OS_CPU_SR  cpu_sr = 0;
  335. #endif
  336. #if OS_ARG_CHK_EN > 0
  337.     if (pmem == (OS_MEM *)0) {                   /* Must point to a valid memory partition             */
  338.         return (OS_ERR_MEM_INVALID_PMEM);
  339.     }
  340.     if (p_mem_data == (OS_MEM_DATA *)0) {        /* Must release a valid storage area for the data     */
  341.         return (OS_ERR_MEM_INVALID_PDATA);
  342.     }
  343. #endif
  344.     OS_ENTER_CRITICAL();
  345.     p_mem_data->OSAddr     = pmem->OSMemAddr;
  346.     p_mem_data->OSFreeList = pmem->OSMemFreeList;
  347.     p_mem_data->OSBlkSize  = pmem->OSMemBlkSize;
  348.     p_mem_data->OSNBlks    = pmem->OSMemNBlks;
  349.     p_mem_data->OSNFree    = pmem->OSMemNFree;
  350.     OS_EXIT_CRITICAL();
  351.     p_mem_data->OSNUsed    = p_mem_data->OSNBlks - p_mem_data->OSNFree;
  352.     return (OS_ERR_NONE);
  353. }
  354. #endif                                           /* OS_MEM_QUERY_EN                                    */
  355. /*$PAGE*/
  356. /*
  357. *********************************************************************************************************
  358. *                                    INITIALIZE MEMORY PARTITION MANAGER
  359. *
  360. * Description : This function is called by uC/OS-II to initialize the memory partition manager.  Your
  361. *               application MUST NOT call this function.
  362. *
  363. * Arguments   : none
  364. *
  365. * Returns     : none
  366. *
  367. * Note(s)    : This function is INTERNAL to uC/OS-II and your application should not call it.
  368. *********************************************************************************************************
  369. */
  370. void  OS_MemInit (void)
  371. {
  372. #if OS_MAX_MEM_PART == 1
  373.     OS_MemClr((INT8U *)&OSMemTbl[0], sizeof(OSMemTbl));   /* Clear the memory partition table          */
  374.     OSMemFreeList               = (OS_MEM *)&OSMemTbl[0]; /* Point to beginning of free list           */
  375. #if OS_MEM_NAME_SIZE > 1
  376.     OSMemFreeList->OSMemName[0] = '?';                    /* Unknown name                              */
  377.     OSMemFreeList->OSMemName[1] = OS_ASCII_NUL;
  378. #endif
  379. #endif
  380. #if OS_MAX_MEM_PART >= 2
  381.     OS_MEM  *pmem;
  382.     INT16U   i;
  383.     OS_MemClr((INT8U *)&OSMemTbl[0], sizeof(OSMemTbl));   /* Clear the memory partition table          */
  384.     pmem = &OSMemTbl[0];                                  /* Point to memory control block (MCB)       */
  385.     for (i = 0; i < (OS_MAX_MEM_PART - 1); i++) {         /* Init. list of free memory partitions      */
  386.         pmem->OSMemFreeList = (void *)&OSMemTbl[i+1];     /* Chain list of free partitions             */
  387. #if OS_MEM_NAME_SIZE > 1
  388.         pmem->OSMemName[0]  = '?';                        /* Unknown name                              */
  389.         pmem->OSMemName[1]  = OS_ASCII_NUL;
  390. #endif
  391.         pmem++;
  392.     }
  393.     pmem->OSMemFreeList = (void *)0;                      /* Initialize last node                      */
  394. #if OS_MEM_NAME_SIZE > 1
  395.     pmem->OSMemName[0]  = '?';                            /* Unknown name                              */
  396.     pmem->OSMemName[1]  = OS_ASCII_NUL;
  397. #endif
  398.     OSMemFreeList       = &OSMemTbl[0];                   /* Point to beginning of free list           */
  399. #endif
  400. }
  401. #endif                                                    /* OS_MEM_EN                                 */