更新日期: 2022/06/01 来源: https://gitee.com/weharmony/kernel_liteos_a_note
los_mux.c
浏览该文件的文档.
1/*!
2 * @file los_mux.c
3 * @brief
4 * @link kernel-mini-basic-ipc-mutex-guide http://weharmonyos.com/openharmony/zh-cn/device-dev/kernel/kernel-mini-basic-ipc-mutex-guide.html @endlink
5 @verbatim
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 通过make menuconfig配置互斥锁模块。
39 创建互斥锁LOS_MuxCreate。
40 申请互斥锁LOS_MuxPend。
41 释放互斥锁LOS_MuxPost。
42 删除互斥锁LOS_MuxDelete。
43
44 @endverbatim
45 * @image html https://gitee.com/weharmonyos/resources/raw/master/27/mux.png
46 * @attention 两个任务不能对同一把互斥锁加锁。如果某任务对已被持有的互斥锁加锁,则该任务会被挂起,直到持有该锁的任务对互斥锁解锁,才能执行对这把互斥锁的加锁操作。
47 \n 互斥锁不能在中断服务程序中使用。
48 \n LiteOS-M内核作为实时操作系统需要保证任务调度的实时性,尽量避免任务的长时间阻塞,因此在获得互斥锁之后,应该尽快释放互斥锁。
49 \n 持有互斥锁的过程中,不得再调用LOS_TaskPriSet等接口更改持有互斥锁任务的优先级。
50 * @version
51 * @author weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
52 * @date 2021-11-18
53 */
54/*
55 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
56 * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
57 *
58 * Redistribution and use in source and binary forms, with or without modification,
59 * are permitted provided that the following conditions are met:
60 *
61 * 1. Redistributions of source code must retain the above copyright notice, this list of
62 * conditions and the following disclaimer.
63 *
64 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
65 * of conditions and the following disclaimer in the documentation and/or other materials
66 * provided with the distribution.
67 *
68 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
69 * to endorse or promote products derived from this software without specific prior written
70 * permission.
71 *
72 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
73 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
74 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
75 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
76 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
77 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
78 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
79 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
80 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
81 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
82 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
83 */
84
85#include "los_mux_pri.h"
86#include "los_bitmap.h"
87#include "los_spinlock.h"
88#include "los_mp.h"
89#include "los_task_pri.h"
90#include "los_exc.h"
91#include "los_sched_pri.h"
92
93
94#ifdef LOSCFG_BASE_IPC_MUX
95#define MUTEXATTR_TYPE_MASK 0x0FU
96///互斥属性初始化
97LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrInit(LosMuxAttr *attr)
98{
99 if (attr == NULL) {
100 return LOS_EINVAL;
101 }
102
103 attr->protocol = LOS_MUX_PRIO_INHERIT; //协议默认用继承方式, A(4)task等B(19)释放锁时,B的调度优先级直接升到(4)
104 attr->prioceiling = OS_TASK_PRIORITY_LOWEST;//最低优先级
105 attr->type = LOS_MUX_DEFAULT; //默认 LOS_MUX_RECURSIVE
106 return LOS_OK;
107}
108/// ????? 销毁互斥属 ,这里啥也没干呀
109LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrDestroy(LosMuxAttr *attr)
110{
111 if (attr == NULL) {
112 return LOS_EINVAL;
113 }
114
115 return LOS_OK;
116}
117///获取互斥锁的类型属性,由outType接走,不送!
118LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrGetType(const LosMuxAttr *attr, INT32 *outType)
119{
120 INT32 type;
121
122 if ((attr == NULL) || (outType == NULL)) {
123 return LOS_EINVAL;
124 }
125
126 type = (INT32)(attr->type & MUTEXATTR_TYPE_MASK);
127 if ((type < LOS_MUX_NORMAL) || (type > LOS_MUX_ERRORCHECK)) {
128 return LOS_EINVAL;
129 }
130
131 *outType = type;
132
133 return LOS_OK;
134}
135///设置互斥锁的类型属性
136LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrSetType(LosMuxAttr *attr, INT32 type)
137{
138 if ((attr == NULL) || (type < LOS_MUX_NORMAL) || (type > LOS_MUX_ERRORCHECK)) {
139 return LOS_EINVAL;
140 }
141
142 attr->type = (UINT8)((attr->type & ~MUTEXATTR_TYPE_MASK) | (UINT32)type);
143 return LOS_OK;
144}
145///获取互斥锁的类型属性
146LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrGetProtocol(const LosMuxAttr *attr, INT32 *protocol)
147{
148 if ((attr != NULL) && (protocol != NULL)) {
149 *protocol = attr->protocol;
150 } else {
151 return LOS_EINVAL;
152 }
153
154 return LOS_OK;
155}
156///设置互斥锁属性的协议
157LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrSetProtocol(LosMuxAttr *attr, INT32 protocol)
158{
159 if (attr == NULL) {
160 return LOS_EINVAL;
161 }
162
163 switch (protocol) {
167 attr->protocol = (UINT8)protocol;
168 return LOS_OK;
169 default:
170 return LOS_EINVAL;
171 }
172}
173///获取互斥锁属性优先级
174LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrGetPrioceiling(const LosMuxAttr *attr, INT32 *prioceiling)
175{
176 if (attr == NULL) {
177 return LOS_EINVAL;
178 }
179
180 if (prioceiling != NULL) {
181 *prioceiling = attr->prioceiling;
182 }
183
184 return LOS_OK;
185}
186///设置互斥锁属性的优先级的上限
187LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrSetPrioceiling(LosMuxAttr *attr, INT32 prioceiling)
188{
189 if ((attr == NULL) ||
190 (prioceiling < OS_TASK_PRIORITY_HIGHEST) ||
191 (prioceiling > OS_TASK_PRIORITY_LOWEST)) {
192 return LOS_EINVAL;
193 }
194
195 attr->prioceiling = (UINT8)prioceiling;
196
197 return LOS_OK;
198}
199///设置互斥锁的优先级的上限,老优先级由oldPrioceiling带走
200LITE_OS_SEC_TEXT UINT32 LOS_MuxSetPrioceiling(LosMux *mutex, INT32 prioceiling, INT32 *oldPrioceiling)
201{
202 INT32 ret;
203 INT32 retLock;
204 if ((mutex == NULL) ||
205 (prioceiling < OS_TASK_PRIORITY_HIGHEST) ||
206 (prioceiling > OS_TASK_PRIORITY_LOWEST)) {
207 return LOS_EINVAL;
208 }
209
210 retLock = LOS_MuxLock(mutex, LOS_WAIT_FOREVER);
211 if (retLock != LOS_OK) {
212 return retLock;
213 }
214
215 if (oldPrioceiling != NULL) {
216 *oldPrioceiling = mutex->attr.prioceiling;
217 }
218
219 ret = LOS_MuxAttrSetPrioceiling(&mutex->attr, prioceiling);
220
221 retLock = LOS_MuxUnlock(mutex);
222 if ((ret == LOS_OK) && (retLock != LOS_OK)) {
223 return retLock;
224 }
225
226 return ret;
227}
228///获取互斥锁的优先级的上限
229LITE_OS_SEC_TEXT UINT32 LOS_MuxGetPrioceiling(const LosMux *mutex, INT32 *prioceiling)
230{
231 if ((mutex != NULL) && (prioceiling != NULL) && (mutex->magic == OS_MUX_MAGIC)) {
232 *prioceiling = mutex->attr.prioceiling;
233 return LOS_OK;
234 }
235
236 return LOS_EINVAL;
237}
238///互斥锁是否有效
239LITE_OS_SEC_TEXT BOOL LOS_MuxIsValid(const LosMux *mutex)
240{
241 if ((mutex != NULL) && (mutex->magic == OS_MUX_MAGIC)) {
242 return TRUE;
243 }
244
245 return FALSE;
246}
247///检查互斥锁属性是否OK,否则 no ok :|)
249{
250 if (((INT8)(attr->type) < LOS_MUX_NORMAL) || (attr->type > LOS_MUX_ERRORCHECK)) {
251 return LOS_NOK;
252 }
253 if (((INT8)(attr->prioceiling) < OS_TASK_PRIORITY_HIGHEST) || (attr->prioceiling > OS_TASK_PRIORITY_LOWEST)) {
254 return LOS_NOK;
255 }
256 if (((INT8)(attr->protocol) < LOS_MUX_PRIO_NONE) || (attr->protocol > LOS_MUX_PRIO_PROTECT)) {
257 return LOS_NOK;
258 }
259 return LOS_OK;
260}
261/// 初始化互斥锁
262LITE_OS_SEC_TEXT UINT32 LOS_MuxInit(LosMux *mutex, const LosMuxAttr *attr)
263{
264 UINT32 intSave;
265
266 if (mutex == NULL) {
267 return LOS_EINVAL;
268 }
269
270 if (attr == NULL) {
271 (VOID)LOS_MuxAttrInit(&mutex->attr);//属性初始化
272 } else {
273 (VOID)memcpy_s(&mutex->attr, sizeof(LosMuxAttr), attr, sizeof(LosMuxAttr));//把attr 拷贝到 mutex->attr
274 }
275
276 if (OsCheckMutexAttr(&mutex->attr) != LOS_OK) {//检查属性
277 return LOS_EINVAL;
278 }
279
280 SCHEDULER_LOCK(intSave); //拿到调度自旋锁
281 mutex->muxCount = 0; //锁定互斥量的次数
282 mutex->owner = NULL; //谁持有该锁
283 LOS_ListInit(&mutex->muxList); //互斥量双循环链表
284 mutex->magic = OS_MUX_MAGIC; //固定标识,互斥锁的魔法数字
285 SCHEDULER_UNLOCK(intSave); //释放调度自旋锁
286 return LOS_OK;
287}
288///销毁互斥锁
289LITE_OS_SEC_TEXT UINT32 LOS_MuxDestroy(LosMux *mutex)
290{
291 UINT32 intSave;
292
293 if (mutex == NULL) {
294 return LOS_EINVAL;
295 }
296
297 SCHEDULER_LOCK(intSave); //保存调度自旋锁
298 if (mutex->magic != OS_MUX_MAGIC) {
299 SCHEDULER_UNLOCK(intSave);//释放调度自旋锁
300 return LOS_EBADF;
301 }
302
303 if (mutex->muxCount != 0) {
304 SCHEDULER_UNLOCK(intSave);//释放调度自旋锁
305 return LOS_EBUSY;
306 }
307
308 (VOID)memset_s(mutex, sizeof(LosMux), 0, sizeof(LosMux));//很简单,全部清0处理.
309 SCHEDULER_UNLOCK(intSave); //释放调度自旋锁
310 return LOS_OK;
311}
312///设置互斥锁位图
313STATIC VOID OsMuxBitmapSet(const LosMux *mutex, const LosTaskCB *runTask)
314{
315 if (mutex->attr.protocol != LOS_MUX_PRIO_INHERIT) {
316 return;
317 }
318
319 SchedParam param = { 0 };
320 LosTaskCB *owner = (LosTaskCB *)mutex->owner;
321 INT32 ret = OsSchedParamCompare(owner, runTask);
322 if (ret > 0) {
323 runTask->ops->schedParamGet(runTask, &param);
324 owner->ops->priorityInheritance(owner, &param);
325 }
326}
327///恢复互斥锁位图
328VOID OsMuxBitmapRestore(const LosMux *mutex, const LOS_DL_LIST *list, const LosTaskCB *runTask)
329{
330 if (mutex->attr.protocol != LOS_MUX_PRIO_INHERIT) {
331 return;
332 }
333
334 SchedParam param = { 0 };
335 LosTaskCB *owner = (LosTaskCB *)mutex->owner;
336 runTask->ops->schedParamGet(runTask, &param);
337 owner->ops->priorityRestore(owner, list, &param);
338}
339
340/// 最坏情况就是拿锁失败,让出CPU,变成阻塞任务,等别的任务释放锁后排到自己了接着执行.
341STATIC UINT32 OsMuxPendOp(LosTaskCB *runTask, LosMux *mutex, UINT32 timeout)
342{
343 UINT32 ret;
344
345 if ((mutex->muxList.pstPrev == NULL) || (mutex->muxList.pstNext == NULL)) {//列表为空时的处理
346 /* This is for mutex macro initialization. */
347 mutex->muxCount = 0;//锁计数器清0
348 mutex->owner = NULL;//锁没有归属任务
349 LOS_ListInit(&mutex->muxList);//初始化锁的任务链表,后续申请这把锁任务都会挂上去
350 }
351
352 if (mutex->muxCount == 0) {//无task用锁时,肯定能拿到锁了.在里面返回
353 mutex->muxCount++; //互斥锁计数器加1
354 mutex->owner = (VOID *)runTask; //当前任务拿到锁
355 LOS_ListTailInsert(&runTask->lockList, &mutex->holdList);
356 if (mutex->attr.protocol == LOS_MUX_PRIO_PROTECT) {
357 SchedParam param = { 0 };
358 runTask->ops->schedParamGet(runTask, &param);
359 param.priority = mutex->attr.prioceiling;
360 runTask->ops->priorityInheritance(runTask, &param);
361 }
362 return LOS_OK;
363 }
364 //递归锁muxCount>0 如果是递归锁就要处理两种情况 1.runtask持有锁 2.锁被别的任务拿走了
365 if (((LosTaskCB *)mutex->owner == runTask) && (mutex->attr.type == LOS_MUX_RECURSIVE)) {//第一种情况 runtask是锁持有方
366 mutex->muxCount++; //递归锁计数器加1,递归锁的目的是防止死锁,鸿蒙默认用的就是递归锁(LOS_MUX_DEFAULT = LOS_MUX_RECURSIVE)
367 return LOS_OK; //成功退出
368 }
369 //到了这里说明锁在别的任务那里,当前任务只能被阻塞了.
370 if (!timeout) {//参数timeout表示等待多久再来拿锁
371 return LOS_EINVAL;//timeout = 0表示不等了,没拿到锁就返回不纠结,返回错误.见于LOS_MuxTrylock
372 }
373 //自己要被阻塞,只能申请调度,让出CPU core 让别的任务上
374 if (!OsPreemptableInSched()) {//不能申请调度 (不能调度的原因是因为没有持有调度任务自旋锁)
375 return LOS_EDEADLK;//返回错误,自旋锁被别的CPU core 持有
376 }
377
378 OsMuxBitmapSet(mutex, runTask);//设置锁位图,尽可能的提高锁持有任务的优先级
379
380 runTask->taskMux = (VOID *)mutex; //记下当前任务在等待这把锁
381 LOS_DL_LIST *node = OsSchedLockPendFindPos(runTask, &mutex->muxList);
382 if (node == NULL) {
383 ret = LOS_NOK;
384 return ret;
385 }
386
387 OsTaskWaitSetPendMask(OS_TASK_WAIT_MUTEX, (UINTPTR)mutex, timeout);
388 ret = runTask->ops->wait(runTask, node, timeout);
389 if (ret == LOS_ERRNO_TSK_TIMEOUT) {//这行代码虽和OsTaskWait挨在一起,但要过很久才会执行到,因为在OsTaskWait中CPU切换了任务上下文
390 OsMuxBitmapRestore(mutex, NULL, runTask);
391 runTask->taskMux = NULL;// 所以重新回到这里时可能已经超时了
392 ret = LOS_ETIMEDOUT;//返回超时
393 }
394
395 return ret;
396}
397
399{
400 LosTaskCB *runTask = OsCurrTaskGet();//获取当前任务
401
402 if (mutex->magic != OS_MUX_MAGIC) {
403 return LOS_EBADF;
404 }
405
406 if (OsCheckMutexAttr(&mutex->attr) != LOS_OK) {
407 return LOS_EINVAL;
408 }
409 //LOS_MUX_ERRORCHECK 时 muxCount是要等于0 ,当前任务持有锁就不能再lock了. 鸿蒙默认用的是递归锁LOS_MUX_RECURSIVE
410 if ((mutex->attr.type == LOS_MUX_ERRORCHECK) && (mutex->owner == (VOID *)runTask)) {
411 return LOS_EDEADLK;
412 }
413
414 return OsMuxPendOp(runTask, mutex, timeout);
415}
416/// 尝试加锁,
418{
419 LosTaskCB *runTask = OsCurrTaskGet();//获取当前任务
420
421 if (mutex->magic != OS_MUX_MAGIC) {//检查MAGIC有没有被改变
422 return LOS_EBADF;
423 }
424
425 if (OsCheckMutexAttr(&mutex->attr) != LOS_OK) {//检查互斥锁属性
426 return LOS_EINVAL;
427 }
428
429 if ((mutex->owner != NULL) &&
430 (((LosTaskCB *)mutex->owner != runTask) || (mutex->attr.type != LOS_MUX_RECURSIVE))) {
431 return LOS_EBUSY;
432 }
433
434 return OsMuxPendOp(runTask, mutex, timeout);//当前任务去拿锁,拿不到就等timeout
435}
436/// 拿互斥锁,
437LITE_OS_SEC_TEXT UINT32 LOS_MuxLock(LosMux *mutex, UINT32 timeout)
438{
439 LosTaskCB *runTask = NULL;
440 UINT32 intSave;
441 UINT32 ret;
442
443 if (mutex == NULL) {
444 return LOS_EINVAL;
445 }
446
447 if (OS_INT_ACTIVE) {
448 return LOS_EINTR;
449 }
450
451 runTask = (LosTaskCB *)OsCurrTaskGet();//获取当前任务
452 /* DO NOT Call blocking API in system tasks */
453 if (runTask->taskStatus & OS_TASK_FLAG_SYSTEM_TASK) {//不要在内核任务里用mux锁
454 PRINTK("Warning: DO NOT call %s in system tasks.\n", __FUNCTION__);
455 OsBackTrace();//打印task信息
456 }
457
458 SCHEDULER_LOCK(intSave);//调度自旋锁
459 ret = OsMuxLockUnsafe(mutex, timeout);//如果任务没拿到锁,将进入阻塞队列一直等待,直到timeout或者持锁任务释放锁时唤醒它
460 SCHEDULER_UNLOCK(intSave);
461 return ret;
462}
463///尝试要锁,没拿到也不等,直接返回,不纠结
464LITE_OS_SEC_TEXT UINT32 LOS_MuxTrylock(LosMux *mutex)
465{
466 LosTaskCB *runTask = NULL;
467 UINT32 intSave;
468 UINT32 ret;
469
470 if (mutex == NULL) {
471 return LOS_EINVAL;
472 }
473
474 if (OS_INT_ACTIVE) {
475 return LOS_EINTR;
476 }
477
478 runTask = (LosTaskCB *)OsCurrTaskGet();//获取当前执行的任务
479 /* DO NOT Call blocking API in system tasks */
480 if (runTask->taskStatus & OS_TASK_FLAG_SYSTEM_TASK) {//系统任务不能
481 PRINTK("Warning: DO NOT call %s in system tasks.\n", __FUNCTION__);
482 OsBackTrace();
483 }
484
485 SCHEDULER_LOCK(intSave);
486 ret = OsMuxTrylockUnsafe(mutex, 0);//timeout = 0,不等待,没拿到锁就算了
487 SCHEDULER_UNLOCK(intSave);
488 return ret;
489}
490
491/*!
492 * @brief OsMuxPostOp
493 * 是否有其他任务持有互斥锁而处于阻塞状,如果是就要唤醒它,注意唤醒一个任务的操作是由别的任务完成的
494 * OsMuxPostOp只由OsMuxUnlockUnsafe,参数任务归还锁了,自然就会遇到锁要给谁用的问题, 因为很多任务在申请锁,由OsMuxPostOp来回答这个问题
495 * @param mutex
496 * @param needSched
497 * @param taskCB
498 * @return
499 *
500 * @see
501 */
502STATIC UINT32 OsMuxPostOp(LosTaskCB *taskCB, LosMux *mutex, BOOL *needSched)
503{
504 if (LOS_ListEmpty(&mutex->muxList)) {//如果互斥锁列表为空
505 LOS_ListDelete(&mutex->holdList);//把持有互斥锁的节点摘掉
506 mutex->owner = NULL;
507 return LOS_OK;
508 }
509
510 LosTaskCB *resumedTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(mutex->muxList)));//拿到等待互斥锁链表的第一个任务实体,接下来要唤醒任务
511 OsMuxBitmapRestore(mutex, &mutex->muxList, resumedTask);
512
513 mutex->muxCount = 1;//互斥锁数量为1
514 mutex->owner = (VOID *)resumedTask;//互斥锁的持有人换了
515 LOS_ListDelete(&mutex->holdList);//自然要从等锁链表中把自己摘出去
516 LOS_ListTailInsert(&resumedTask->lockList, &mutex->holdList);//把锁挂到恢复任务的锁链表上,lockList是任务持有的所有锁记录
517 OsTaskWakeClearPendMask(resumedTask);
518 resumedTask->ops->wake(resumedTask);
519 resumedTask->taskMux = NULL;
520 if (needSched != NULL) {//如果不为空
521 *needSched = TRUE;//就走起再次调度流程
522 }
523
524 return LOS_OK;
525}
526
527UINT32 OsMuxUnlockUnsafe(LosTaskCB *taskCB, LosMux *mutex, BOOL *needSched)
528{
529 if (mutex->magic != OS_MUX_MAGIC) {
530 return LOS_EBADF;
531 }
532
533 if (OsCheckMutexAttr(&mutex->attr) != LOS_OK) {
534 return LOS_EINVAL;
535 }
536
537 if ((LosTaskCB *)mutex->owner != taskCB) {
538 return LOS_EPERM;
539 }
540
541 if (mutex->muxCount == 0) {
542 return LOS_EPERM;
543 }
544 //注意 --mutex->muxCount 先执行了-- 操作.
545 if ((--mutex->muxCount != 0) && (mutex->attr.type == LOS_MUX_RECURSIVE)) {//属性类型为LOS_MUX_RECURSIVE时,muxCount是可以不为0的
546 return LOS_OK;
547 }
548
549 if (mutex->attr.protocol == LOS_MUX_PRIO_PROTECT) {//属性协议为保护时
550 SchedParam param = { 0 };
551 taskCB->ops->schedParamGet(taskCB, &param);
552 taskCB->ops->priorityRestore(taskCB, NULL, &param);
553 }
554
555 /* Whether a task block the mutex lock. *///任务是否阻塞互斥锁
556 return OsMuxPostOp(taskCB, mutex, needSched);//一个任务去唤醒另一个在等锁的任务
557}
558///释放锁
559LITE_OS_SEC_TEXT UINT32 LOS_MuxUnlock(LosMux *mutex)
560{
561 LosTaskCB *runTask = NULL;
562 BOOL needSched = FALSE;
563 UINT32 intSave;
564 UINT32 ret;
565
566 if (mutex == NULL) {
567 return LOS_EINVAL;
568 }
569
570 if (OS_INT_ACTIVE) {
571 return LOS_EINTR;
572 }
573
574 runTask = (LosTaskCB *)OsCurrTaskGet();//获取当前任务
575 /* DO NOT Call blocking API in system tasks */
576 if (runTask->taskStatus & OS_TASK_FLAG_SYSTEM_TASK) {//不能在系统任务里调用,因为很容易让系统任务发生死锁
577 PRINTK("Warning: DO NOT call %s in system tasks.\n", __FUNCTION__);
578 OsBackTrace();
579 }
580
581 SCHEDULER_LOCK(intSave);
582 ret = OsMuxUnlockUnsafe(runTask, mutex, &needSched);
583 SCHEDULER_UNLOCK(intSave);
584 if (needSched == TRUE) {//需要调度的情况
585 LOS_MpSchedule(OS_MP_CPU_ALL);//向所有CPU发送调度指令
586 LOS_Schedule();//发起调度
587 }
588 return ret;
589}
590
591#endif /* (LOSCFG_BASE_IPC_MUX == YES) */
592
VOID OsBackTrace(VOID)
Kernel backtrace function.
Definition: los_exc.c:1025
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListInit(LOS_DL_LIST *list)
Definition: los_list.h:104
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListTailInsert(LOS_DL_LIST *list, LOS_DL_LIST *node)
Insert a node to the tail of a doubly linked list.
Definition: los_list.h:244
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListDelete(LOS_DL_LIST *node)
Definition: los_list.h:292
LITE_OS_SEC_ALW_INLINE STATIC INLINE BOOL LOS_ListEmpty(LOS_DL_LIST *list)
Identify whether a specified doubly linked list is empty. | 判断链表是否为空
Definition: los_list.h:321
LITE_OS_SEC_TEXT UINT32 LOS_MuxTrylock(LosMux *mutex)
尝试要锁,没拿到也不等,直接返回,不纠结
Definition: los_mux.c:464
LITE_OS_SEC_TEXT UINT32 LOS_MuxInit(LosMux *mutex, const LosMuxAttr *attr)
初始化互斥锁
Definition: los_mux.c:262
LITE_OS_SEC_TEXT UINT32 LOS_MuxUnlock(LosMux *mutex)
释放锁
Definition: los_mux.c:559
struct OsMux LosMux
LITE_OS_SEC_TEXT UINT32 LOS_MuxDestroy(LosMux *mutex)
销毁互斥锁
Definition: los_mux.c:289
LITE_OS_SEC_TEXT UINT32 LOS_MuxLock(LosMux *mutex, UINT32 timeout)
拿互斥锁,
Definition: los_mux.c:437
VOID LOS_Schedule(VOID)
Trigger active task scheduling.
Definition: los_sched.c:469
VOID LOS_MpSchedule(UINT32 target)
Definition: los_mp.c:76
LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrGetProtocol(const LosMuxAttr *attr, INT32 *protocol)
获取互斥锁的类型属性
Definition: los_mux.c:146
LITE_OS_SEC_TEXT BOOL LOS_MuxIsValid(const LosMux *mutex)
互斥锁是否有效
Definition: los_mux.c:239
STATIC UINT32 OsMuxPendOp(LosTaskCB *runTask, LosMux *mutex, UINT32 timeout)
最坏情况就是拿锁失败,让出CPU,变成阻塞任务,等别的任务释放锁后排到自己了接着执行.
Definition: los_mux.c:341
LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrSetType(LosMuxAttr *attr, INT32 type)
设置互斥锁的类型属性
Definition: los_mux.c:136
STATIC UINT32 OsMuxPostOp(LosTaskCB *taskCB, LosMux *mutex, BOOL *needSched)
OsMuxPostOp 是否有其他任务持有互斥锁而处于阻塞状,如果是就要唤醒它,注意唤醒一个任务的操作是由别的任务完成的 OsMuxPostOp只由OsMuxUnlockUnsafe,...
Definition: los_mux.c:502
VOID OsMuxBitmapRestore(const LosMux *mutex, const LOS_DL_LIST *list, const LosTaskCB *runTask)
恢复互斥锁位图
Definition: los_mux.c:328
LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrGetPrioceiling(const LosMuxAttr *attr, INT32 *prioceiling)
获取互斥锁属性优先级
Definition: los_mux.c:174
UINT32 OsMuxTrylockUnsafe(LosMux *mutex, UINT32 timeout)
尝试加锁,
Definition: los_mux.c:417
LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrDestroy(LosMuxAttr *attr)
????? 销毁互斥属 ,这里啥也没干呀
Definition: los_mux.c:109
LITE_OS_SEC_TEXT UINT32 LOS_MuxSetPrioceiling(LosMux *mutex, INT32 prioceiling, INT32 *oldPrioceiling)
设置互斥锁的优先级的上限,老优先级由oldPrioceiling带走
Definition: los_mux.c:200
UINT32 OsMuxLockUnsafe(LosMux *mutex, UINT32 timeout)
Definition: los_mux.c:398
LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrSetProtocol(LosMuxAttr *attr, INT32 protocol)
设置互斥锁属性的协议
Definition: los_mux.c:157
LITE_OS_SEC_TEXT UINT32 LOS_MuxGetPrioceiling(const LosMux *mutex, INT32 *prioceiling)
获取互斥锁的优先级的上限
Definition: los_mux.c:229
LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrSetPrioceiling(LosMuxAttr *attr, INT32 prioceiling)
设置互斥锁属性的优先级的上限
Definition: los_mux.c:187
LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrGetType(const LosMuxAttr *attr, INT32 *outType)
获取互斥锁的类型属性,由outType接走,不送!
Definition: los_mux.c:118
STATIC UINT32 OsCheckMutexAttr(const LosMuxAttr *attr)
检查互斥锁属性是否OK,否则 no ok :|)
Definition: los_mux.c:248
STATIC VOID OsMuxBitmapSet(const LosMux *mutex, const LosTaskCB *runTask)
设置互斥锁位图
Definition: los_mux.c:313
UINT32 OsMuxUnlockUnsafe(LosTaskCB *taskCB, LosMux *mutex, BOOL *needSched)
Definition: los_mux.c:527
LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrInit(LosMuxAttr *attr)
互斥属性初始化
Definition: los_mux.c:97
@ LOS_MUX_ERRORCHECK
进行错误检查,如果一个线程企图对一个已经锁住的mutex进行relock或对未加锁的unlock,将返回一个错误。
Definition: los_mux.h:58
@ LOS_MUX_RECURSIVE
递归锁 允许同一线程在互斥量解锁前对该互斥量进行多次加锁。递归互斥量维护锁的计数,在解锁次数和加锁次数不相同的情况下,不会释放锁,别的线程就无法加锁此互斥量。
Definition: los_mux.h:57
@ LOS_MUX_DEFAULT
Definition: los_mux.h:59
@ LOS_MUX_NORMAL
非递归锁 只有[0.1]两个状态,不做任何特殊的错误检,不进行deadlock detection(死锁检测)
Definition: los_mux.h:56
@ LOS_MUX_PRIO_INHERIT
Definition: los_mux.h:50
@ LOS_MUX_PRIO_PROTECT
详见: OsMuxPendOp 中的注解,详细说明了LOS_MUX_PRIO_PROTECT的含义
Definition: los_mux.h:52
@ LOS_MUX_PRIO_NONE
线程的优先级和调度不会受到互斥锁影响,先来后到,普通排队.
Definition: los_mux.h:49
STATIC INLINE LosTaskCB * OsCurrTaskGet(VOID)
LOS_DL_LIST * OsSchedLockPendFindPos(const LosTaskCB *runTask, LOS_DL_LIST *lockList)
Definition: los_sched.c:519
STATIC INLINE BOOL OsPreemptableInSched(VOID)
INT32 OsSchedParamCompare(const LosTaskCB *task1, const LosTaskCB *task2)
Definition: los_sched.c:233
STATIC INLINE VOID OsTaskWaitSetPendMask(UINT16 mask, UINTPTR lockID, UINT32 timeout)
设置事件阻塞掩码,即设置任务的等待事件.
Definition: los_task_pri.h:289
STATIC INLINE VOID OsTaskWakeClearPendMask(LosTaskCB *resumeTask)
清除事件阻塞掩码,即任务不再等待任何事件.
Definition: los_task_pri.h:298
signed int INT32
Definition: los_typedef.h:60
signed char INT8
Definition: los_typedef.h:58
unsigned char UINT8
Definition: los_typedef.h:55
unsigned long UINTPTR
Definition: los_typedef.h:68
unsigned int UINT32
Definition: los_typedef.h:57
size_t BOOL
Definition: los_typedef.h:88
struct LOS_DL_LIST * pstPrev
Definition: los_list.h:83
struct LOS_DL_LIST * pstNext
Definition: los_list.h:84
UINT8 protocol
协议
Definition: los_mux.h:63
UINT8 type
类型属性
Definition: los_mux.h:65
UINT8 prioceiling
优先级上限
Definition: los_mux.h:64
Definition: los_mux.h:73
VOID * owner
Definition: los_mux.h:78
UINT32 magic
Definition: los_mux.h:74
LOS_DL_LIST muxList
Definition: los_mux.h:77
UINT16 muxCount
Definition: los_mux.h:79
LOS_DL_LIST holdList
Definition: los_mux.h:76
LosMuxAttr attr
Definition: los_mux.h:75
VOID(* priorityInheritance)(LosTaskCB *owner, const SchedParam *param)
UINT32(* wait)(LosTaskCB *runTask, LOS_DL_LIST *list, UINT32 timeout)
任务等待
VOID(* wake)(LosTaskCB *taskCB)
任务唤醒
VOID(* priorityRestore)(LosTaskCB *owner, const LOS_DL_LIST *list, const SchedParam *param)
恢复调度参数
UINT32(* schedParamGet)(const LosTaskCB *taskCB, SchedParam *param)
获取调度参数
UINT16 priority
LOS_DL_LIST lockList
VOID * taskMux
const SchedOps * ops
UINT16 taskStatus