98#ifdef LOSCFG_KERNEL_VM
100#define OS_FUTEX_FROM_FUTEXLIST(ptr) LOS_DL_LIST_ENTRY(ptr, FutexNode, futexList)
101#define OS_FUTEX_FROM_QUEUELIST(ptr) LOS_DL_LIST_ENTRY(ptr, FutexNode, queueList)
102#define OS_FUTEX_KEY_BASE USER_ASPACE_BASE
103#define OS_FUTEX_KEY_MAX (USER_ASPACE_BASE + USER_ASPACE_SIZE)
107#define FUTEX_INDEX_PRIVATE_MAX 64
109#define FUTEX_INDEX_SHARED_MAX 16
110#define FUTEX_INDEX_MAX (FUTEX_INDEX_PRIVATE_MAX + FUTEX_INDEX_SHARED_MAX)
112#define FUTEX_INDEX_SHARED_POS FUTEX_INDEX_PRIVATE_MAX
113#define FUTEX_HASH_PRIVATE_MASK (FUTEX_INDEX_PRIVATE_MAX - 1)
114#define FUTEX_HASH_SHARED_MASK (FUTEX_INDEX_SHARED_MAX - 1)
128 PRINT_ERR(
"Futex lock failed! ERROR: 0x%x!\n", ret);
138 PRINT_ERR(
"Futex unlock failed! ERROR: 0x%x!\n", ret);
149 for (count = 0; count < FUTEX_INDEX_MAX; count++) {
162#ifdef LOS_FUTEX_DEBUG
170 tempNode = OS_FUTEX_FROM_FUTEXLIST(futexList);
171 PRINTK(
"key(pid) : 0x%x(%u) : ->", tempNode->
key, tempNode->
pid);
173 for (queueList = &tempNode->
queueList; ;) {
174 lastNode = OS_FUTEX_FROM_QUEUELIST(queueList);
176 taskCB = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(lastNode->
pendList)));
177 PRINTK(
" %u ->", taskCB->
taskID);
179 taskCB = LOS_DL_LIST_ENTRY(lastNode,
LosTaskCB, futex);
180 PRINTK(
" %u ->", taskCB->
taskID);
182 queueList = queueList->
pstNext;
195 INT32 hashNodeMax = FUTEX_INDEX_MAX;
196 PRINTK(
"#################### los_futex_pri.hash ####################\n");
197 for (count = 0; count < hashNodeMax; count++) {
202 PRINTK(
"hash -> index : %d\n", count);
203 for (futexList = futexList->
pstNext;
205 futexList = futexList->
pstNext) {
216 if (flags & FUTEX_PRIVATE) {
229 if (flags & FUTEX_PRIVATE) {
230 index &= FUTEX_HASH_PRIVATE_MASK;
232 index &= FUTEX_HASH_SHARED_MASK;
233 index += FUTEX_INDEX_SHARED_POS;
241 node->
key = futexKey;
248 node->
index = OS_INVALID_VALUE;
272 if (node->
index >= FUTEX_INDEX_MAX) {
278 if (queueFlags != NULL) {
286 if (isDeleteHead == TRUE) {
287 nextNode = OS_FUTEX_FROM_QUEUELIST(LOS_DL_LIST_FIRST(&node->
queueList));
289 if (headNode != NULL) {
290 *headNode = nextNode;
307 if (index >= FUTEX_INDEX_MAX) {
316 if (node->
index != index) {
334 BOOL queueFlag = FALSE;
338 nextNode = OS_FUTEX_FROM_QUEUELIST(LOS_DL_LIST_FIRST(&(tempNode->
queueList)));
364 headNode = OS_FUTEX_FROM_FUTEXLIST(LOS_DL_LIST_FIRST(&(hashNode->
lockList)));
366 if (node->
key < headNode->
key) {
371 tailNode = OS_FUTEX_FROM_FUTEXLIST(LOS_DL_LIST_LAST(&(hashNode->
lockList)));
372 if (node->
key > tailNode->
key) {
379 futexList = futexList->
pstNext) {
380 headNode = OS_FUTEX_FROM_FUTEXLIST(futexList);
381 if (node->
key <= headNode->
key) {
397 for (; listHead != listTail; listTail = listTail->
pstPrev) {
398 FutexNode *tempNode = OS_FUTEX_FROM_QUEUELIST(listTail);
400 if (tempNode == NULL) {
403 LosTaskCB *taskTail = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(tempNode->
pendList)));
409 if (listTail->
pstPrev == listHead) {
424 for (; listHead != listTail; listHead = listHead->
pstNext) {
425 FutexNode *tempNode = OS_FUTEX_FROM_QUEUELIST(listHead);
427 if (tempNode == NULL) {
430 LosTaskCB *taskHead = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(tempNode->
pendList)));
436 if (listHead->
pstNext == listTail) {
454 SCHEDULER_LOCK(intSave);
456 SCHEDULER_UNLOCK(intSave);
459 if (*firstNode == NULL) {
470 LosTaskCB *taskHead = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&((*firstNode)->pendList)));
471 LOS_DL_LIST *queueList = &((*firstNode)->queueList);
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)));
491 if ((ret2 <= 0) || (ret1 > ret2)) {
504 for (futexList = futexList->
pstNext;
506 futexList = futexList->
pstNext) {
507 headNode = OS_FUTEX_FROM_FUTEXLIST(futexList);
508 if ((headNode->
key == node->
key) && (headNode->
pid == node->
pid)) {
524 if (headNode == NULL) {
533 }
else if (firstNode == NULL) {
537 SCHEDULER_LOCK(intSave);
539 SCHEDULER_UNLOCK(intSave);
549 if (!(flags & FUTEX_PRIVATE)) {
551 if (paddr == 0)
return LOS_NOK;
565 if (flags & (~FUTEX_PRIVATE)) {
566 PRINT_ERR(
"Futex wait param check failed! error flags: 0x%x\n", flags);
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);
576 PRINT_ERR(
"Futex wait param check failed! error shared memory perm userVaddr: 0x%x\n", userVaddr);
581 return LOS_ETIMEDOUT;
594 if (node->
index < FUTEX_INDEX_MAX) {
595 SCHEDULER_LOCK(intSave);
597 SCHEDULER_UNLOCK(intSave);
600#ifdef LOS_FUTEX_DEBUG
607 return LOS_ETIMEDOUT;
614 *node = &((*taskCB)->futex);
641 PRINT_ERR(
"Futex wait param check failed! copy from user failed!\n");
642 futexRet = LOS_EINVAL;
646 if (lockVal != val) {
647 futexRet = LOS_EBADF;
656 SCHEDULER_LOCK(intSave);
666 goto EXIT_UNLOCK_ERR;
678 if (taskCB->
taskStatus & OS_TASK_STATUS_TIMEOUT) {
679 taskCB->
taskStatus &= ~OS_TASK_STATUS_TIMEOUT;
680 SCHEDULER_UNLOCK(intSave);
684 SCHEDULER_UNLOCK(intSave);
696 UINT32 timeout = LOS_WAIT_FOREVER;
702 if (absTime != LOS_WAIT_FOREVER) {
713 if ((flags & (~FUTEX_PRIVATE)) != FUTEX_WAKE) {
714 PRINT_ERR(
"Futex wake param check failed! error flags: 0x%x\n", flags);
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);
724 PRINT_ERR(
"Futex wake param check failed! error shared memory perm userVaddr: 0x%x\n", userVaddr);
741 for (count = 0; count < wakeNumber; count++) {
744 if (*nextNode == NULL) {
749 taskCB = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(node->
pendList)));
753 *nextNode = OS_FUTEX_FROM_QUEUELIST(LOS_DL_LIST_FIRST(&(node->
queueList)));
754 if (node != headNode) {
801 SCHEDULER_LOCK(intSave);
803 if ((*newHeadNode) != NULL) {
806 }
else if (headNode->
index < FUTEX_INDEX_MAX) {
810 SCHEDULER_UNLOCK(intSave);
822 BOOL wakeAny = FALSE;
836 ret =
OsFutexWakeTask(futexKey, flags, wakeNumber, &headNode, &wakeAny);
841#ifdef LOS_FUTEX_DEBUG
847 goto EXIT_UNLOCK_ERR;
850 if (wakeAny == TRUE) {
868 BOOL queueListIsEmpty = FALSE;
880 if (newHeadNode == NULL) {
886 nextNode = OS_FUTEX_FROM_QUEUELIST(queueList);
887 SCHEDULER_LOCK(intSave);
890 queueListIsEmpty = TRUE;
892 queueList = queueList->
pstNext;
895 SCHEDULER_UNLOCK(intSave);
896 if (queueListIsEmpty) {
903 task = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(nextNode->
pendList)));
905 queueListIsEmpty = TRUE;
907 queueList = queueList->
pstNext;
911 SCHEDULER_UNLOCK(intSave);
913 PRINT_ERR(
"Futex requeue insert new key failed!\n");
915 }
while (!queueListIsEmpty);
924 FutexNode *tailNode = OS_FUTEX_FROM_QUEUELIST(LOS_DL_LIST_LAST(queueList));
932 for (i = 0; i < count; i++) {
933 nextNode = OS_FUTEX_FROM_QUEUELIST(queueList);
934 nextNode->
key = futexKey;
935 nextNode->
index = newIndex;
941 queueList = queueList->
pstNext;
950 newHeadNode = OS_FUTEX_FROM_QUEUELIST(queueList);
972 if (wakeNumber > 0) {
973 ret =
OsFutexWakeTask(oldFutexKey, flags, wakeNumber, &oldHeadNode, wakeAny);
974 if ((ret != LOS_OK) || (oldHeadNode == NULL)) {
979 if (requeueCount <= 0) {
983 if (oldHeadNode == NULL) {
985 if (oldHeadNode == NULL) {
1000 if (oldVaddr == newVaddr) {
1004 if ((flags & (~FUTEX_PRIVATE)) != FUTEX_REQUEUE) {
1005 PRINT_ERR(
"Futex requeue param check failed! error flags: 0x%x\n", flags);
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);
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);
1032 BOOL wakeAny = FALSE;
1049 if (oldHeadNode == NULL) {
1051 if (wakeAny == TRUE) {
1059 if (oldIndex != newIndex) {
1076 if (wakeAny == TRUE) {
STATIC INLINE VOID LOS_IntRestore(UINT32 intSave)
Restore interrupts. | 恢复到使用LOS_IntLock关闭所有中断之前的状态
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListInit(LOS_DL_LIST *list)
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.
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.
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListDelete(LOS_DL_LIST *node)
LITE_OS_SEC_ALW_INLINE STATIC INLINE BOOL LOS_ListEmpty(LOS_DL_LIST *list)
Identify whether a specified doubly linked list is empty. | 判断链表是否为空
LITE_OS_SEC_TEXT UINT32 LOS_MuxInit(LosMux *mutex, const LosMuxAttr *attr)
初始化互斥锁
LITE_OS_SEC_TEXT UINT32 LOS_MuxUnlock(LosMux *mutex)
释放锁
LITE_OS_SEC_TEXT UINT32 LOS_MuxLock(LosMux *mutex, UINT32 timeout)
拿互斥锁,
LITE_OS_SEC_TEXT_MINOR UINT32 OsNS2Tick(UINT64 nanoseconds)
纳秒转化成 tick
VOID LOS_Schedule(VOID)
Trigger active task scheduling.
STATIC INLINE VOID OsFutexDeleteKeyFromFutexList(FutexNode *node)
将参数节点从futexList上摘除
FutexHash g_futexHash[FUTEX_INDEX_MAX]
80个哈希桶
STATIC INT32 OsFutexWakeTask(UINTPTR futexKey, UINT32 flags, INT32 wakeNumber, FutexNode **newHeadNode, BOOL *wakeAny)
OsFutexWakeTask 唤醒任务
STATIC INT32 OsFutexRecycleAndFindHeadNode(FutexNode *headNode, FutexNode *node, FutexNode **firstNode)
将快锁挂到任务的阻塞链表上
VOID OsFutexNodeDeleteFromFutexHash(FutexNode *node, BOOL isDeleteHead, FutexNode **headNode, BOOL *queueFlags)
从哈希桶上删除快锁
STATIC INT32 OsFutexLock(LosMux *lock)
对互斥锁封装
STATIC VOID OsFutexDeleteKeyNodeFromHash(FutexNode *node, BOOL isDeleteHead, FutexNode **headNode, BOOL *queueFlags)
从哈希桶中删除快锁节点
STATIC INT32 OsFutexWaitParamCheck(const UINT32 *userVaddr, UINT32 flags, UINT32 absTime)
STATIC INT32 OsFutexUnlock(LosMux *lock)
初始化Futex(Fast userspace mutex,用户态快速互斥锁)模块
STATIC INLINE UINTPTR OsFutexFlagsToKey(const UINT32 *userVaddr, const UINT32 flags)
通过用户空间地址获取哈希key
STATIC INT32 OsFutexInsertTasktoPendList(FutexNode **firstNode, FutexNode *node, const LosTaskCB *run)
STATIC INT32 OsFutexWakeParamCheck(const UINT32 *userVaddr, UINT32 flags)
VOID OsFutexHashShow(VOID)
STATIC INT32 OsFutexInsertFindFromFrontToBack(LOS_DL_LIST *queueList, const LosTaskCB *runTask, FutexNode *node)
STATIC VOID OsFutexCheckAndWakePendTask(FutexNode *headNode, const INT32 wakeNumber, FutexHash *hashNode, FutexNode **nextNode, BOOL *wakeAny)
INT32 OsFutexWait(const UINT32 *userVaddr, UINT32 flags, UINT32 val, UINT32 absTime)
设置线程等待 | 向Futex表中插入代表被阻塞的线程的node
STATIC INT32 OsFutexWaitTask(const UINT32 *userVaddr, const UINT32 flags, const UINT32 val, const UINT32 timeout)
将当前任务挂入等待链表中
LOS_MODULE_INIT(OsFutexInit, LOS_INIT_LEVEL_KMOD_EXTENDED)
注册Futex模块
STATIC INT32 OsFutexRequeueInsertNewKey(UINTPTR newFutexKey, INT32 newIndex, FutexNode *oldHeadNode)
STATIC FutexNode * OsFutexRequeueRemoveOldKeyAndGetHead(UINTPTR oldFutexKey, UINT32 flags, INT32 wakeNumber, UINTPTR newFutexKey, INT32 requeueCount, BOOL *wakeAny)
删除旧key并获取头节点
STATIC INT32 OsFutexDeleteTimeoutTaskNode(FutexHash *hashNode, FutexNode *node)
STATIC INLINE VOID OsFutexSetKey(UINTPTR futexKey, UINT32 flags, FutexNode *node)
设置快锁哈希key
STATIC FutexNode * OsFutexDeleteAlreadyWakeTaskAndGetNext(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 INLINE VOID OsFutexReplaceQueueListHeadNode(FutexNode *oldHeadNode, FutexNode *newHeadNode)
新旧两个节点交换 futexList 位置
STATIC FutexNode * OsFindFutexNode(const FutexNode *node)
由指定快锁找到对应哈希桶
STATIC INT32 OsFindAndInsertToHash(FutexNode *node)
STATIC INLINE UINT32 OsFutexKeyToIndex(const UINTPTR futexKey, const UINT32 flags)
通过哈希key获取索引
INT32 OsFutexRequeue(const UINT32 *userVaddr, UINT32 flags, INT32 wakeNumber, INT32 count, const UINT32 *newUserVaddr)
调整指定锁在Futex表中的位置
STATIC INT32 OsFutexInsertTaskToHash(LosTaskCB **taskCB, FutexNode **node, const UINTPTR futexKey, const UINT32 flags)
将快锁节点插入任务
INT32 OsFutexWake(const UINT32 *userVaddr, UINT32 flags, INT32 wakeNumber)
唤醒一个被指定锁阻塞的线程
STATIC INT32 OsFutexKeyShmPermCheck(const UINT32 *userVaddr, const UINT32 flags)
共享内存检查
STATIC VOID OsFutexRequeueSplitTwoLists(FutexHash *oldHashNode, FutexNode *oldHeadNode, UINT32 flags, UINTPTR futexKey, INT32 count)
STATIC VOID OsFutexShowTaskNodeAttr(const LOS_DL_LIST *futexList)
STATIC INT32 OsFutexRequeueParamCheck(const UINT32 *oldUserVaddr, UINT32 flags, const UINT32 *newUserVaddr)
检查锁在Futex表中的状态
STATIC INLINE VOID OsFutexDeinitFutexNode(FutexNode *node)
LITE_OS_SEC_ALW_INLINE STATIC INLINE UINT32 LOS_HashFNV32aBuf(const VOID *buf, size_t len, UINT32 hval)
VOID LOS_MpSchedule(UINT32 target)
UINT32 OsMuxLockUnsafe(LosMux *mutex, UINT32 timeout)
UINT32 OsMuxUnlockUnsafe(LosTaskCB *taskCB, LosMux *mutex, BOOL *needSched)
LITE_OS_SEC_TEXT UINT32 LOS_GetCurrProcessID(VOID)
获取当前进程的进程ID
STATIC INLINE VOID OsSchedUnlock(VOID)
STATIC INLINE LosTaskCB * OsCurrTaskGet(VOID)
INT32 OsSchedParamCompare(const LosTaskCB *task1, const LosTaskCB *task2)
STATIC INLINE VOID OsSchedLock(VOID)
VOID OsSchedResched(VOID)
VOID LOS_SpinLock(SPIN_LOCK_S *lock)
VOID LOS_SpinUnlock(SPIN_LOCK_S *lock)
STATIC INLINE VOID OsTaskWaitSetPendMask(UINT16 mask, UINTPTR lockID, UINT32 timeout)
设置事件阻塞掩码,即设置任务的等待事件.
STATIC INLINE VOID OsTaskWakeClearPendMask(LosTaskCB *resumeTask)
清除事件阻塞掩码,即任务不再等待任何事件.
PADDR_T LOS_PaddrQuery(VOID *vaddr)
通过虚拟地址查询映射的物理地址
LosMux listLock
内核操作lockList的互斥锁
LOS_DL_LIST lockList
用于挂载 FutexNode (Fast userspace mutex,用户态快速互斥锁)
每个futex node对应一个被挂起的task ,key值唯一标识一把用户态锁,具有相同key值的node被queue_list串联起来表示被同一把锁阻塞的task队列。
struct LOS_DL_LIST * pstPrev
struct LOS_DL_LIST * pstNext
UINT32(* wait)(LosTaskCB *runTask, LOS_DL_LIST *list, UINT32 timeout)
任务等待
VOID(* wake)(LosTaskCB *taskCB)
任务唤醒
size_t LOS_ArchCopyFromUser(void *dst, const void *src, size_t len)