RTOS存储块
概述
不实现malloc等函数的原因:RTOS的使用场景中,内存是比较珍贵的资源
- 频繁的进行任意大小而定内存分配可能会产生很多不连续的细小的外部碎片,导致无法再次分配。
- 代码实现比较复杂,分配和释放过程操作时间不确定
** 是否真有需要分配做任意大小的存储空间? ** - 从程序的最底层往上到应用层,所有东西开发都是完全可见的。
- 针对特定场合开发,有时存储空间分配大小的种类通常只有少量几种。
** 若针对特定场合开发存储空间分配方式的缺点:**- 不论何时,各个存储块类型总是独立持有各空闲存储块,彼此无法共享
- 有时候还会存在少量的内部碎片(存储块内部),但是并非下次分配也无法利用
** 若针对特定场合开发存储空间分配方式的优点:**牺牲了一定存储空间换来了简单、快速、确定的分配方式。
原理
预先分配所需的大内存块(一个全局的数组),将大内存块划分为多个小内存块,然后用链表链接起来。当所有存储块都被分配完的时候,需要使用存储块的任务可以等待在存储块上。
实现
定义
1
2
3
4
5
6
7
typedef struct _memblock {
eventCtrlBlock_t event; // 事件控制块,如果暂时没有空间去分配就将任务阻塞在此
void* memStart; // 存储块的开始地址
uint32_t blockSize; // 每一个存储块的大小
uint32_t maxCount; // 存储块的数量
listHead blockList; // 连接各个存储块
}memBlock_t;
初始化, 一个绝妙的方法,将每一个存储块的首地址强制转换为链表的结构串起来,分配时把此结点移走,不浪费一点空间。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
uint32_t memBlockInit(memBlock_t* memBlock, void* memStart, uint32_t blockSize, uint32_t blockNum){
uint8_t* memBlockStart = (uint8_t*)memStart;
uint8_t* memBlockEnd = memBlockStart + blockSize * blockNum;
if (blockSize < sizeof(listNode)) {
return 1;
}
eventInit(&memBlock->event, EVENT_TYPE_MEMBLOCK);
memBlock->memStart = memStart;
memBlock->blockSize = blockSize;
memBlock->maxCount = blockNum;
listHeadInit(&memBlock->blockList);
while (memBlockStart < memBlockEnd) {
listNodeInit((listNode*)memBlockStart);
listNodeInsert2Tail(&memBlock->blockList, (listNode*)memBlockStart);
memBlockStart += blockSize;
}
return 0;
}
获取一个存储块:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
uint32_t memBlockWait(memBlock_t* memblock, void* mem, uint32_t waitTime) {
uint32_t st = enterCritical();
if (getListNodeNum(&memblock->blockList) > 0) {
*(void**)mem = listRemoveFirst(&memblock->blockList);
leaveCritical(st);
return NO_ERROR;
}
eventWait(&memblock->event, currentTask, NULL, TASK_STATUS_WAIT_MEMBLOCK, waitTime);
taskSched();
leaveCritical(st);
// 如果等到了存储块,存入task->eventMsg中
*(void**)mem = currentTask->eventMsg;
return currentTask->eventWaitResult;
}
获取存储块,如果没有存储块也不会等待在此
1
2
3
4
5
6
7
8
9
10
11
12
13
14
uint32_t memBlockGetWithNoWait(memBlock_t* memblock, void* mem) {
uint32_t st = enterCritical();
if (getListNodeNum(&memblock->blockList) > 0) {
*(void**)mem = listRemoveFirst(&memblock->blockList);
leaveCritical(st);
return NO_ERROR;
}
leaveCritical(st);
return ERROR_RESOURCE_UNAVAILABLE;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 归还一个存储块,如果有任务等待在此,则将此存储块直接交给其中一个任务,将此任务唤醒
// 如果唤醒的任务优先级大于当前任务,则进行任务切换
// 如果没有,则将其加入存储块队列
void memBlockPost(memBlock_t* memblock, void* mem) {
uint32_t st = enterCritical();
if(eventGetWaitNum(&memblock->event) > 0) {
task_t* task = eventWakeUp(&memblock->event, mem, NO_ERROR);
if (task->priority < currentTask->priority) {
taskSched();
}
leaveCritical(st);
return;
}
listNodeInsert2Tail(&memblock->blockList, (listNode*)mem);
leaveCritical(st);
}
删除存储块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 此函数是否需要返回值是值得考量的!
// eventRemoveAllTask本身是原子操作,那么本函数加锁还有没有意义?
uint32_t memBlockDestory(memBlock_t* memblock) {
uint32_t st = enterCritical();
uint32_t count = eventRemoveAllTask(&memblock->event, NULL, ERROR_DELETED);
if (count > 0) {
taskSched();
}
leaveCritical(st);
return count;
}
获取存储块的信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
memBlockInfo_t memBlockGetInfo(memBlock_t* memblock) {
memBlockInfo_t info;
uint32_t st = enterCritical();
info.blockSize = memblock->blockSize;
info.maxCount = memblock->maxCount;
info.memBlockNum = getListNodeNum(&memblock->blockList);
info.waitTaskNum = eventGetWaitNum(&memblock->event);
leaveCritical(st);
return info;
}
本文由作者按照 CC BY 4.0 进行授权