130 likes | 223 Views
Chapter 12 Memory 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
E N D
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() 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
12.01 Creating a partition, OSMemCreate() OS_MEM *CommTxBuf; INT8U CommTxPart[100][32]; void main (void) { INT8U err; OSInit(); . . CommTxBuf = OSMemCreate(CommTxPart, 100, 32, &err); . . OSStart(); } • 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 *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
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); }
Scanning analog inputs and reporting errors AnalogInputTask() { 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 partition OS_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) } }