1 /*
2 * Copyright (c) 2009-2022 Huawei Technologies Co., Ltd. All rights reserved.
3 *
4 * UniProton is licensed under Mulan PSL v2.
5 * You can use this software according to the terms and conditions of the Mulan PSL v2.
6 * You may obtain a copy of Mulan PSL v2 at:
7 * http://license.coscl.org.cn/MulanPSL2
8 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
9 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
10 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
11 * See the Mulan PSL v2 for more details.
12 * Create: 2009-12-22
13 * Description: 队列函数实现
14 */
15 #include "prt_queue_external.h"
16 #include "prt_task_external.h"
17 #include "prt_asm_cpu_external.h"
18
OsGetSrcPid(void)19 OS_SEC_ALW_INLINE INLINE U32 OsGetSrcPid(void)
20 {
21 U32 srcPid;
22
23 if (OS_HWI_ACTIVE) {
24 /* 硬中断创建消息不具体区别中断号 */
25 srcPid = COMPOSE_PID(OsGetHwThreadId(), OS_HWI_HANDLE);
26 } else {
27 srcPid = RUNNING_TASK->taskPid;
28 }
29
30 return srcPid;
31 }
32
33 /*
34 * 描述:内部Pend操作,这个函数在调用之前必须关中断。
35 */
OsInnerPend(U16 * count,struct TagListObject * pendList,U32 timeOut)36 OS_SEC_ALW_INLINE INLINE U32 OsInnerPend(U16 *count, struct TagListObject *pendList, U32 timeOut)
37 {
38 struct TagTskCb *runTsk = NULL;
39
40 /* 判断是否需要阻塞 */
41 if (*count > 0) {
42 (*count)--;
43 return OS_OK;
44 }
45
46 /* 阻塞任务 */
47 if (timeOut == OS_QUEUE_NO_WAIT) {
48 return OS_ERRNO_QUEUE_NO_SOURCE;
49 }
50
51 if (OS_INT_ACTIVE) {
52 return OS_ERRNO_QUEUE_IN_INTERRUPT;
53 }
54
55 /* 如果锁任务的情况下 */
56 if (OS_TASK_LOCK_DATA != 0) {
57 return OS_ERRNO_QUEUE_PEND_IN_LOCK;
58 }
59
60 /* 利用局部变量 runTsk 完成对任务控制块的相关操作,不修改 RUNNING_TASK */
61 runTsk = (struct TagTskCb *)RUNNING_TASK;
62
63 /* 从任务的Ready list上把当前任务删除,添加到pend list上 */
64 OsTskReadyDel(runTsk);
65
66 TSK_STATUS_SET(runTsk, OS_TSK_QUEUE_PEND);
67 ListTailAdd(&runTsk->pendList, pendList);
68
69 /* 如果timeOut > 0,timeOut为等待时间,如果timeOut == OS_QUEUE_WAIT_FOREVER,表示永久等待 */
70 if (timeOut != OS_QUEUE_WAIT_FOREVER) {
71 /* 如果不是永久等待则将任务挂到计时器链表中,设置OS_TSK_TIMEOUT是为了判断是否等待超时 */
72 TSK_STATUS_SET(runTsk, OS_TSK_TIMEOUT);
73 OsTskTimerAdd(runTsk, timeOut);
74 }
75
76 /* 调用函数之前已经关中断,此处关中断进行调度 */
77 /* 触发任务调度 */
78 OsTskSchedule();
79 TSK_STATUS_CLEAR(runTsk, OS_TSK_QUEUE_BUSY);
80
81 /* 判断是否是等待队列超时 */
82 if ((runTsk->taskStatus & OS_TSK_TIMEOUT) != 0) {
83 TSK_STATUS_CLEAR(runTsk, OS_TSK_TIMEOUT);
84
85 /* 在函数的外面会开中断 */
86 return OS_ERRNO_QUEUE_TIMEOUT;
87 }
88 /* 在函数的外面会开中断 */
89 return OS_OK;
90 }
91
OsQueuePendNeedProc(struct TagListObject * objectList)92 OS_SEC_ALW_INLINE INLINE bool OsQueuePendNeedProc(struct TagListObject *objectList)
93 {
94 struct TagTskCb *resumedTask = NULL;
95
96 /* 判断是否有任务阻塞于该队列 */
97 if (ListEmpty(objectList)) {
98 return FALSE;
99 }
100
101 /* 激活阻塞在该队列的首个任务 */
102 resumedTask = GET_TCB_PEND(OS_LIST_FIRST(objectList));
103 ListDelete(OS_LIST_FIRST(objectList));
104
105 /* 去除该任务的队列阻塞位 */
106 TSK_STATUS_CLEAR(resumedTask, OS_TSK_QUEUE_PEND);
107 /* 如果阻塞的任务属于定时等待的任务时候,去掉其定时等待标志位,并将其从去除 */
108 if ((resumedTask->taskStatus & OS_TSK_TIMEOUT) != 0) {
109 /*
110 * 添加PEND状态时,会加上TIMEOUT标志和timer,或者都不加。
111 * 所以此时有TIMEOUT标志就一定有timer,且只有一个,且只用于该PEND方式
112 */
113 OS_TSK_DELAY_LOCKED_DETACH(resumedTask);
114 TSK_STATUS_CLEAR(resumedTask, OS_TSK_TIMEOUT);
115 }
116
117 TSK_STATUS_SET(resumedTask, OS_TSK_QUEUE_BUSY);
118
119 /* 如果去除队列阻塞位后,该任务不处于挂起态则将该任务挂入就绪队列并触发任务调度 */
120 if ((resumedTask->taskStatus & OS_TSK_SUSPEND) == 0) {
121 OsTskReadyAddBgd(resumedTask);
122 }
123 return TRUE;
124 }
125
126 /*
127 * 描述:读指定队列
128 */
PRT_QueueRead(U32 queueId,void * bufferAddr,U32 * len,U32 timeOut)129 OS_SEC_L4_TEXT U32 PRT_QueueRead(U32 queueId, void *bufferAddr, U32 *len, U32 timeOut)
130 {
131 uintptr_t intSave;
132 U32 ret;
133 U32 bufLen;
134 U32 innerId = OS_QUEUE_INNER_ID(queueId);
135 struct TagQueCb *queueCb = NULL;
136 struct QueNode *queueNode = NULL;
137
138 if (innerId >= g_maxQueue) {
139 return OS_ERRNO_QUEUE_INVALID;
140 }
141
142 if ((bufferAddr == NULL) || (len == NULL)) {
143 return OS_ERRNO_QUEUE_PTR_NULL;
144 }
145
146 if (*len == 0) {
147 return OS_ERRNO_QUEUE_SIZE_ZERO;
148 }
149
150 bufLen = *len;
151 /* 获取指定队列控制块 */
152 queueCb = (struct TagQueCb *)GET_QUEUE_HANDLE(innerId);
153
154 intSave = OsIntLock();
155 if (queueCb->queueState == OS_QUEUE_UNUSED) {
156 ret = OS_ERRNO_QUEUE_NOT_CREATE;
157 goto QUEUE_END;
158 }
159
160 /* 读队列PEND */
161 ret = OsInnerPend(&queueCb->readableCnt, &queueCb->readList, timeOut);
162 if (ret != OS_OK) {
163 goto QUEUE_END;
164 }
165
166 /* 获取该队列中第一个有数据结点首地址,并将数据存入buffer中 */
167 queueNode = (struct QueNode *)(uintptr_t)&queueCb->queue[(queueCb->queueHead) * (queueCb->nodeSize)];
168
169 /* 如果buf的长度小于数据长度,则仅返回buf大小的数据,如果大于,则返回全部数据 */
170 if (*len > queueNode->size) {
171 *len = queueNode->size;
172 }
173
174 if (memcpy_s(bufferAddr, bufLen, (void *)queueNode->buf, *len) != EOK) {
175 OS_GOTO_SYS_ERROR1();
176 }
177
178 queueNode->srcPid = OS_QUEUE_PID_INVALID;
179
180 /* 队列头指针加1 */
181 queueCb->queueHead++;
182 /* 如果队列头指针已经到队列尾,那么头指针指向队列头 */
183 if (queueCb->queueHead == queueCb->nodeNum) {
184 queueCb->queueHead = 0;
185 }
186
187 if (OsQueuePendNeedProc(&queueCb->writeList)) {
188 OsTskSchedule();
189 OsIntRestore(intSave);
190 return OS_OK;
191 }
192
193 queueCb->writableCnt++;
194
195 QUEUE_END:
196 OsIntRestore(intSave);
197 return ret;
198 }
199
OsQueueWriteParaCheck(U32 innerId,uintptr_t bufferAddr,U32 bufferSize,U32 prio)200 OS_SEC_L4_TEXT U32 OsQueueWriteParaCheck(U32 innerId, uintptr_t bufferAddr, U32 bufferSize, U32 prio)
201 {
202 if (innerId >= g_maxQueue) {
203 return OS_ERRNO_QUEUE_INVALID;
204 }
205
206 if (bufferAddr == 0) {
207 return OS_ERRNO_QUEUE_PTR_NULL;
208 }
209
210 if (bufferSize == 0) {
211 return OS_ERRNO_QUEUE_SIZE_ZERO;
212 }
213
214 if (prio > (U32)OS_QUEUE_URGENT) {
215 return OS_ERRNO_QUEUE_PRIO_INVALID;
216 }
217
218 return OS_OK;
219 }
220
OsQueueCpData2Node(U32 prio,uintptr_t bufferAddr,U32 bufferSize,struct TagQueCb * queueCb)221 OS_SEC_ALW_INLINE INLINE void OsQueueCpData2Node(U32 prio, uintptr_t bufferAddr, U32 bufferSize,
222 struct TagQueCb *queueCb)
223 {
224 U16 peak;
225 struct QueNode *queueNode = NULL;
226 if (prio == (U32)OS_QUEUE_NORMAL) {
227 /* 普通消息加到队列尾部 */
228 queueNode = (struct QueNode *)(uintptr_t)&queueCb->queue[((queueCb->queueTail) * (queueCb->nodeSize))];
229
230 queueCb->queueTail++;
231 if (queueCb->queueTail == queueCb->nodeNum) {
232 queueCb->queueTail = 0;
233 }
234 } else {
235 /* 紧急消息加到队列头上 */
236 if (queueCb->queueHead == 0) {
237 queueCb->queueHead = queueCb->nodeNum;
238 }
239 queueCb->queueHead--;
240
241 queueNode = (struct QueNode *)(uintptr_t)&queueCb->queue[((queueCb->queueHead) * (queueCb->nodeSize))];
242 }
243
244 if (memcpy_s((void *)queueNode->buf, (queueCb->nodeSize - OS_QUEUE_NODE_HEAD_LEN),
245 (void *)bufferAddr, bufferSize) != EOK) {
246 OS_GOTO_SYS_ERROR1();
247 }
248
249 queueNode->size = (U16)bufferSize;
250 queueNode->srcPid = (U16)OsGetSrcPid();
251
252 peak = queueCb->queueTail > queueCb->queueHead ? queueCb->queueTail - queueCb->queueHead
253 : (queueCb->nodeNum - queueCb->queueHead) + queueCb->queueTail;
254
255 if (peak > queueCb->nodePeak) {
256 queueCb->nodePeak = peak;
257 }
258 }
259
260 /*
261 * 描述:写指定队列
262 */
PRT_QueueWrite(U32 queueId,void * bufferAddr,U32 bufferSize,U32 timeOut,U32 prio)263 OS_SEC_L4_TEXT U32 PRT_QueueWrite(U32 queueId, void *bufferAddr, U32 bufferSize, U32 timeOut, U32 prio)
264 {
265 U32 ret;
266 uintptr_t intSave;
267 U32 innerId = OS_QUEUE_INNER_ID(queueId);
268 struct TagQueCb *queueCb = NULL;
269
270 ret = OsQueueWriteParaCheck(innerId, (uintptr_t)bufferAddr, bufferSize, prio);
271 if (ret != OS_OK) {
272 return ret;
273 }
274
275 /* 获取指定队列控制块 */
276 queueCb = (struct TagQueCb *)GET_QUEUE_HANDLE(innerId);
277 intSave = OsIntLock();
278 if (queueCb->queueState == OS_QUEUE_UNUSED) {
279 ret = OS_ERRNO_QUEUE_NOT_CREATE;
280 goto QUEUE_END;
281 }
282
283 if (bufferSize > (queueCb->nodeSize - OS_QUEUE_NODE_HEAD_LEN)) {
284 ret = OS_ERRNO_QUEUE_SIZE_TOO_BIG;
285 goto QUEUE_END;
286 }
287
288 /* 读队列PEND */
289 ret = OsInnerPend(&queueCb->writableCnt, &queueCb->writeList, timeOut);
290 if (ret != OS_OK) {
291 goto QUEUE_END;
292 }
293
294 /* 选取消息节点,初始化消息节点拷贝数据 */
295 OsQueueCpData2Node(prio, (uintptr_t)bufferAddr, bufferSize, queueCb);
296
297 if (OsQueuePendNeedProc(&queueCb->readList)) {
298 OsTskSchedule();
299 OsIntRestore(intSave);
300 return OS_OK;
301 }
302
303 queueCb->readableCnt++;
304
305 QUEUE_END:
306 OsIntRestore(intSave);
307 return ret;
308 }
309