RTOS事件控制块
事件控制块
它一般作为信号量、消息队列、事件标志等功能的基础。
功能
- 任务在事件控制块上等待,暂停运行
- 事件发生,通知事件控制块
- 时间控制块通知等待任务列表中的任务
- 被通知的任务脱离事件控制块,继续运行
解决的问题
- 实现任务间的同步
- 解决多任务共享资源的冲突问题
- 实现多任务间的消息传递
- 在中断ISR与任务之间传递多个事件标志
实现原理
事件控制块的两大核心功能:
- 任务进入事件控制块等待:任务进入事件控制块等待队列中暂停运行
- 发送事件通知给控制块恢复任务执行:事件发送通知时任务从队列移除继续运行
代码定义
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
typedef enum _eventType {
eventTypeUnknown,
}eventType_t;
// 事件控制块的定义
typedef struct _eventCtrlBlock_t {
eventType_t type;
listHead waitlist;
}eventCtrlBlock_t;
typedef enum _error {
NO_ERROR = 0,
ERROR_TIMEOUT = 1,
}rt_error;
// 定义任务结构
typedef struct _t_Task {
.........
struct _eventCtrlBlock_t* waitEvent; // 等待的事件控制块
void* eventMsg; // 事件信息
uint32_t eventWaitResult; // 事件的等待结果
}task_t;
添加对任务结构中事件相关字段的初始化相关代码
1
2
3
4
5
6
7
8
// 任务初始化
void taskInit (task_t* task, void (*entry)(void*), void* param, taskStack_t* stack, uint32_t priority) {
...........
task->waitEvent = NULL;
task->eventMsg = NULL;
task->eventWaitResult = NO_ERROR;
...........
}
事件控制块的核心功能函数编写:事件等待、唤醒、移除等
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
void eventInit(eventCtrlBlock_t* ecb, eventType_t type){
ecb->type = eventTypeUnknown;
listHeadInit(&ecb->waitlist);
}
// 将任务阻塞在事件控制块上
// 此函数要求被操作的任务必须处于就绪态或运行态
// 此函数是否要加临界区保护待决定
void eventWait(eventCtrlBlock_t* event, task_t* task, void* msg, uint32_t state, uint32_t timeout) {
uint32_t st = enterCritical();
task->state |= state;
task->waitEvent = event;
task->eventMsg = msg;
task->eventWaitResult = NO_ERROR;
taskSched2Unready(task);
listNodeInsert2Tail(&event->waitlist, &task->linkNode);
if (timeout) {
taskSched2Delay(task, timeout);
}
leaveCritical(st);
}
// HIGH_RT_MODE有可能导致死锁,需要注意
task_t* eventWakeUp(eventCtrlBlock_t* event, void* msg, uint32_t result) {
task_t* task = NULL;
uint32_t st = enterCritical();
#ifdef HIGH_RT_MODE
uint32_t flag = RTOS_PRIORITY_COUNT;
for (listNode* node = event->waitlist.firstNode; node != &event->waitlist.headNode; node = node->next) {
task_t* temptask = getListNodeParent(node, task_t, linkNode);
if (temptask->priority < flag) {
flag = temptask->priority;
task = temptask;
}
}
if (task) {
listRemove(&event->waitlist, &task->linkNode);
}
#else
listNode* node = NULL;
if ((node = listRemoveFirst(&event->waitlist)) != NULL) {
task = getListNodeParent(node, task_t, linkNode);
}
#endif
if (task == NULL) {
leaveCritical(st);
return NULL;
}
task->waitEvent = NULL;
task->eventMsg = msg;
task->eventWaitResult = result;
task->state &= ~TASK_STATUS_WAIT_MASK;
if (task->state & TASK_STATUS_DELAY) {
taskSched2Undelay(task);
}
taskSched2Ready(task);
leaveCritical(st);
return task;
}
// 这里不加锁也行,因为调用它的一定是加锁的函数
// 把任务从事件控制块中拿走,但是没有将该任务从延时队列中放出来
void eventRemoveTask(task_t* task, void* msg, uint32_t result) {
uint32_t st = enterCritical();
listRemove(&task->waitEvent->waitlist , &task->linkNode);
task->waitEvent = NULL;
task->eventMsg = msg;
task->eventWaitResult = result;
task->state &= ~TASK_STATUS_WAIT_MASK;
leaveCritical(st);
}
uint32_t eventRemoveAllTask(eventCtrlBlock_t* event, void* msg, uint32_t result) {
uint32_t st = enterCritical();
uint32_t count = getListNodeNum(&event->waitlist);
for (listNode* node = event->waitlist.firstNode; node != &event->waitlist.headNode;) {
task_t* task = getListNodeParent(node, task_t, linkNode);
node = node->next;
eventRemoveTask(task, msg, result);
if (task->state & TASK_STATUS_DELAY) {
taskSched2Undelay(task);
}
taskSched2Ready(task);
}
leaveCritical(st);
return count;
}
// 这里需不需要加锁,还需考量
uint32_t eventGetWaitNum(eventCtrlBlock_t* event) {
uint32_t count = 0;
uint32_t st = enterCritical();
count = getListNodeNum(&event->waitlist);
leaveCritical(st);
return count;
}
本文由作者按照 CC BY 4.0 进行授权