Upload
primrose-cameron
View
216
Download
2
Embed Size (px)
Citation preview
Chapter 12Memory Management
• The dynamic memory allocation can be achieved by using malloc() and free() function
• Using malloc() and free(0 in an embedded real-time system is dangerous– Eventually may incur fragmentation – Execution time of malloc() and free(0) are nondeterministic
• uC/OS-II provides fixed-sized memory blocks from partition made of a contiguous memory
– Allocation and deallocation of these memory blocks is done in constant time and is deterministic
• Memory service: OSMemCreate(0, OSMemGet(), OSMemPut(), OSMemQuery()
Partition
Block
Start addressPartition #1 Partition #2 Partition #3 Partition #4
Figure 7.1 memory partition Figure 7.2 multiple memory partitions
Memory control block data structure
• The memory partitions is maintained by memory control block
typedef struct { void *OSMemAddr; //point to the beginning of memory block void *OSMemFreeList; //point to MCB or memory block INT32U OSMemBlkSize; INT32U OSMemNBlks; //total memory blocks INT32U OSMemNFree; //current available memory blocks} OS_MEM;
List of free memory control blocks
OSMemAddr
OSMemFreeList
OSMemBlkSize
OSMemNBlks
OSMemNFree
OSMemAddr
OSMemFreeList
OSMemBlkSize
OSMemNBlks
OSMemNFree
OSMemAddr
OSMemFreeList
OSMemBlkSize
OSMemNBlks
OSMemNFree
0OSMemFreeList
OS_MAX_MEM_PART
12.01 Creating a partition, OSMemCreate()
• Four arguments are required– Beginning address of the memory partition
– The number of blocks to be allocated from this partition
– The size (in bytes) of each block
– A pointer to a variable that contains an error code
OS_MEM *CommTxBuf;INT8U CommTxPart[100][32];void main (void){ INT8U err; OSInit(); . . CommTxBuf = OSMemCreate(CommTxPart, 100, 32, &err); . . OSStart();}
OS_MEM *OSMemCreate (void *addr, INT32U nblks, INT32U blksize, INT8U *err){ OS_MEM *pmem; INT8U *pblk; void **plink; INT32U i; if (nblks < 2) { //each memory partition must contain at least two memory blocks (1) *err = OS_MEM_INVALID_BLKS; return ((OS_MEM *)0); } if (blksize < sizeof(void *)) { //each memory block must be able to hold the size of a pointer (2) *err = OS_MEM_INVALID_SIZE; return ((OS_MEM *)0); } OS_ENTER_CRITICAL(); pmem = OSMemFreeList; //obtain a MCB (3) if (OSMemFreeList != (OS_MEM *)0) { OSMemFreeList = (OS_MEM *)OSMemFreeList->OSMemFreeList; } OS_EXIT_CRITICAL(); if (pmem == (OS_MEM *)0) { (4) *err = OS_MEM_INVALID_PART; return ((OS_MEM *)0); }
OSMemCrate(): return MCB address or 0
plink = (void **)addr; (5) pblk = (INT8U *)addr + blksize; for (i = 0; i < (nblks - 1); i++) { *plink = (void *)pblk; plink = (void **)pblk; pblk = pblk + blksize; } *plink = (void *)0; OS_ENTER_CRITICAL(); pmem->OSMemAddr = addr; (6) pmem->OSMemFreeList = addr; pmem->OSMemNFree = nblks; pmem->OSMemNBlks = nblks; pmem->OSMemBlkSize = blksize; OS_EXIT_CRITICAL(); *err = OS_NO_ERR; return (pmem); (7)}
Figure 12.4 The data structure after OSMemCreate() successful
0
OSMemAddr = addr
OSMemFreeList= addr
OSMemBlkSize = blksize
OSMemNBlks = nblks
OSMemNFree = nblks
Contiguous memory
pmem
OSMemCreate() arguments
12.02 Obtaining a Memory block, OSMemGet()
• The APs need to understand how size of memory block is required– Need to provide the associated pointer of memory control block
– When you are done using the block, you must return it to the proper memory partition
void *OSMemGet (OS_MEM *pmem, INT8U *err) (1){ void *pblk; OS_ENTER_CRITICAL(); if (pmem->OSMemNFree > 0) { (2) pblk = pmem->OSMemFreeList; (3) pmem->OSMemFreeList = *(void **)pblk; (4) pmem->OSMemNFree--; (5) OS_EXIT_CRITICAL(); *err = OS_NO_ERR; return (pblk); (6) } else { OS_EXIT_CRITICAL(); *err = OS_MEM_NO_FREE_BLKS; return ((void *)0); }}
Returning a Memory Block, OSMemPut()
• If you return a wrong memory partition, the system may be crash or waste memory space
INT8U OSMemPut (OS_MEM *pmem, void *pblk) (1){ OS_ENTER_CRITICAL(); if (pmem->OSMemNFree >= pmem->OSMemNBlks) { (2) OS_EXIT_CRITICAL(); return (OS_MEM_FULL); } *(void **)pblk = pmem->OSMemFreeList; (3) pmem->OSMemFreeList = pblk; pmem->OSMemNFree++; (4) OS_EXIT_CRITICAL(); return (OS_NO_ERR); }
Obtaining Status of a Memory Partition, OSMemQuery()
typedef struct { void *OSAddr; /* Points to beginning address of the memory partition */ void *OSFreeList; /* Points to beginning of the free list of memory blocks */ INT32U OSBlkSize; /* Size (in bytes) of each memory block */ INT32U OSNBlks; /* Total number of blocks in the partition */ INT32U OSNFree; /* Number of memory blocks free */ INT32U OSNUsed; /* Number of memory blocks used */} OS_MEM_DATA;
INT8U OSMemQuery (OS_MEM *pmem, OS_MEM_DATA *pdata){ OS_ENTER_CRITICAL(); pdata->OSAddr = pmem->OSMemAddr; (1) pdata->OSFreeList = pmem->OSMemFreeList; pdata->OSBlkSize = pmem->OSMemBlkSize; pdata->OSNBlks = pmem->OSMemNBlks; pdata->OSNFree = pmem->OSMemNFree; OS_EXIT_CRITICAL(); pdata->OSNUsed = pdata->OSNBlks - pdata->OSNFree; (2) return (OS_NO_ERR); }
Using Memory Partitions
ErrMsgPart
ErrMsgQ
ErrorHandler
AITask
0
OSMemGet() OSMemPut()
OSQPost() OSQPend()
OSTime
OSTimeGet()
(1)
AnalogInputs
(2)
(3)
(4)
(5) (6)
(7)
(8)
Scanning analog inputs and reporting errorsAnalogInputTask(){ for (;;) { for (all analog inputs to read) { Read analog input; (1) if (analog input exceed threshold) { Get memory block; (2) Get current system time (in clock ticks); (3) Store the following items in the memory block: (4) System time (i.e. a time stamp); The channel that exceeded the threshold; An error code; The severity of the error; Etc. Post the error message to error queue; (5) (A pointer to the memory block containing the data) } } Delay task until it’s time to sample analog inputs again; }}ErrorHandlerTask(){ for (;;) { Wait for message from error queue; (6) (Gets a pointer to a memory block containing information about the error reported) Read the message and take action based on error reported; (7) Return the memory block to the memory partition; (8) }}
Waiting for memory blocks from a partitionOS_EVENT *SemaphorePtr; (1)OS_MEM *PartitionPtr;INT8U Partition[100][32];OS_STK TaskStk[1000];void main (void){ INT8U err; OSInit(); (2) . . SemaphorePtr = OSSemCreate(100); (3) PartitionPtr = OSMemCreate(Partition, 100, 32, &err); (4) . OSTaskCreate(Task, (void *)0, &TaskStk[999], &err); (5) . OSStart(); (6)}void Task (void *pdata){ INT8U err; INT8U *pblock; for (;;) { OSSemPend(SemaphorePtr, 0, &err); (7) pblock = OSMemGet(PartitionPtr, &err); (8) . . /* Use the memory block */ . OSMemPut(PartitionPtr, pblock); (9) OSSemPost(SemaphorePtr); (10) }}