更新日期: 2022/06/01 来源: https://gitee.com/weharmony/kernel_liteos_a_note
los_rwlock.c 文件参考

https://weharmony.github.io/openharmony/zh-cn/device-dev/kernel/kernel-small-basic-trans-rwlock.html 更多...

浏览源代码.

函数

BOOL LOS_RwlockIsValid (const LosRwlock *rwlock)
 判断读写锁有效性 更多...
 
UINT32 LOS_RwlockInit (LosRwlock *rwlock)
 创建读写锁,初始化锁信息 更多...
 
UINT32 LOS_RwlockDestroy (LosRwlock *rwlock)
 删除指定的读写锁 更多...
 
STATIC UINT32 OsRwlockCheck (LosRwlock *rwlock)
 读写锁检查 更多...
 
STATIC BOOL OsRwlockPriCompare (LosTaskCB *runTask, LOS_DL_LIST *rwList)
 指定任务优先级优先级是否低于 写锁任务最高优先级
更多...
 
STATIC UINT32 OsRwlockRdPendOp (LosTaskCB *runTask, LosRwlock *rwlock, UINT32 timeout)
 
STATIC UINT32 OsRwlockWrPendOp (LosTaskCB *runTask, LosRwlock *rwlock, UINT32 timeout)
 申请写模式下的锁 更多...
 
UINT32 OsRwlockRdUnsafe (LosRwlock *rwlock, UINT32 timeout)
 
UINT32 OsRwlockTryRdUnsafe (LosRwlock *rwlock, UINT32 timeout)
 
UINT32 OsRwlockWrUnsafe (LosRwlock *rwlock, UINT32 timeout)
 
UINT32 OsRwlockTryWrUnsafe (LosRwlock *rwlock, UINT32 timeout)
 
UINT32 LOS_RwlockRdLock (LosRwlock *rwlock, UINT32 timeout)
 申请指定的读模式下的锁 更多...
 
UINT32 LOS_RwlockTryRdLock (LosRwlock *rwlock)
 尝试申请指定的读模式下的锁 更多...
 
UINT32 LOS_RwlockWrLock (LosRwlock *rwlock, UINT32 timeout)
 申请指定的写模式下的锁 更多...
 
UINT32 LOS_RwlockTryWrLock (LosRwlock *rwlock)
 尝试申请指定的写模式下的锁 更多...
 
STATIC UINT32 OsRwlockGetMode (LOS_DL_LIST *readList, LOS_DL_LIST *writeList)
 获取读写锁模式 更多...
 
STATIC UINT32 OsRwlockPostOp (LosRwlock *rwlock, BOOL *needSched)
 释放锁 更多...
 
UINT32 OsRwlockUnlockUnsafe (LosRwlock *rwlock, BOOL *needSched)
 释放锁,唤醒任务 更多...
 
UINT32 LOS_RwlockUnLock (LosRwlock *rwlock)
 释放指定读写锁 更多...
 

详细描述

https://weharmony.github.io/openharmony/zh-cn/device-dev/kernel/kernel-small-basic-trans-rwlock.html

基本概念
    读写锁与互斥锁类似,可用来同步同一进程中的各个任务,但与互斥锁不同的是,其允许多个读操作并发重入,而写操作互斥。
    相对于互斥锁的开锁或闭锁状态,读写锁有三种状态:读模式下的锁,写模式下的锁,无锁。
    读写锁的使用规则:
        保护区无写模式下的锁,任何任务均可以为其增加读模式下的锁。
        保护区处于无锁状态下,才可增加写模式下的锁。
        多任务环境下往往存在多个任务访问同一共享资源的应用场景,读模式下的锁以共享状态对保护区访问,
        而写模式下的锁可被用于对共享资源的保护从而实现独占式访问。
        这种共享-独占的方式非常适合多任务中读数据频率远大于写数据频率的应用中,提高应用多任务并发度。
运行机制
    相较于互斥锁,读写锁如何实现读模式下的锁及写模式下的锁来控制多任务的读写访问呢?
    若A任务首次获取了写模式下的锁,有其他任务来获取或尝试获取读模式下的锁,均无法再上锁。
    若A任务获取了读模式下的锁,当有任务来获取或尝试获取读模式下的锁时,读写锁计数均加一。
版本
作者
weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
日期
2022-02-18

在文件 los_rwlock.c 中定义.

函数说明

◆ LOS_RwlockIsValid()

BOOL LOS_RwlockIsValid ( const LosRwlock rwlock)

判断读写锁有效性

在文件 los_rwlock.c70 行定义.

71{
72 if ((rwlock != NULL) && ((rwlock->magic & RWLOCK_COUNT_MASK) == OS_RWLOCK_MAGIC)) {
73 return TRUE;
74 }
75
76 return FALSE;
77}
INT32 magic
Definition: los_rwlock.h:53

◆ OsRwlockCheck()

STATIC UINT32 OsRwlockCheck ( LosRwlock rwlock)

读写锁检查

在文件 los_rwlock.c126 行定义.

127{
128 if (rwlock == NULL) {
129 return LOS_EINVAL;
130 }
131
132 if (OS_INT_ACTIVE) { // 读写锁不能在中断服务程序中使用。请想想为什么 ?
133 return LOS_EINTR;
134 }
135
136 /* DO NOT Call blocking API in system tasks | 系统任务不能使用读写锁 */
137 LosTaskCB *runTask = (LosTaskCB *)OsCurrTaskGet();
138 if (runTask->taskStatus & OS_TASK_FLAG_SYSTEM_TASK) {
139 return LOS_EPERM;
140 }
141
142 return LOS_OK;
143}
STATIC INLINE LosTaskCB * OsCurrTaskGet(VOID)
UINT16 taskStatus
函数调用图:
这是这个函数的调用关系图:

◆ OsRwlockGetMode()

STATIC UINT32 OsRwlockGetMode ( LOS_DL_LIST readList,
LOS_DL_LIST writeList 
)

获取读写锁模式

在文件 los_rwlock.c381 行定义.

382{
383 BOOL isReadEmpty = LOS_ListEmpty(readList);
384 BOOL isWriteEmpty = LOS_ListEmpty(writeList);
385 if (isReadEmpty && isWriteEmpty) { //读写链表都没有内容
386 return RWLOCK_NONE_MODE; //自由模式
387 }
388 if (!isReadEmpty && isWriteEmpty) { //读链表有数据,写链表没有数据
389 return RWLOCK_READ_MODE;
390 }
391 if (isReadEmpty && !isWriteEmpty) { //写链表有数据,读链表没有数据
392 return RWLOCK_WRITE_MODE;
393 }
394 LosTaskCB *pendedReadTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(readList));
395 LosTaskCB *pendedWriteTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(writeList));
396 if (OsSchedParamCompare(pendedWriteTask, pendedReadTask) <= 0) {
397 return RWLOCK_WRITEFIRST_MODE; //写的优先级高时,为写优先模式
398 }
399 return RWLOCK_READFIRST_MODE; //读的优先级高时,为读优先模式
400}
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
@ RWLOCK_READ_MODE
读模式: 读链表有数据,写链表没有数据
@ RWLOCK_WRITE_MODE
写模式: 写链表有数据,读链表没有数据
@ RWLOCK_READFIRST_MODE
读优先模式: 读链表中的任务最高优先级高于写链表中任务最高优先级
@ RWLOCK_NONE_MODE
自由模式: 读写链表都没有内容
@ RWLOCK_WRITEFIRST_MODE
写优先模式: 写链表中的任务最高优先级高于读链表中任务最高优先级
INT32 OsSchedParamCompare(const LosTaskCB *task1, const LosTaskCB *task2)
Definition: los_sched.c:233
size_t BOOL
Definition: los_typedef.h:88
函数调用图:
这是这个函数的调用关系图:

◆ OsRwlockPostOp()

STATIC UINT32 OsRwlockPostOp ( LosRwlock rwlock,
BOOL needSched 
)

释放锁

在文件 los_rwlock.c402 行定义.

403{
404 UINT32 rwlockMode;
405 LosTaskCB *resumedTask = NULL;
406
407 rwlock->rwCount = 0;
408 rwlock->writeOwner = NULL;
409 rwlockMode = OsRwlockGetMode(&(rwlock->readList), &(rwlock->writeList));//先获取模式
410 if (rwlockMode == RWLOCK_NONE_MODE) {//自由模式则正常返回
411 return LOS_OK;
412 }
413 /* In this case, rwlock will wake the first pended write task. | 在这种情况下,rwlock 将唤醒第一个挂起的写任务。 */
414 if ((rwlockMode == RWLOCK_WRITE_MODE) || (rwlockMode == RWLOCK_WRITEFIRST_MODE)) {//如果当前是写模式 (有任务在等写锁涅)
415 resumedTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(rwlock->writeList)));//获取任务实体
416 rwlock->rwCount = -1;//直接干成-1,注意这里并不是 --
417 rwlock->writeOwner = (VOID *)resumedTask;//有锁了则唤醒等锁的任务(写模式)
418 resumedTask->ops->wake(resumedTask);
419 if (needSched != NULL) {
420 *needSched = TRUE;
421 }
422 return LOS_OK;
423 }
424
425 rwlock->rwCount = 1; //直接干成1,因为是释放操作
426 resumedTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(rwlock->readList)));
427 resumedTask->ops->wake(resumedTask);
428 while (!LOS_ListEmpty(&(rwlock->readList))) {//遍历读链表,目的是要唤醒其他读模式的任务(优先级得要高于pendedWriteTaskPri才行)
429 resumedTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(rwlock->readList)));
430 if (rwlockMode == RWLOCK_READFIRST_MODE) {
431 LosTaskCB *pendedWriteTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(rwlock->writeList)));
432 if (OsSchedParamCompare(resumedTask, pendedWriteTask) >= 0) {
433 break;//跳出循环
434 }
435 }
436 if (rwlock->rwCount == INT8_MAX) {
437 return EINVAL;
438 }
439 rwlock->rwCount++;//读锁任务数量增加
440 resumedTask->ops->wake(resumedTask);//不断唤醒读锁任务,由此实现了允许多个读操作并发,因为在多核情况下resumedTask很大可能
441 //与当前任务并不在同一个核上运行, 此处非常有意思,点赞! @note_good
442 }
443 if (needSched != NULL) {
444 *needSched = TRUE;
445 }
446 return LOS_OK;
447}
STATIC UINT32 OsRwlockGetMode(LOS_DL_LIST *readList, LOS_DL_LIST *writeList)
获取读写锁模式
Definition: los_rwlock.c:381
unsigned int UINT32
Definition: los_typedef.h:57
LOS_DL_LIST readList
Definition: los_rwlock.h:59
VOID * writeOwner
Definition: los_rwlock.h:58
INT32 rwCount
Definition: los_rwlock.h:54
LOS_DL_LIST writeList
Definition: los_rwlock.h:60
VOID(* wake)(LosTaskCB *taskCB)
任务唤醒
const SchedOps * ops
函数调用图:
这是这个函数的调用关系图:

◆ OsRwlockPriCompare()

STATIC BOOL OsRwlockPriCompare ( LosTaskCB runTask,
LOS_DL_LIST rwList 
)

指定任务优先级优先级是否低于 写锁任务最高优先级

在文件 los_rwlock.c145 行定义.

146{
147 if (!LOS_ListEmpty(rwList)) {
148 LosTaskCB *highestTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(rwList));//首个写锁任务优先级是最高的
149 if (OsSchedParamCompare(runTask, highestTask) < 0) {//如果当前任务优先级低于等待写锁任务
150 return TRUE;
151 }
152 return FALSE;
153 }
154 return TRUE;
155}
函数调用图:
这是这个函数的调用关系图:

◆ OsRwlockRdPendOp()

STATIC UINT32 OsRwlockRdPendOp ( LosTaskCB runTask,
LosRwlock rwlock,
UINT32  timeout 
)

在文件 los_rwlock.c161 行定义.

162{
163 UINT32 ret;
164
165 /*
166 * When the rwlock mode is read mode or free mode and the priority of the current read task
167 * is higher than the first pended write task. current read task can obtain this rwlock.
168 */
169 if (rwlock->rwCount >= 0) {//第一和第二种情况
170 if (OsRwlockPriCompare(runTask, &(rwlock->writeList))) {//读优先级低于写优先级,意思就是必须先写再读
171 if (rwlock->rwCount == INT8_MAX) {//读锁任务达到上限
172 return LOS_EINVAL;
173 }
174 rwlock->rwCount++;//拿读锁成功
175 return LOS_OK;
176 }
177 }
178
179 if (!timeout) {
180 return LOS_EINVAL;
181 }
182
183 if (!OsPreemptableInSched()) {//不可抢占时
184 return LOS_EDEADLK;
185 }
186
187 /* The current task is not allowed to obtain the write lock when it obtains the read lock.
188 | 当前任务在获得读锁时不允许获得写锁 */
189 if ((LosTaskCB *)(rwlock->writeOwner) == runTask) { //拥有写锁任务是否为当前任务
190 return LOS_EINVAL;
191 }
192
193 /*
194 * When the rwlock mode is write mode or the priority of the current read task
195 * is lower than the first pended write task, current read task will be pended.
196 | 当 rwlock 模式为写模式或当前读任务的优先级低于第一个挂起的写任务时,当前读任务将被挂起。
197 反正就是写锁任务优先
198 */
199 LOS_DL_LIST *node = OsSchedLockPendFindPos(runTask, &(rwlock->readList));//找到要挂入的位置
200 //例如现有链表内任务优先级为 0 3 8 9 23 当前为 10 时, 返回的是 9 这个节点
201 ret = runTask->ops->wait(runTask, node, timeout);//从尾部插入读锁链表 由此变成了 0 3 8 9 10 23
202 if (ret == LOS_ERRNO_TSK_TIMEOUT) {
203 return LOS_ETIMEDOUT;
204 }
205
206 return ret;
207}
STATIC BOOL OsRwlockPriCompare(LosTaskCB *runTask, LOS_DL_LIST *rwList)
指定任务优先级优先级是否低于 写锁任务最高优先级
Definition: los_rwlock.c:145
LOS_DL_LIST * OsSchedLockPendFindPos(const LosTaskCB *runTask, LOS_DL_LIST *lockList)
Definition: los_sched.c:519
STATIC INLINE BOOL OsPreemptableInSched(VOID)
UINT32(* wait)(LosTaskCB *runTask, LOS_DL_LIST *list, UINT32 timeout)
任务等待
函数调用图:
这是这个函数的调用关系图:

◆ OsRwlockRdUnsafe()

UINT32 OsRwlockRdUnsafe ( LosRwlock rwlock,
UINT32  timeout 
)

在文件 los_rwlock.c252 行定义.

253{
254 if ((rwlock->magic & RWLOCK_COUNT_MASK) != OS_RWLOCK_MAGIC) {
255 return LOS_EBADF;
256 }
257
258 return OsRwlockRdPendOp(OsCurrTaskGet(), rwlock, timeout);
259}
STATIC UINT32 OsRwlockRdPendOp(LosTaskCB *runTask, LosRwlock *rwlock, UINT32 timeout)
Definition: los_rwlock.c:161
函数调用图:
这是这个函数的调用关系图:

◆ OsRwlockTryRdUnsafe()

UINT32 OsRwlockTryRdUnsafe ( LosRwlock rwlock,
UINT32  timeout 
)

在文件 los_rwlock.c261 行定义.

262{
263 if ((rwlock->magic & RWLOCK_COUNT_MASK) != OS_RWLOCK_MAGIC) {
264 return LOS_EBADF;
265 }
266
267 LosTaskCB *runTask = OsCurrTaskGet();
268 if ((LosTaskCB *)(rwlock->writeOwner) == runTask) {
269 return LOS_EINVAL;
270 }
271
272 /*
273 * When the rwlock mode is read mode or free mode and the priority of the current read task
274 * is lower than the first pended write task, current read task can not obtain the rwlock.
275 */
276 if ((rwlock->rwCount >= 0) && !OsRwlockPriCompare(runTask, &(rwlock->writeList))) {
277 return LOS_EBUSY;
278 }
279
280 /*
281 * When the rwlock mode is write mode, current read task can not obtain the rwlock.
282 */
283 if (rwlock->rwCount < 0) {
284 return LOS_EBUSY;
285 }
286
287 return OsRwlockRdPendOp(runTask, rwlock, timeout);
288}
函数调用图:
这是这个函数的调用关系图:

◆ OsRwlockTryWrUnsafe()

UINT32 OsRwlockTryWrUnsafe ( LosRwlock rwlock,
UINT32  timeout 
)

在文件 los_rwlock.c299 行定义.

300{
301 if ((rwlock->magic & RWLOCK_COUNT_MASK) != OS_RWLOCK_MAGIC) {
302 return LOS_EBADF;
303 }
304
305 /* When the rwlock is read mode, current write task will be pended.
306 | 当 rwlock 为读模式时,当前的写任务将被挂起。*/
307 if (rwlock->rwCount > 0) {
308 return LOS_EBUSY;
309 }
310
311 /* When other write task obtains this rwlock, current write task will be pended.
312 | 当其他写任务获得这个rwlock时,当前的写任务将被挂起。*/
313 LosTaskCB *runTask = OsCurrTaskGet();
314 if ((rwlock->rwCount < 0) && ((LosTaskCB *)(rwlock->writeOwner) != runTask)) {
315 return LOS_EBUSY;
316 }
317
318 return OsRwlockWrPendOp(runTask, rwlock, timeout);//
319}
STATIC UINT32 OsRwlockWrPendOp(LosTaskCB *runTask, LosRwlock *rwlock, UINT32 timeout)
申请写模式下的锁
Definition: los_rwlock.c:209
函数调用图:
这是这个函数的调用关系图:

◆ OsRwlockUnlockUnsafe()

UINT32 OsRwlockUnlockUnsafe ( LosRwlock rwlock,
BOOL needSched 
)

释放锁,唤醒任务

在文件 los_rwlock.c449 行定义.

450{
451 if ((rwlock->magic & RWLOCK_COUNT_MASK) != OS_RWLOCK_MAGIC) {
452 return LOS_EBADF;
453 }
454
455 if (rwlock->rwCount == 0) {
456 return LOS_EPERM;
457 }
458
459 LosTaskCB *runTask = OsCurrTaskGet();
460 if ((rwlock->rwCount < 0) && ((LosTaskCB *)(rwlock->writeOwner) != runTask)) {//写模式时,当前任务未持有锁
461 return LOS_EPERM;
462 }
463
464 /*
465 * When the rwCount of the rwlock more than 1 or less than -1, the rwlock mode will
466 * not changed after current unlock operation, so pended tasks can not be waken.
467 | 当 rwlock 的 rwCount 大于 1 或小于 -1 时,当前解锁操作后 rwlock 模式不会改变,因此挂起的任务不能被唤醒。
468 */
469 if (rwlock->rwCount > 1) {//读模式
470 rwlock->rwCount--;
471 return LOS_OK;
472 }
473
474 if (rwlock->rwCount < -1) {//写模式
475 rwlock->rwCount++;
476 return LOS_OK;
477 }
478
479 return OsRwlockPostOp(rwlock, needSched);
480}
STATIC UINT32 OsRwlockPostOp(LosRwlock *rwlock, BOOL *needSched)
释放锁
Definition: los_rwlock.c:402
函数调用图:
这是这个函数的调用关系图:

◆ OsRwlockWrPendOp()

STATIC UINT32 OsRwlockWrPendOp ( LosTaskCB runTask,
LosRwlock rwlock,
UINT32  timeout 
)

申请写模式下的锁

在文件 los_rwlock.c209 行定义.

210{
211 UINT32 ret;
212
213 /* When the rwlock is free mode, current write task can obtain this rwlock.
214 | 若该锁当前没有任务持有,或者持有该读模式下的锁的任务和申请该锁的任务为同一个任务,则申请成功,可立即获得写模式下的锁。*/
215 if (rwlock->rwCount == 0) {
216 rwlock->rwCount = -1;
217 rwlock->writeOwner = (VOID *)runTask;//直接给当前进程锁
218 return LOS_OK;
219 }
220
221 /* Current write task can use one rwlock once again if the rwlock owner is it.
222 | 如果 rwlock 拥有者是当前写入任务,则它可以再次使用该锁。*/
223 if ((rwlock->rwCount < 0) && ((LosTaskCB *)(rwlock->writeOwner) == runTask)) {
224 if (rwlock->rwCount == INT8_MIN) {
225 return LOS_EINVAL;
226 }
227 rwlock->rwCount--;//注意再次拥有算是两把写锁了.
228 return LOS_OK;
229 }
230
231 if (!timeout) {
232 return LOS_EINVAL;
233 }
234
235 if (!OsPreemptableInSched()) {
236 return LOS_EDEADLK;
237 }
238
239 /*
240 * When the rwlock is read mode or other write task obtains this rwlock, current
241 * write task will be pended. | 当 rwlock 为读模式或其他写任务获得该 rwlock 时,当前的写任务将被挂起。直到读模式下的锁释放
242 */
243 LOS_DL_LIST *node = OsSchedLockPendFindPos(runTask, &(rwlock->writeList));//找到要挂入的位置
244 ret = runTask->ops->wait(runTask, node, timeout);
245 if (ret == LOS_ERRNO_TSK_TIMEOUT) {
246 ret = LOS_ETIMEDOUT;
247 }
248
249 return ret;
250}
函数调用图:
这是这个函数的调用关系图:

◆ OsRwlockWrUnsafe()

UINT32 OsRwlockWrUnsafe ( LosRwlock rwlock,
UINT32  timeout 
)

在文件 los_rwlock.c290 行定义.

291{
292 if ((rwlock->magic & RWLOCK_COUNT_MASK) != OS_RWLOCK_MAGIC) {
293 return LOS_EBADF;
294 }
295
296 return OsRwlockWrPendOp(OsCurrTaskGet(), rwlock, timeout);
297}
函数调用图:
这是这个函数的调用关系图: