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

http://weharmonyos.com/openharmony/zh-cn/device-dev/kernel/kernel-small-basic-trans-user-mutex.html https://www.jianshu.com/p/d17a6152740c 更多...

浏览源代码.

结构体

struct  FutexHash
 单独哈希桶,上面挂了一个个 FutexNode 更多...
 

函数

STATIC INT32 OsFutexLock (LosMux *lock)
 对互斥锁封装 更多...
 
STATIC INT32 OsFutexUnlock (LosMux *lock)
 初始化Futex(Fast userspace mutex,用户态快速互斥锁)模块 更多...
 
UINT32 OsFutexInit (VOID)
 
 LOS_MODULE_INIT (OsFutexInit, LOS_INIT_LEVEL_KMOD_EXTENDED)
 注册Futex模块 更多...
 
STATIC VOID OsFutexShowTaskNodeAttr (const LOS_DL_LIST *futexList)
 
VOID OsFutexHashShow (VOID)
 
STATIC INLINE UINTPTR OsFutexFlagsToKey (const UINT32 *userVaddr, const UINT32 flags)
 通过用户空间地址获取哈希key 更多...
 
STATIC INLINE UINT32 OsFutexKeyToIndex (const UINTPTR futexKey, const UINT32 flags)
 通过哈希key获取索引 更多...
 
STATIC INLINE VOID OsFutexSetKey (UINTPTR futexKey, UINT32 flags, FutexNode *node)
 设置快锁哈希key 更多...
 
STATIC INLINE VOID OsFutexDeinitFutexNode (FutexNode *node)
 
STATIC INLINE VOID OsFutexReplaceQueueListHeadNode (FutexNode *oldHeadNode, FutexNode *newHeadNode)
 新旧两个节点交换 futexList 位置 更多...
 
STATIC INLINE VOID OsFutexDeleteKeyFromFutexList (FutexNode *node)
 将参数节点从futexList上摘除 更多...
 
STATIC VOID OsFutexDeleteKeyNodeFromHash (FutexNode *node, BOOL isDeleteHead, FutexNode **headNode, BOOL *queueFlags)
 从哈希桶中删除快锁节点 更多...
 
VOID OsFutexNodeDeleteFromFutexHash (FutexNode *node, BOOL isDeleteHead, FutexNode **headNode, BOOL *queueFlags)
 从哈希桶上删除快锁 更多...
 
STATIC FutexNodeOsFutexDeleteAlreadyWakeTaskAndGetNext (const FutexNode *node, FutexNode **headNode, BOOL isDeleteHead)
 这块代码谁写的? 这种命名 ... 更多...
 
STATIC VOID OsFutexInsertNewFutexKeyToHash (FutexNode *node)
 插入一把新Futex锁到哈希桶中,只有是新的key时才会插入,因为其实存在多个FutexNode是一个key 更多...
 
STATIC INT32 OsFutexInsertFindFormBackToFront (LOS_DL_LIST *queueList, const LosTaskCB *runTask, FutexNode *node)
 
STATIC INT32 OsFutexInsertFindFromFrontToBack (LOS_DL_LIST *queueList, const LosTaskCB *runTask, FutexNode *node)
 
STATIC INT32 OsFutexRecycleAndFindHeadNode (FutexNode *headNode, FutexNode *node, FutexNode **firstNode)
 将快锁挂到任务的阻塞链表上 更多...
 
STATIC INT32 OsFutexInsertTasktoPendList (FutexNode **firstNode, FutexNode *node, const LosTaskCB *run)
 
STATIC FutexNodeOsFindFutexNode (const FutexNode *node)
 由指定快锁找到对应哈希桶 更多...
 
STATIC INT32 OsFindAndInsertToHash (FutexNode *node)
 
STATIC INT32 OsFutexKeyShmPermCheck (const UINT32 *userVaddr, const UINT32 flags)
 共享内存检查 更多...
 
STATIC INT32 OsFutexWaitParamCheck (const UINT32 *userVaddr, UINT32 flags, UINT32 absTime)
 
STATIC INT32 OsFutexDeleteTimeoutTaskNode (FutexHash *hashNode, FutexNode *node)
 
STATIC INT32 OsFutexInsertTaskToHash (LosTaskCB **taskCB, FutexNode **node, const UINTPTR futexKey, const UINT32 flags)
 将快锁节点插入任务 更多...
 
STATIC INT32 OsFutexWaitTask (const UINT32 *userVaddr, const UINT32 flags, const UINT32 val, const UINT32 timeout)
 将当前任务挂入等待链表中 更多...
 
INT32 OsFutexWait (const UINT32 *userVaddr, UINT32 flags, UINT32 val, UINT32 absTime)
 设置线程等待 | 向Futex表中插入代表被阻塞的线程的node 更多...
 
STATIC INT32 OsFutexWakeParamCheck (const UINT32 *userVaddr, UINT32 flags)
 
STATIC VOID OsFutexCheckAndWakePendTask (FutexNode *headNode, const INT32 wakeNumber, FutexHash *hashNode, FutexNode **nextNode, BOOL *wakeAny)
 
STATIC INT32 OsFutexWakeTask (UINTPTR futexKey, UINT32 flags, INT32 wakeNumber, FutexNode **newHeadNode, BOOL *wakeAny)
 OsFutexWakeTask 唤醒任务 更多...
 
INT32 OsFutexWake (const UINT32 *userVaddr, UINT32 flags, INT32 wakeNumber)
 唤醒一个被指定锁阻塞的线程 更多...
 
STATIC INT32 OsFutexRequeueInsertNewKey (UINTPTR newFutexKey, INT32 newIndex, FutexNode *oldHeadNode)
 
STATIC VOID OsFutexRequeueSplitTwoLists (FutexHash *oldHashNode, FutexNode *oldHeadNode, UINT32 flags, UINTPTR futexKey, INT32 count)
 
STATIC FutexNodeOsFutexRequeueRemoveOldKeyAndGetHead (UINTPTR oldFutexKey, UINT32 flags, INT32 wakeNumber, UINTPTR newFutexKey, INT32 requeueCount, BOOL *wakeAny)
 删除旧key并获取头节点 更多...
 
STATIC INT32 OsFutexRequeueParamCheck (const UINT32 *oldUserVaddr, UINT32 flags, const UINT32 *newUserVaddr)
 检查锁在Futex表中的状态 更多...
 
INT32 OsFutexRequeue (const UINT32 *userVaddr, UINT32 flags, INT32 wakeNumber, INT32 count, const UINT32 *newUserVaddr)
 调整指定锁在Futex表中的位置 更多...
 

变量

FutexHash g_futexHash [FUTEX_INDEX_MAX]
 80个哈希桶 更多...
 

详细描述

http://weharmonyos.com/openharmony/zh-cn/device-dev/kernel/kernel-small-basic-trans-user-mutex.html https://www.jianshu.com/p/d17a6152740c

Futex 由一块能够被多个进程共享的内存空间(一个对齐后的整型变量)组成;这个整型变量的值能够通过汇编语言调用CPU提供的原子操作指令来增加或减少,
并且一个进程可以等待直到那个值变成正数。Futex 的操作几乎全部在用户空间完成;只有当操作结果不一致从而需要仲裁时,才需要进入操作系统内核空间执行。
这种机制允许使用 futex 的锁定原语有非常高的执行效率:由于绝大多数的操作并不需要在多个进程之间进行仲裁,所以绝大多数操作都可以在应用程序空间执行,
而不需要使用(相对高代价的)内核系统调用。

基本概念
    Futex(Fast userspace mutex,用户态快速互斥锁)是内核提供的一种系统调用能力,通常作为基础组件与用户态的相关
    锁逻辑结合组成用户态锁,是一种用户态与内核态共同作用的锁,例如用户态mutex锁、barrier与cond同步锁、读写锁。
    其用户态部分负责锁逻辑,内核态部分负责锁调度。
    
    当用户态线程请求锁时,先在用户态进行锁状态的判断维护,若此时不产生锁的竞争,则直接在用户态进行上锁返回;
    反之,则需要进行线程的挂起操作,通过Futex系统调用请求内核介入来挂起线程,并维护阻塞队列。
    
    当用户态线程释放锁时,先在用户态进行锁状态的判断维护,若此时没有其他线程被该锁阻塞,则直接在用户态进行解锁返回;
    反之,则需要进行阻塞线程的唤醒操作,通过Futex系统调用请求内核介入来唤醒阻塞队列中的线程。
历史
    futex (fast userspace mutex) 是Linux的一个基础组件,可以用来构建各种更高级别的同步机制,比如锁或者信号量等等,
    POSIX信号量就是基于futex构建的。大多数时候编写应用程序并不需要直接使用futex,一般用基于它所实现的系统库就够了。

    传统的SystemV IPC(inter process communication)进程间同步机制都是通过内核对象来实现的,以 semaphore 为例,
    当进程间要同步的时候,必须通过系统调用semop(2)进入内核进行PV操作。系统调用的缺点是开销很大,需要从user mode
    切换到kernel mode、保存寄存器状态、从user stack切换到kernel stack、等等,通常要消耗上百条指令。事实上,
    有一部分系统调用是可以避免的,因为现实中很多同步操作进行的时候根本不存在竞争,即某个进程从持有semaphore直至
    释放semaphore的这段时间内,常常没有其它进程对同一semaphore有需求,在这种情况下,内核的参与本来是不必要的,
    可是在传统机制下,持有semaphore必须先调用semop(2)进入内核去看看有没有人和它竞争,释放semaphore也必须调用semop(2)
    进入内核去看看有没有人在等待同一semaphore,这些不必要的系统调用造成了大量的性能损耗。  
设计思想
       futex的解决思路是:在无竞争的情况下操作完全在user space进行,不需要系统调用,仅在发生竞争的时候进入内核去完成
       相应的处理(wait 或者 wake up)。所以说,futex是一种user mode和kernel mode混合的同步机制,需要两种模式合作才能完成,
       futex变量必须位于user space,而不是内核对象,futex的代码也分为user mode和kernel mode两部分,无竞争的情况下在user mode,
       发生竞争时则通过sys_futex系统调用进入kernel mode进行处理
运行机制
       当用户态产生锁的竞争或释放需要进行相关线程的调度操作时,会触发Futex系统调用进入内核,此时会将用户态锁的地址
       传入内核,并在内核的Futex中以锁地址来区分用户态的每一把锁,因为用户态可用虚拟地址空间为1GiB,为了便于查找、
       管理,内核Futex采用哈希桶来存放用户态传入的锁。

    当前哈希桶共有80个,0~63号桶用于存放私有锁(以虚拟地址进行哈希),64~79号桶用于存放共享锁(以物理地址进行哈希),
    私有/共享属性通过用户态锁的初始化以及Futex系统调用入参确定。

    如下图: 每个futex哈希桶中存放被futex_list串联起来的哈希值相同的futex node,每个futex node对应一个被挂起的task,
    node中key值唯一标识一把用户态锁,具有相同key值的node被queue_list串联起来表示被同一把锁阻塞的task队列。
注意
Futex系统调用通常与用户态逻辑共同组成用户态锁,故推荐使用用户态POSIX接口的锁
版本
作者
weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
日期
2021-11-23

在文件 los_futex.c 中定义.

函数说明

◆ LOS_MODULE_INIT()

LOS_MODULE_INIT ( OsFutexInit  ,
LOS_INIT_LEVEL_KMOD_EXTENDED   
)

注册Futex模块

◆ OsFindAndInsertToHash()

STATIC INT32 OsFindAndInsertToHash ( FutexNode node)

在文件 los_futex.c516 行定义.

517{
518 FutexNode *headNode = NULL;
519 FutexNode *firstNode = NULL;
520 UINT32 intSave;
521 INT32 ret;
522
523 headNode = OsFindFutexNode(node);
524 if (headNode == NULL) {//没有找到,说明这是一把新锁
526 LOS_ListInit(&(node->queueList));
527 return LOS_OK;
528 }
529
530 ret = OsFutexRecycleAndFindHeadNode(headNode, node, &firstNode);
531 if (ret != LOS_OK) {
532 return ret;
533 } else if (firstNode == NULL) {
534 return ret;
535 }
536
537 SCHEDULER_LOCK(intSave);
538 ret = OsFutexInsertTasktoPendList(&firstNode, node, OsCurrTaskGet());
539 SCHEDULER_UNLOCK(intSave);
540
541 return ret;
542}
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListInit(LOS_DL_LIST *list)
Definition: los_list.h:104
STATIC INT32 OsFutexRecycleAndFindHeadNode(FutexNode *headNode, FutexNode *node, FutexNode **firstNode)
将快锁挂到任务的阻塞链表上
Definition: los_futex.c:450
STATIC INT32 OsFutexInsertTasktoPendList(FutexNode **firstNode, FutexNode *node, const LosTaskCB *run)
Definition: los_futex.c:468
STATIC VOID OsFutexInsertNewFutexKeyToHash(FutexNode *node)
插入一把新Futex锁到哈希桶中,只有是新的key时才会插入,因为其实存在多个FutexNode是一个key
Definition: los_futex.c:352
STATIC FutexNode * OsFindFutexNode(const FutexNode *node)
由指定快锁找到对应哈希桶
Definition: los_futex.c:498
STATIC INLINE LosTaskCB * OsCurrTaskGet(VOID)
signed int INT32
Definition: los_typedef.h:60
unsigned int UINT32
Definition: los_typedef.h:57
每个futex node对应一个被挂起的task ,key值唯一标识一把用户态锁,具有相同key值的node被queue_list串联起来表示被同一把锁阻塞的task队列。
Definition: los_futex_pri.h:77
LOS_DL_LIST queueList
Definition: los_futex_pri.h:82
函数调用图:
这是这个函数的调用关系图:

◆ OsFindFutexNode()

STATIC FutexNode * OsFindFutexNode ( const FutexNode node)

由指定快锁找到对应哈希桶

查找快锁并插入哈希桶中

在文件 los_futex.c498 行定义.

这是这个函数的调用关系图:

◆ OsFutexCheckAndWakePendTask()

STATIC VOID OsFutexCheckAndWakePendTask ( FutexNode headNode,
const INT32  wakeNumber,
FutexHash hashNode,
FutexNode **  nextNode,
BOOL wakeAny 
)

在文件 los_futex.c735 行定义.

737{
738 INT32 count;
739 LosTaskCB *taskCB = NULL;
740 FutexNode *node = headNode;
741 for (count = 0; count < wakeNumber; count++) {
742 /* Ensure the integrity of the head */
743 *nextNode = OsFutexDeleteAlreadyWakeTaskAndGetNext(node, NULL, FALSE);
744 if (*nextNode == NULL) {
745 /* The last node in queuelist is invalid or the entire list is invalid */
746 return;
747 }
748 node = *nextNode;
749 taskCB = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(node->pendList)));
751 taskCB->ops->wake(taskCB);
752 *wakeAny = TRUE;
753 *nextNode = OS_FUTEX_FROM_QUEUELIST(LOS_DL_LIST_FIRST(&(node->queueList)));
754 if (node != headNode) {
756 }
757
758 if (LOS_ListEmpty(&headNode->queueList)) {
759 /* Wakes up the entire linked list node */
760 *nextNode = NULL;
761 return;
762 }
763
764 node = *nextNode;
765 }
766 return;
767}
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
STATIC FutexNode * OsFutexDeleteAlreadyWakeTaskAndGetNext(const FutexNode *node, FutexNode **headNode, BOOL isDeleteHead)
这块代码谁写的? 这种命名 ...
Definition: los_futex.c:330
STATIC INLINE VOID OsFutexDeinitFutexNode(FutexNode *node)
Definition: los_futex.c:246
STATIC INLINE VOID OsTaskWakeClearPendMask(LosTaskCB *resumeTask)
清除事件阻塞掩码,即任务不再等待任何事件.
Definition: los_task_pri.h:298
LOS_DL_LIST pendList
Definition: los_futex_pri.h:81
VOID(* wake)(LosTaskCB *taskCB)
任务唤醒
const SchedOps * ops
函数调用图:
这是这个函数的调用关系图:

◆ OsFutexDeinitFutexNode()

STATIC INLINE VOID OsFutexDeinitFutexNode ( FutexNode node)

在文件 los_futex.c246 行定义.

247{
248 node->index = OS_INVALID_VALUE;
249 node->pid = 0;
251}
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListDelete(LOS_DL_LIST *node)
Definition: los_list.h:292
UINT32 index
Definition: los_futex_pri.h:79
UINT32 pid
Definition: los_futex_pri.h:80
函数调用图:
这是这个函数的调用关系图:

◆ OsFutexDeleteAlreadyWakeTaskAndGetNext()

STATIC FutexNode * OsFutexDeleteAlreadyWakeTaskAndGetNext ( const FutexNode node,
FutexNode **  headNode,
BOOL  isDeleteHead 
)

这块代码谁写的? 这种命名 ...

在文件 los_futex.c330 行定义.

331{
332 FutexNode *tempNode = (FutexNode *)node;
333 FutexNode *nextNode = NULL;
334 BOOL queueFlag = FALSE;
335
336 while (LOS_ListEmpty(&(tempNode->pendList))) { /* already weak */
337 if (!LOS_ListEmpty(&(tempNode->queueList))) { /* It's not a head node */
338 nextNode = OS_FUTEX_FROM_QUEUELIST(LOS_DL_LIST_FIRST(&(tempNode->queueList)));
339 }
340
341 OsFutexDeleteKeyNodeFromHash(tempNode, isDeleteHead, headNode, &queueFlag);
342 if (queueFlag) {
343 return NULL;
344 }
345
346 tempNode = nextNode;
347 }
348
349 return tempNode;
350}
STATIC VOID OsFutexDeleteKeyNodeFromHash(FutexNode *node, BOOL isDeleteHead, FutexNode **headNode, BOOL *queueFlags)
从哈希桶中删除快锁节点
Definition: los_futex.c:268
size_t BOOL
Definition: los_typedef.h:88
函数调用图:
这是这个函数的调用关系图:

◆ OsFutexDeleteKeyFromFutexList()

STATIC INLINE VOID OsFutexDeleteKeyFromFutexList ( FutexNode node)

将参数节点从futexList上摘除

在文件 los_futex.c263 行定义.

264{
266}
LOS_DL_LIST futexList
Definition: los_futex_pri.h:84
函数调用图:
这是这个函数的调用关系图:

◆ OsFutexDeleteKeyNodeFromHash()

STATIC VOID OsFutexDeleteKeyNodeFromHash ( FutexNode node,
BOOL  isDeleteHead,
FutexNode **  headNode,
BOOL queueFlags 
)

从哈希桶中删除快锁节点

在文件 los_futex.c268 行定义.

269{
270 FutexNode *nextNode = NULL;
271
272 if (node->index >= FUTEX_INDEX_MAX) {
273 return;
274 }
275
276 if (LOS_ListEmpty(&node->queueList)) {//如果没有任务在等锁
277 OsFutexDeleteKeyFromFutexList(node);//从快锁链表上摘除
278 if (queueFlags != NULL) {
279 *queueFlags = TRUE;
280 }
281 goto EXIT;
282 }
283
284 /* FutexList is not NULL, but the header node of queueList */
285 if (node->futexList.pstNext != NULL) {//是头节点
286 if (isDeleteHead == TRUE) {//是否要删除头节点
287 nextNode = OS_FUTEX_FROM_QUEUELIST(LOS_DL_LIST_FIRST(&node->queueList));//取出第一个快锁节点
288 OsFutexReplaceQueueListHeadNode(node, nextNode);//两个节点交换位置
289 if (headNode != NULL) {
290 *headNode = nextNode;
291 }
292 } else {
293 return;
294 }
295 }
296
297EXIT:
299 return;
300}
STATIC INLINE VOID OsFutexDeleteKeyFromFutexList(FutexNode *node)
将参数节点从futexList上摘除
Definition: los_futex.c:263
STATIC INLINE VOID OsFutexReplaceQueueListHeadNode(FutexNode *oldHeadNode, FutexNode *newHeadNode)
新旧两个节点交换 futexList 位置
Definition: los_futex.c:253
struct LOS_DL_LIST * pstNext
Definition: los_list.h:84
函数调用图:
这是这个函数的调用关系图:

◆ OsFutexDeleteTimeoutTaskNode()

STATIC INT32 OsFutexDeleteTimeoutTaskNode ( FutexHash hashNode,
FutexNode node 
)

在文件 los_futex.c587 行定义.

588{
589 UINT32 intSave;
590 if (OsFutexLock(&hashNode->listLock)) {
591 return LOS_EINVAL;
592 }
593
594 if (node->index < FUTEX_INDEX_MAX) {
595 SCHEDULER_LOCK(intSave);
596 (VOID)OsFutexDeleteAlreadyWakeTaskAndGetNext(node, NULL, TRUE);
597 SCHEDULER_UNLOCK(intSave);
598 }
599
600#ifdef LOS_FUTEX_DEBUG
602#endif
603
604 if (OsFutexUnlock(&hashNode->listLock)) {
605 return LOS_EINVAL;
606 }
607 return LOS_ETIMEDOUT;
608}
STATIC INT32 OsFutexLock(LosMux *lock)
对互斥锁封装
Definition: los_futex.c:124
STATIC INT32 OsFutexUnlock(LosMux *lock)
初始化Futex(Fast userspace mutex,用户态快速互斥锁)模块
Definition: los_futex.c:134
VOID OsFutexHashShow(VOID)
Definition: los_futex.c:190
LosMux listLock
内核操作lockList的互斥锁
Definition: los_futex.c:117
函数调用图:
这是这个函数的调用关系图:

◆ OsFutexFlagsToKey()

STATIC INLINE UINTPTR OsFutexFlagsToKey ( const UINT32 userVaddr,
const UINT32  flags 
)

通过用户空间地址获取哈希key

在文件 los_futex.c212 行定义.

213{
214 UINTPTR futexKey;
215
216 if (flags & FUTEX_PRIVATE) {
217 futexKey = (UINTPTR)userVaddr;//私有锁(以虚拟地址进行哈希)
218 } else {
219 futexKey = (UINTPTR)LOS_PaddrQuery((UINT32 *)userVaddr);//共享锁(以物理地址进行哈希)
220 }
221
222 return futexKey;
223}
unsigned long UINTPTR
Definition: los_typedef.h:68
PADDR_T LOS_PaddrQuery(VOID *vaddr)
通过虚拟地址查询映射的物理地址
Definition: los_vm_map.c:550
函数调用图:
这是这个函数的调用关系图:

◆ OsFutexHashShow()

VOID OsFutexHashShow ( VOID  )

在文件 los_futex.c190 行定义.

191{
192 LOS_DL_LIST *futexList = NULL;
193 INT32 count;
194 /* The maximum number of barrels of a hash table */
195 INT32 hashNodeMax = FUTEX_INDEX_MAX;
196 PRINTK("#################### los_futex_pri.hash ####################\n");
197 for (count = 0; count < hashNodeMax; count++) {
198 futexList = &(g_futexHash[count].lockList);
199 if (LOS_ListEmpty(futexList)) {
200 continue;
201 }
202 PRINTK("hash -> index : %d\n", count);
203 for (futexList = futexList->pstNext;
204 futexList != &(g_futexHash[count].lockList);
205 futexList = futexList->pstNext) {
206 OsFutexShowTaskNodeAttr(futexList);
207 }
208 }
209}
FutexHash g_futexHash[FUTEX_INDEX_MAX]
80个哈希桶
Definition: los_futex.c:121
STATIC VOID OsFutexShowTaskNodeAttr(const LOS_DL_LIST *futexList)
Definition: los_futex.c:163
LOS_DL_LIST lockList
用于挂载 FutexNode (Fast userspace mutex,用户态快速互斥锁)
Definition: los_futex.c:118
函数调用图:
这是这个函数的调用关系图:

◆ OsFutexInit()

UINT32 OsFutexInit ( VOID  )

在文件 los_futex.c144 行定义.

145{
146 INT32 count;
147 UINT32 ret;
148 // 初始化 80个哈希桶
149 for (count = 0; count < FUTEX_INDEX_MAX; count++) {
150 LOS_ListInit(&g_futexHash[count].lockList); // 初始化双向链表,上面挂 FutexNode
151 ret = LOS_MuxInit(&(g_futexHash[count].listLock), NULL);//初始化互斥锁
152 if (ret) {
153 return ret;
154 }
155 }
156
157 return LOS_OK;
158}
LITE_OS_SEC_TEXT UINT32 LOS_MuxInit(LosMux *mutex, const LosMuxAttr *attr)
初始化互斥锁
Definition: los_mux.c:262
函数调用图:

◆ OsFutexInsertFindFormBackToFront()

STATIC INT32 OsFutexInsertFindFormBackToFront ( LOS_DL_LIST queueList,
const LosTaskCB runTask,
FutexNode node 
)

在文件 los_futex.c392 行定义.

393{
394 LOS_DL_LIST *listHead = queueList;
395 LOS_DL_LIST *listTail = queueList->pstPrev;
396
397 for (; listHead != listTail; listTail = listTail->pstPrev) {
398 FutexNode *tempNode = OS_FUTEX_FROM_QUEUELIST(listTail);
399 tempNode = OsFutexDeleteAlreadyWakeTaskAndGetNext(tempNode, NULL, FALSE);
400 if (tempNode == NULL) {
401 return LOS_NOK;
402 }
403 LosTaskCB *taskTail = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(tempNode->pendList)));
404 INT32 ret = OsSchedParamCompare(runTask, taskTail);
405 if (ret >= 0) {
406 LOS_ListHeadInsert(&(tempNode->queueList), &(node->queueList));
407 return LOS_OK;
408 } else {
409 if (listTail->pstPrev == listHead) {
410 LOS_ListTailInsert(&(tempNode->queueList), &(node->queueList));
411 return LOS_OK;
412 }
413 }
414 }
415
416 return LOS_NOK;
417}
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_ListHeadInsert(LOS_DL_LIST *list, LOS_DL_LIST *node)
Insert a node to the head of a doubly linked list.
Definition: los_list.h:268
INT32 OsSchedParamCompare(const LosTaskCB *task1, const LosTaskCB *task2)
Definition: los_sched.c:233
struct LOS_DL_LIST * pstPrev
Definition: los_list.h:83
函数调用图:
这是这个函数的调用关系图:

◆ OsFutexInsertFindFromFrontToBack()

STATIC INT32 OsFutexInsertFindFromFrontToBack ( LOS_DL_LIST queueList,
const LosTaskCB runTask,
FutexNode node 
)

在文件 los_futex.c419 行定义.

420{
421 LOS_DL_LIST *listHead = queueList;
422 LOS_DL_LIST *listTail = queueList->pstPrev;
423
424 for (; listHead != listTail; listHead = listHead->pstNext) {
425 FutexNode *tempNode = OS_FUTEX_FROM_QUEUELIST(listHead);
426 tempNode = OsFutexDeleteAlreadyWakeTaskAndGetNext(tempNode, NULL, FALSE);
427 if (tempNode == NULL) {
428 return LOS_NOK;
429 }
430 LosTaskCB *taskHead = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(tempNode->pendList)));
431 /* High priority comes before low priority,
432 * in the case of the same priority, after the current node
433 */
434 INT32 ret = OsSchedParamCompare(runTask, taskHead);
435 if (ret >= 0) {
436 if (listHead->pstNext == listTail) {
437 LOS_ListHeadInsert(&(tempNode->queueList), &(node->queueList));
438 return LOS_OK;
439 }
440 continue;
441 } else {
442 LOS_ListTailInsert(&(tempNode->queueList), &(node->queueList));
443 return LOS_OK;
444 }
445 }
446
447 return LOS_NOK;
448}
函数调用图:
这是这个函数的调用关系图:

◆ OsFutexInsertNewFutexKeyToHash()

STATIC VOID OsFutexInsertNewFutexKeyToHash ( FutexNode node)

插入一把新Futex锁到哈希桶中,只有是新的key时才会插入,因为其实存在多个FutexNode是一个key

从后往前插入快锁 Form写错了 @note_thinking

在文件 los_futex.c352 行定义.

函数调用图:
这是这个函数的调用关系图:

◆ OsFutexInsertTaskToHash()

STATIC INT32 OsFutexInsertTaskToHash ( LosTaskCB **  taskCB,
FutexNode **  node,
const UINTPTR  futexKey,
const UINT32  flags 
)

将快锁节点插入任务

在文件 los_futex.c610 行定义.

611{
612 INT32 ret;
613 *taskCB = OsCurrTaskGet(); //获取当前任务
614 *node = &((*taskCB)->futex); //获取当前任务的快锁节点
615 OsFutexSetKey(futexKey, flags, *node);//设置参数 key index pid
616
617 ret = OsFindAndInsertToHash(*node);
618 if (ret) {
619 return LOS_NOK;
620 }
621
622 LOS_ListInit(&((*node)->pendList));
623 return LOS_OK;
624}
STATIC INLINE VOID OsFutexSetKey(UINTPTR futexKey, UINT32 flags, FutexNode *node)
设置快锁哈希key
Definition: los_futex.c:239
STATIC INT32 OsFindAndInsertToHash(FutexNode *node)
Definition: los_futex.c:516
函数调用图:
这是这个函数的调用关系图:

◆ OsFutexInsertTasktoPendList()

STATIC INT32 OsFutexInsertTasktoPendList ( FutexNode **  firstNode,
FutexNode node,
const LosTaskCB run 
)

在文件 los_futex.c468 行定义.

469{
470 LosTaskCB *taskHead = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&((*firstNode)->pendList)));//获取阻塞链表首个任务
471 LOS_DL_LIST *queueList = &((*firstNode)->queueList);
472
473 INT32 ret1 = OsSchedParamCompare(run, taskHead);
474 if (ret1 < 0) {
475 /* The one with the highest priority is inserted at the top of the queue */
476 LOS_ListTailInsert(queueList, &(node->queueList));//查到queueList的尾部
477 OsFutexReplaceQueueListHeadNode(*firstNode, node);//同时交换futexList链表上的位置
478 *firstNode = node;
479 return LOS_OK;
480 }
481 //如果等锁链表上没有任务或者当前任务大于链表首个任务
482 if (LOS_ListEmpty(queueList) && (ret1 >= 0)) {
483 /* Insert the next position in the queue with equal priority */
484 LOS_ListHeadInsert(queueList, &(node->queueList));//从头部插入当前任务,当前任务是要被挂起的
485 return LOS_OK;
486 }
487
488 FutexNode *tailNode = OS_FUTEX_FROM_QUEUELIST(LOS_DL_LIST_LAST(queueList));//获取尾部节点
489 LosTaskCB *taskTail = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(tailNode->pendList)));//获取阻塞任务的最后一个
490 INT32 ret2 = OsSchedParamCompare(taskTail, run);
491 if ((ret2 <= 0) || (ret1 > ret2)) {
492 return OsFutexInsertFindFormBackToFront(queueList, run, node);//从后往前插入
493 }
494
495 return OsFutexInsertFindFromFrontToBack(queueList, run, node);//否则从前往后插入
496}
STATIC INT32 OsFutexInsertFindFromFrontToBack(LOS_DL_LIST *queueList, const LosTaskCB *runTask, FutexNode *node)
Definition: los_futex.c:419
STATIC INT32 OsFutexInsertFindFormBackToFront(LOS_DL_LIST *queueList, const LosTaskCB *runTask, FutexNode *node)
Definition: los_futex.c:392
函数调用图:
这是这个函数的调用关系图:

◆ OsFutexKeyShmPermCheck()

STATIC INT32 OsFutexKeyShmPermCheck ( const UINT32 userVaddr,
const UINT32  flags 
)

共享内存检查

在文件 los_futex.c544 行定义.

545{
546 PADDR_T paddr;
547
548 /* Check whether the futexKey is a shared lock */
549 if (!(flags & FUTEX_PRIVATE)) {//非私有快锁
550 paddr = (UINTPTR)LOS_PaddrQuery((UINT32 *)userVaddr);//能否查询到物理地址
551 if (paddr == 0) return LOS_NOK;
552 }
553
554 return LOS_OK;
555}
unsigned long PADDR_T
Definition: los_typedef.h:207
函数调用图:
这是这个函数的调用关系图:

◆ OsFutexKeyToIndex()

STATIC INLINE UINT32 OsFutexKeyToIndex ( const UINTPTR  futexKey,
const UINT32  flags 
)

通过哈希key获取索引

在文件 los_futex.c225 行定义.

226{
227 UINT32 index = LOS_HashFNV32aBuf(&futexKey, sizeof(UINTPTR), FNV1_32A_INIT);//获取哈希桶索引
228
229 if (flags & FUTEX_PRIVATE) {
230 index &= FUTEX_HASH_PRIVATE_MASK;//将index锁定在 0 ~ 63号
231 } else {
232 index &= FUTEX_HASH_SHARED_MASK;
233 index += FUTEX_INDEX_SHARED_POS;//共享锁索引,将index锁定在 64 ~ 79号
234 }
235
236 return index;
237}
LITE_OS_SEC_ALW_INLINE STATIC INLINE UINT32 LOS_HashFNV32aBuf(const VOID *buf, size_t len, UINT32 hval)
Definition: los_hash.h:79
函数调用图:
这是这个函数的调用关系图:

◆ OsFutexLock()

STATIC INT32 OsFutexLock ( LosMux lock)

对互斥锁封装

在文件 los_futex.c124 行定义.

125{
126 UINT32 ret = LOS_MuxLock(lock, LOS_WAIT_FOREVER);
127 if (ret != LOS_OK) {
128 PRINT_ERR("Futex lock failed! ERROR: 0x%x!\n", ret);
129 return LOS_EINVAL;
130 }
131 return LOS_OK;
132}
LITE_OS_SEC_TEXT UINT32 LOS_MuxLock(LosMux *mutex, UINT32 timeout)
拿互斥锁,
Definition: los_mux.c:437
函数调用图:
这是这个函数的调用关系图:

◆ OsFutexNodeDeleteFromFutexHash()

VOID OsFutexNodeDeleteFromFutexHash ( FutexNode node,
BOOL  isDeleteHead,
FutexNode **  headNode,
BOOL queueFlags 
)

从哈希桶上删除快锁

在文件 los_futex.c302 行定义.

303{
304 FutexHash *hashNode = NULL;
305 //通过key找到桶号
306 UINT32 index = OsFutexKeyToIndex(node->key, (node->pid == OS_INVALID) ? 0 : FUTEX_PRIVATE);
307 if (index >= FUTEX_INDEX_MAX) {
308 return;
309 }
310
311 hashNode = &g_futexHash[index];//找到hash桶
312 if (OsMuxLockUnsafe(&hashNode->listLock, LOS_WAIT_FOREVER)) {
313 return;
314 }
315
316 if (node->index != index) {//快锁节点桶号需和哈希桶号一致
317 goto EXIT;
318 }
319
320 OsFutexDeleteKeyNodeFromHash(node, isDeleteHead, headNode, queueFlags);
321
322EXIT:
323 if (OsMuxUnlockUnsafe(OsCurrTaskGet(), &hashNode->listLock, NULL)) {
324 return;
325 }
326
327 return;
328}
STATIC INLINE UINT32 OsFutexKeyToIndex(const UINTPTR futexKey, const UINT32 flags)
通过哈希key获取索引
Definition: los_futex.c:225
UINT32 OsMuxLockUnsafe(LosMux *mutex, UINT32 timeout)
Definition: los_mux.c:398
UINT32 OsMuxUnlockUnsafe(LosTaskCB *taskCB, LosMux *mutex, BOOL *needSched)
Definition: los_mux.c:527
单独哈希桶,上面挂了一个个 FutexNode
Definition: los_futex.c:116
UINTPTR key
Definition: los_futex_pri.h:78
函数调用图:
这是这个函数的调用关系图:

◆ OsFutexRecycleAndFindHeadNode()

STATIC INT32 OsFutexRecycleAndFindHeadNode ( FutexNode headNode,
FutexNode node,
FutexNode **  firstNode 
)

将快锁挂到任务的阻塞链表上

在文件 los_futex.c450 行定义.

函数调用图:
这是这个函数的调用关系图:

◆ OsFutexReplaceQueueListHeadNode()

STATIC INLINE VOID OsFutexReplaceQueueListHeadNode ( FutexNode oldHeadNode,
FutexNode newHeadNode 
)

新旧两个节点交换 futexList 位置

在文件 los_futex.c253 行定义.

254{
255 LOS_DL_LIST *futexList = oldHeadNode->futexList.pstPrev;
256 LOS_ListDelete(&oldHeadNode->futexList);//将旧节点从futexList链表上摘除
257 LOS_ListHeadInsert(futexList, &newHeadNode->futexList);//将新节点从头部插入futexList链表
258 if ((newHeadNode->queueList.pstNext == NULL) || (newHeadNode->queueList.pstPrev == NULL)) {//新节点前后没有等待这把锁的任务
259 LOS_ListInit(&newHeadNode->queueList);//初始化等锁任务链表
260 }
261}
函数调用图:
这是这个函数的调用关系图:

◆ OsFutexRequeue()

INT32 OsFutexRequeue ( const UINT32 userVaddr,
UINT32  flags,
INT32  wakeNumber,
INT32  count,
const UINT32 newUserVaddr 
)

调整指定锁在Futex表中的位置

在文件 los_futex.c1022 行定义.

1023{
1024 INT32 ret;
1025 UINTPTR oldFutexKey;
1026 UINTPTR newFutexKey;
1027 INT32 oldIndex;
1028 INT32 newIndex;
1029 FutexHash *oldHashNode = NULL;
1030 FutexHash *newHashNode = NULL;
1031 FutexNode *oldHeadNode = NULL;
1032 BOOL wakeAny = FALSE;
1033
1034 if (OsFutexRequeueParamCheck(userVaddr, flags, newUserVaddr)) {
1035 return LOS_EINVAL;
1036 }
1037
1038 oldFutexKey = OsFutexFlagsToKey(userVaddr, flags);//先拿key
1039 newFutexKey = OsFutexFlagsToKey(newUserVaddr, flags);
1040 oldIndex = OsFutexKeyToIndex(oldFutexKey, flags);//再拿所在哈希桶位置,共有80个哈希桶
1041 newIndex = OsFutexKeyToIndex(newFutexKey, flags);
1042
1043 oldHashNode = &g_futexHash[oldIndex];//拿到对应哈希桶实体
1044 if (OsFutexLock(&oldHashNode->listLock)) {
1045 return LOS_EINVAL;
1046 }
1047
1048 oldHeadNode = OsFutexRequeueRemoveOldKeyAndGetHead(oldFutexKey, flags, wakeNumber, newFutexKey, count, &wakeAny);
1049 if (oldHeadNode == NULL) {
1050 (VOID)OsFutexUnlock(&oldHashNode->listLock);
1051 if (wakeAny == TRUE) {
1052 ret = LOS_OK;
1053 goto EXIT;
1054 }
1055 return LOS_EBADF;
1056 }
1057
1058 newHashNode = &g_futexHash[newIndex];
1059 if (oldIndex != newIndex) {
1060 if (OsFutexUnlock(&oldHashNode->listLock)) {
1061 return LOS_EINVAL;
1062 }
1063
1064 if (OsFutexLock(&newHashNode->listLock)) {
1065 return LOS_EINVAL;
1066 }
1067 }
1068
1069 ret = OsFutexRequeueInsertNewKey(newFutexKey, newIndex, oldHeadNode);
1070
1071 if (OsFutexUnlock(&newHashNode->listLock)) {
1072 return LOS_EINVAL;
1073 }
1074
1075EXIT:
1076 if (wakeAny == TRUE) {
1077 LOS_MpSchedule(OS_MP_CPU_ALL);
1078 LOS_Schedule();
1079 }
1080
1081 return ret;
1082}
VOID LOS_Schedule(VOID)
Trigger active task scheduling.
Definition: los_sched.c:469
STATIC INLINE UINTPTR OsFutexFlagsToKey(const UINT32 *userVaddr, const UINT32 flags)
通过用户空间地址获取哈希key
Definition: los_futex.c:212
STATIC INT32 OsFutexRequeueInsertNewKey(UINTPTR newFutexKey, INT32 newIndex, FutexNode *oldHeadNode)
Definition: los_futex.c:866
STATIC FutexNode * OsFutexRequeueRemoveOldKeyAndGetHead(UINTPTR oldFutexKey, UINT32 flags, INT32 wakeNumber, UINTPTR newFutexKey, INT32 requeueCount, BOOL *wakeAny)
删除旧key并获取头节点
Definition: los_futex.c:959
STATIC INT32 OsFutexRequeueParamCheck(const UINT32 *oldUserVaddr, UINT32 flags, const UINT32 *newUserVaddr)
检查锁在Futex表中的状态
Definition: los_futex.c:995
VOID LOS_MpSchedule(UINT32 target)
Definition: los_mp.c:76
函数调用图:
这是这个函数的调用关系图:

◆ OsFutexRequeueInsertNewKey()

STATIC INT32 OsFutexRequeueInsertNewKey ( UINTPTR  newFutexKey,
INT32  newIndex,
FutexNode oldHeadNode 
)

在文件 los_futex.c866 行定义.

867{
868 BOOL queueListIsEmpty = FALSE;
869 INT32 ret;
870 UINT32 intSave;
871 LosTaskCB *task = NULL;
872 FutexNode *nextNode = NULL;
873 FutexNode newTempNode = {
874 .key = newFutexKey,
875 .index = newIndex,
876 .pid = (newIndex < FUTEX_INDEX_SHARED_POS) ? LOS_GetCurrProcessID() : OS_INVALID,
877 };
878 LOS_DL_LIST *queueList = &oldHeadNode->queueList;
879 FutexNode *newHeadNode = OsFindFutexNode(&newTempNode);
880 if (newHeadNode == NULL) {
882 return LOS_OK;
883 }
884
885 do {
886 nextNode = OS_FUTEX_FROM_QUEUELIST(queueList);
887 SCHEDULER_LOCK(intSave);
888 if (LOS_ListEmpty(&nextNode->pendList)) {
889 if (LOS_ListEmpty(queueList)) {
890 queueListIsEmpty = TRUE;
891 } else {
892 queueList = queueList->pstNext;
893 }
894 OsFutexDeinitFutexNode(nextNode);
895 SCHEDULER_UNLOCK(intSave);
896 if (queueListIsEmpty) {
897 return LOS_OK;
898 }
899
900 continue;
901 }
902
903 task = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(nextNode->pendList)));
904 if (LOS_ListEmpty(queueList)) {
905 queueListIsEmpty = TRUE;
906 } else {
907 queueList = queueList->pstNext;
908 }
909 LOS_ListDelete(&nextNode->queueList);
910 ret = OsFutexInsertTasktoPendList(&newHeadNode, nextNode, task);
911 SCHEDULER_UNLOCK(intSave);
912 if (ret != LOS_OK) {
913 PRINT_ERR("Futex requeue insert new key failed!\n");
914 }
915 } while (!queueListIsEmpty);
916
917 return LOS_OK;
918}
LITE_OS_SEC_TEXT UINT32 LOS_GetCurrProcessID(VOID)
获取当前进程的进程ID
Definition: los_process.c:2161
函数调用图:
这是这个函数的调用关系图:

◆ OsFutexRequeueParamCheck()

STATIC INT32 OsFutexRequeueParamCheck ( const UINT32 oldUserVaddr,
UINT32  flags,
const UINT32 newUserVaddr 
)

检查锁在Futex表中的状态

在文件 los_futex.c995 行定义.

996{
997 VADDR_T oldVaddr = (VADDR_T)(UINTPTR)oldUserVaddr;
998 VADDR_T newVaddr = (VADDR_T)(UINTPTR)newUserVaddr;
999
1000 if (oldVaddr == newVaddr) {
1001 return LOS_EINVAL;
1002 }
1003 //检查标记
1004 if ((flags & (~FUTEX_PRIVATE)) != FUTEX_REQUEUE) {
1005 PRINT_ERR("Futex requeue param check failed! error flags: 0x%x\n", flags);
1006 return LOS_EINVAL;
1007 }
1008 //检查地址范围,必须在用户空间
1009 if ((oldVaddr % sizeof(INT32)) || (oldVaddr < OS_FUTEX_KEY_BASE) || (oldVaddr >= OS_FUTEX_KEY_MAX)) {
1010 PRINT_ERR("Futex requeue param check failed! error old userVaddr: 0x%x\n", oldUserVaddr);
1011 return LOS_EINVAL;
1012 }
1013
1014 if ((newVaddr % sizeof(INT32)) || (newVaddr < OS_FUTEX_KEY_BASE) || (newVaddr >= OS_FUTEX_KEY_MAX)) {
1015 PRINT_ERR("Futex requeue param check failed! error new userVaddr: 0x%x\n", newUserVaddr);
1016 return LOS_EINVAL;
1017 }
1018
1019 return LOS_OK;
1020}
unsigned long VADDR_T
Definition: los_typedef.h:208
这是这个函数的调用关系图:

◆ OsFutexRequeueRemoveOldKeyAndGetHead()

STATIC FutexNode * OsFutexRequeueRemoveOldKeyAndGetHead ( UINTPTR  oldFutexKey,
UINT32  flags,
INT32  wakeNumber,
UINTPTR  newFutexKey,
INT32  requeueCount,
BOOL wakeAny 
)

删除旧key并获取头节点

在文件 los_futex.c959 行定义.

961{
962 INT32 ret;
963 INT32 oldIndex = OsFutexKeyToIndex(oldFutexKey, flags);
964 FutexNode *oldHeadNode = NULL;
965 FutexHash *oldHashNode = &g_futexHash[oldIndex];
966 FutexNode oldTempNode = {
967 .key = oldFutexKey,
968 .index = oldIndex,
969 .pid = (flags & FUTEX_PRIVATE) ? LOS_GetCurrProcessID() : OS_INVALID,
970 };
971
972 if (wakeNumber > 0) {
973 ret = OsFutexWakeTask(oldFutexKey, flags, wakeNumber, &oldHeadNode, wakeAny);
974 if ((ret != LOS_OK) || (oldHeadNode == NULL)) {
975 return NULL;
976 }
977 }
978
979 if (requeueCount <= 0) {
980 return NULL;
981 }
982
983 if (oldHeadNode == NULL) {
984 oldHeadNode = OsFindFutexNode(&oldTempNode);
985 if (oldHeadNode == NULL) {
986 return NULL;
987 }
988 }
989
990 OsFutexRequeueSplitTwoLists(oldHashNode, oldHeadNode, flags, newFutexKey, requeueCount);
991
992 return oldHeadNode;
993}
STATIC INT32 OsFutexWakeTask(UINTPTR futexKey, UINT32 flags, INT32 wakeNumber, FutexNode **newHeadNode, BOOL *wakeAny)
OsFutexWakeTask 唤醒任务
Definition: los_futex.c:781
STATIC VOID OsFutexRequeueSplitTwoLists(FutexHash *oldHashNode, FutexNode *oldHeadNode, UINT32 flags, UINTPTR futexKey, INT32 count)
Definition: los_futex.c:920
函数调用图:
这是这个函数的调用关系图:

◆ OsFutexRequeueSplitTwoLists()

STATIC VOID OsFutexRequeueSplitTwoLists ( FutexHash oldHashNode,
FutexNode oldHeadNode,
UINT32  flags,
UINTPTR  futexKey,
INT32  count 
)

在文件 los_futex.c920 行定义.

922{
923 LOS_DL_LIST *queueList = &oldHeadNode->queueList;
924 FutexNode *tailNode = OS_FUTEX_FROM_QUEUELIST(LOS_DL_LIST_LAST(queueList));
925 INT32 newIndex = OsFutexKeyToIndex(futexKey, flags);
926 FutexNode *nextNode = NULL;
927 FutexNode *newHeadNode = NULL;
928 LOS_DL_LIST *futexList = NULL;
929 BOOL isAll = FALSE;
930 INT32 i;
931
932 for (i = 0; i < count; i++) {
933 nextNode = OS_FUTEX_FROM_QUEUELIST(queueList);
934 nextNode->key = futexKey;
935 nextNode->index = newIndex;
936 if (queueList->pstNext == &oldHeadNode->queueList) {
937 isAll = TRUE;
938 break;
939 }
940
941 queueList = queueList->pstNext;
942 }
943
944 futexList = oldHeadNode->futexList.pstPrev;
945 LOS_ListDelete(&oldHeadNode->futexList);
946 if (isAll == TRUE) {
947 return;
948 }
949
950 newHeadNode = OS_FUTEX_FROM_QUEUELIST(queueList);
951 LOS_ListHeadInsert(futexList, &newHeadNode->futexList);
952 oldHeadNode->queueList.pstPrev = &nextNode->queueList;
953 nextNode->queueList.pstNext = &oldHeadNode->queueList;
954 newHeadNode->queueList.pstPrev = &tailNode->queueList;
955 tailNode->queueList.pstNext = &newHeadNode->queueList;
956 return;
957}
函数调用图:
这是这个函数的调用关系图:

◆ OsFutexSetKey()

STATIC INLINE VOID OsFutexSetKey ( UINTPTR  futexKey,
UINT32  flags,
FutexNode node 
)

设置快锁哈希key

在文件 los_futex.c239 行定义.

240{
241 node->key = futexKey;//哈希key
242 node->index = OsFutexKeyToIndex(futexKey, flags);//哈希桶索引
243 node->pid = (flags & FUTEX_PRIVATE) ? LOS_GetCurrProcessID() : OS_INVALID;//获取进程ID,共享快锁时 快锁节点没有进程ID
244}
函数调用图:
这是这个函数的调用关系图:

◆ OsFutexShowTaskNodeAttr()

STATIC VOID OsFutexShowTaskNodeAttr ( const LOS_DL_LIST futexList)

在文件 los_futex.c163 行定义.

164{
165 FutexNode *tempNode = NULL;
166 FutexNode *lastNode = NULL;
167 LosTaskCB *taskCB = NULL;
168 LOS_DL_LIST *queueList = NULL;
169
170 tempNode = OS_FUTEX_FROM_FUTEXLIST(futexList);
171 PRINTK("key(pid) : 0x%x(%u) : ->", tempNode->key, tempNode->pid);
172
173 for (queueList = &tempNode->queueList; ;) {
174 lastNode = OS_FUTEX_FROM_QUEUELIST(queueList);
175 if (!LOS_ListEmpty(&(lastNode->pendList))) {
176 taskCB = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(lastNode->pendList)));
177 PRINTK(" %u ->", taskCB->taskID);
178 } else {
179 taskCB = LOS_DL_LIST_ENTRY(lastNode, LosTaskCB, futex);
180 PRINTK(" %u ->", taskCB->taskID);
181 }
182 queueList = queueList->pstNext;
183 if (queueList == &tempNode->queueList) {
184 break;
185 }
186 }
187 PRINTK("\n");
188}
UINT32 taskID
函数调用图:
这是这个函数的调用关系图:

◆ OsFutexUnlock()

STATIC INT32 OsFutexUnlock ( LosMux lock)

初始化Futex(Fast userspace mutex,用户态快速互斥锁)模块

在文件 los_futex.c134 行定义.

函数调用图:
这是这个函数的调用关系图:

◆ OsFutexWait()

INT32 OsFutexWait ( const UINT32 userVaddr,
UINT32  flags,
UINT32  val,
UINT32  absTime 
)

设置线程等待 | 向Futex表中插入代表被阻塞的线程的node

在文件 los_futex.c693 行定义.

694{
695 INT32 ret;
696 UINT32 timeout = LOS_WAIT_FOREVER;
697
698 ret = OsFutexWaitParamCheck(userVaddr, flags, absTime);//参数检查
699 if (ret) {
700 return ret;
701 }
702 if (absTime != LOS_WAIT_FOREVER) {//转换时间 , 内核的时间单位是 tick
703 timeout = OsNS2Tick((UINT64)absTime * OS_SYS_NS_PER_US); //转成 tick
704 }
705
706 return OsFutexWaitTask(userVaddr, flags, val, timeout);//将任务挂起 timeOut 时长
707}
LITE_OS_SEC_TEXT_MINOR UINT32 OsNS2Tick(UINT64 nanoseconds)
纳秒转化成 tick
Definition: los_sys.c:125
STATIC INT32 OsFutexWaitParamCheck(const UINT32 *userVaddr, UINT32 flags, UINT32 absTime)
Definition: los_futex.c:557
STATIC INT32 OsFutexWaitTask(const UINT32 *userVaddr, const UINT32 flags, const UINT32 val, const UINT32 timeout)
将当前任务挂入等待链表中
Definition: los_futex.c:626
long unsigned int UINT64
Definition: los_typedef.h:66
函数调用图:
这是这个函数的调用关系图:

◆ OsFutexWaitParamCheck()

STATIC INT32 OsFutexWaitParamCheck ( const UINT32 userVaddr,
UINT32  flags,
UINT32  absTime 
)

在文件 los_futex.c557 行定义.

558{
559 VADDR_T vaddr = (VADDR_T)(UINTPTR)userVaddr;
560
561 if (OS_INT_ACTIVE) {
562 return LOS_EINTR;
563 }
564
565 if (flags & (~FUTEX_PRIVATE)) {
566 PRINT_ERR("Futex wait param check failed! error flags: 0x%x\n", flags);
567 return LOS_EINVAL;
568 }
569
570 if ((vaddr % sizeof(INT32)) || (vaddr < OS_FUTEX_KEY_BASE) || (vaddr >= OS_FUTEX_KEY_MAX)) {
571 PRINT_ERR("Futex wait param check failed! error userVaddr: 0x%x\n", vaddr);
572 return LOS_EINVAL;
573 }
574
575 if (flags && (OsFutexKeyShmPermCheck(userVaddr, flags) != LOS_OK)) {
576 PRINT_ERR("Futex wait param check failed! error shared memory perm userVaddr: 0x%x\n", userVaddr);
577 return LOS_EINVAL;
578 }
579
580 if (!absTime) {
581 return LOS_ETIMEDOUT;
582 }
583
584 return LOS_OK;
585}
STATIC INT32 OsFutexKeyShmPermCheck(const UINT32 *userVaddr, const UINT32 flags)
共享内存检查
Definition: los_futex.c:544
函数调用图:
这是这个函数的调用关系图:

◆ OsFutexWaitTask()

STATIC INT32 OsFutexWaitTask ( const UINT32 userVaddr,
const UINT32  flags,
const UINT32  val,
const UINT32  timeout 
)

将当前任务挂入等待链表中

在文件 los_futex.c626 行定义.

627{
628 INT32 futexRet;
629 UINT32 intSave, lockVal;
630 LosTaskCB *taskCB = NULL;
631 FutexNode *node = NULL;
632 UINTPTR futexKey = OsFutexFlagsToKey(userVaddr, flags);//通过地址和flags 找到 key
633 UINT32 index = OsFutexKeyToIndex(futexKey, flags);//通过key找到哈希桶
634 FutexHash *hashNode = &g_futexHash[index];
635
636 if (OsFutexLock(&hashNode->listLock)) {//操作快锁节点链表前先上互斥锁
637 return LOS_EINVAL;
638 }
639 //userVaddr必须是用户空间虚拟地址
640 if (LOS_ArchCopyFromUser(&lockVal, userVaddr, sizeof(UINT32))) {//将值拷贝到内核空间
641 PRINT_ERR("Futex wait param check failed! copy from user failed!\n");
642 futexRet = LOS_EINVAL;
643 goto EXIT_ERR;
644 }
645
646 if (lockVal != val) {//对参数内部逻辑检查
647 futexRet = LOS_EBADF;
648 goto EXIT_ERR;
649 }
650 //注意第二个参数 FutexNode *node = NULL
651 if (OsFutexInsertTaskToHash(&taskCB, &node, futexKey, flags)) {// node = taskCB->futex
652 futexRet = LOS_NOK;
653 goto EXIT_ERR;
654 }
655
656 SCHEDULER_LOCK(intSave);
657 OsSchedLock();
658 OsTaskWaitSetPendMask(OS_TASK_WAIT_FUTEX, futexKey, timeout);
659 taskCB->ops->wait(taskCB, &(node->pendList), timeout);
661
662 futexRet = OsFutexUnlock(&hashNode->listLock);//
663 if (futexRet) {
665 LOS_IntRestore(intSave);
666 goto EXIT_UNLOCK_ERR;
667 }
668
671
672 /*
673 * it will immediately do the scheduling, so there's no need to release the
674 * task spinlock. when this task's been rescheduled, it will be holding the spinlock.
675 */
677
678 if (taskCB->taskStatus & OS_TASK_STATUS_TIMEOUT) {
679 taskCB->taskStatus &= ~OS_TASK_STATUS_TIMEOUT;
680 SCHEDULER_UNLOCK(intSave);
681 return OsFutexDeleteTimeoutTaskNode(hashNode, node);
682 }
683
684 SCHEDULER_UNLOCK(intSave);
685 return LOS_OK;
686
687EXIT_ERR:
688 (VOID)OsFutexUnlock(&hashNode->listLock);
689EXIT_UNLOCK_ERR:
690 return futexRet;
691}
STATIC INLINE VOID LOS_IntRestore(UINT32 intSave)
Restore interrupts. | 恢复到使用LOS_IntLock关闭所有中断之前的状态
Definition: los_hwi.h:337
STATIC INT32 OsFutexDeleteTimeoutTaskNode(FutexHash *hashNode, FutexNode *node)
Definition: los_futex.c:587
STATIC INT32 OsFutexInsertTaskToHash(LosTaskCB **taskCB, FutexNode **node, const UINTPTR futexKey, const UINT32 flags)
将快锁节点插入任务
Definition: los_futex.c:610
STATIC INLINE VOID OsSchedUnlock(VOID)
STATIC INLINE VOID OsSchedLock(VOID)
VOID OsSchedResched(VOID)
Definition: los_sched.c:449
VOID LOS_SpinLock(SPIN_LOCK_S *lock)
Definition: los_spinlock.c:50
VOID LOS_SpinUnlock(SPIN_LOCK_S *lock)
Definition: los_spinlock.c:84
STATIC INLINE VOID OsTaskWaitSetPendMask(UINT16 mask, UINTPTR lockID, UINT32 timeout)
设置事件阻塞掩码,即设置任务的等待事件.
Definition: los_task_pri.h:289
SPIN_LOCK_S g_taskSpin
UINT32(* wait)(LosTaskCB *runTask, LOS_DL_LIST *list, UINT32 timeout)
任务等待
UINT16 taskStatus
size_t LOS_ArchCopyFromUser(void *dst, const void *src, size_t len)
Definition: user_copy.c:58
函数调用图:
这是这个函数的调用关系图:

◆ OsFutexWake()

INT32 OsFutexWake ( const UINT32 userVaddr,
UINT32  flags,
INT32  wakeNumber 
)

唤醒一个被指定锁阻塞的线程

在文件 los_futex.c815 行定义.

816{
817 INT32 ret, futexRet;
818 UINTPTR futexKey;
819 UINT32 index;
820 FutexHash *hashNode = NULL;
821 FutexNode *headNode = NULL;
822 BOOL wakeAny = FALSE;
823 //1.检查参数
824 if (OsFutexWakeParamCheck(userVaddr, flags)) {
825 return LOS_EINVAL;
826 }
827 //2.找到指定用户空间地址对应的桶
828 futexKey = OsFutexFlagsToKey(userVaddr, flags);
829 index = OsFutexKeyToIndex(futexKey, flags);
830
831 hashNode = &g_futexHash[index];
832 if (OsFutexLock(&hashNode->listLock)) {
833 return LOS_EINVAL;
834 }
835 //3.换起等待该锁的进程
836 ret = OsFutexWakeTask(futexKey, flags, wakeNumber, &headNode, &wakeAny);
837 if (ret) {
838 goto EXIT_ERR;
839 }
840
841#ifdef LOS_FUTEX_DEBUG
843#endif
844
845 futexRet = OsFutexUnlock(&hashNode->listLock);
846 if (futexRet) {
847 goto EXIT_UNLOCK_ERR;
848 }
849 //4.根据指定参数决定是否发起调度
850 if (wakeAny == TRUE) {
851 LOS_MpSchedule(OS_MP_CPU_ALL);
852 LOS_Schedule();
853 }
854
855 return LOS_OK;
856
857EXIT_ERR:
858 futexRet = OsFutexUnlock(&hashNode->listLock);
859EXIT_UNLOCK_ERR:
860 if (futexRet) {
861 return futexRet;
862 }
863 return ret;
864}
STATIC INT32 OsFutexWakeParamCheck(const UINT32 *userVaddr, UINT32 flags)
Definition: los_futex.c:709
函数调用图:
这是这个函数的调用关系图:

◆ OsFutexWakeParamCheck()

STATIC INT32 OsFutexWakeParamCheck ( const UINT32 userVaddr,
UINT32  flags 
)

在文件 los_futex.c709 行定义.

710{
711 VADDR_T vaddr = (VADDR_T)(UINTPTR)userVaddr;
712
713 if ((flags & (~FUTEX_PRIVATE)) != FUTEX_WAKE) {
714 PRINT_ERR("Futex wake param check failed! error flags: 0x%x\n", flags);
715 return LOS_EINVAL;
716 }
717 //地址必须在用户空间
718 if ((vaddr % sizeof(INT32)) || (vaddr < OS_FUTEX_KEY_BASE) || (vaddr >= OS_FUTEX_KEY_MAX)) {
719 PRINT_ERR("Futex wake param check failed! error userVaddr: 0x%x\n", userVaddr);
720 return LOS_EINVAL;
721 }
722 //必须得是个共享内存地址
723 if (flags && (OsFutexKeyShmPermCheck(userVaddr, flags) != LOS_OK)) {
724 PRINT_ERR("Futex wake param check failed! error shared memory perm userVaddr: 0x%x\n", userVaddr);
725 return LOS_EINVAL;
726 }
727
728 return LOS_OK;
729}
函数调用图:
这是这个函数的调用关系图:

◆ OsFutexWakeTask()

STATIC INT32 OsFutexWakeTask ( UINTPTR  futexKey,
UINT32  flags,
INT32  wakeNumber,
FutexNode **  newHeadNode,
BOOL wakeAny 
)

OsFutexWakeTask 唤醒任务

参数
flags
futexKey
newHeadNode
wakeAny
wakeNumber唤醒数量
返回
参见

在文件 los_futex.c781 行定义.

782{
783 UINT32 intSave;
784 FutexNode *node = NULL;
785 FutexNode *headNode = NULL;
786 UINT32 index = OsFutexKeyToIndex(futexKey, flags);
787 FutexHash *hashNode = &g_futexHash[index];
788 FutexNode tempNode = { //先组成一个临时快锁节点,目的是为了找到哈希桶中是否有这个节点
789 .key = futexKey,
790 .index = index,
791 .pid = (flags & FUTEX_PRIVATE) ? LOS_GetCurrProcessID() : OS_INVALID,
792 };
793
794 node = OsFindFutexNode(&tempNode);//找快锁节点
795 if (node == NULL) {
796 return LOS_EBADF;
797 }
798
799 headNode = node;
800
801 SCHEDULER_LOCK(intSave);
802 OsFutexCheckAndWakePendTask(headNode, wakeNumber, hashNode, newHeadNode, wakeAny);//再找到等这把锁的唤醒指向数量的任务
803 if ((*newHeadNode) != NULL) {
804 OsFutexReplaceQueueListHeadNode(headNode, *newHeadNode);
805 OsFutexDeinitFutexNode(headNode);
806 } else if (headNode->index < FUTEX_INDEX_MAX) {
808 OsFutexDeinitFutexNode(headNode);
809 }
810 SCHEDULER_UNLOCK(intSave);
811
812 return LOS_OK;
813}
STATIC VOID OsFutexCheckAndWakePendTask(FutexNode *headNode, const INT32 wakeNumber, FutexHash *hashNode, FutexNode **nextNode, BOOL *wakeAny)
Definition: los_futex.c:735
函数调用图:
这是这个函数的调用关系图:

变量说明

◆ g_futexHash

FutexHash g_futexHash[FUTEX_INDEX_MAX]

80个哈希桶

在文件 los_futex.c121 行定义.