更新日期: 2022/06/01 来源: https://gitee.com/weharmony/kernel_liteos_a_note
los_futex.c
浏览该文件的文档.
1/*!
2 * @file los_futex.c
3 * @brief
4 * @link mutex http://weharmonyos.com/openharmony/zh-cn/device-dev/kernel/kernel-small-basic-trans-user-mutex.html @endlink
5 * @link d17a6152740c https://www.jianshu.com/p/d17a6152740c @endlink
6 @verbatim
7 Futex 由一块能够被多个进程共享的内存空间(一个对齐后的整型变量)组成;这个整型变量的值能够通过汇编语言调用CPU提供的原子操作指令来增加或减少,
8 并且一个进程可以等待直到那个值变成正数。Futex 的操作几乎全部在用户空间完成;只有当操作结果不一致从而需要仲裁时,才需要进入操作系统内核空间执行。
9 这种机制允许使用 futex 的锁定原语有非常高的执行效率:由于绝大多数的操作并不需要在多个进程之间进行仲裁,所以绝大多数操作都可以在应用程序空间执行,
10 而不需要使用(相对高代价的)内核系统调用。
11
12 基本概念
13 Futex(Fast userspace mutex,用户态快速互斥锁)是内核提供的一种系统调用能力,通常作为基础组件与用户态的相关
14 锁逻辑结合组成用户态锁,是一种用户态与内核态共同作用的锁,例如用户态mutex锁、barrier与cond同步锁、读写锁。
15 其用户态部分负责锁逻辑,内核态部分负责锁调度。
16
17 当用户态线程请求锁时,先在用户态进行锁状态的判断维护,若此时不产生锁的竞争,则直接在用户态进行上锁返回;
18 反之,则需要进行线程的挂起操作,通过Futex系统调用请求内核介入来挂起线程,并维护阻塞队列。
19
20 当用户态线程释放锁时,先在用户态进行锁状态的判断维护,若此时没有其他线程被该锁阻塞,则直接在用户态进行解锁返回;
21 反之,则需要进行阻塞线程的唤醒操作,通过Futex系统调用请求内核介入来唤醒阻塞队列中的线程。
22 历史
23 futex (fast userspace mutex) 是Linux的一个基础组件,可以用来构建各种更高级别的同步机制,比如锁或者信号量等等,
24 POSIX信号量就是基于futex构建的。大多数时候编写应用程序并不需要直接使用futex,一般用基于它所实现的系统库就够了。
25
26 传统的SystemV IPC(inter process communication)进程间同步机制都是通过内核对象来实现的,以 semaphore 为例,
27 当进程间要同步的时候,必须通过系统调用semop(2)进入内核进行PV操作。系统调用的缺点是开销很大,需要从user mode
28 切换到kernel mode、保存寄存器状态、从user stack切换到kernel stack、等等,通常要消耗上百条指令。事实上,
29 有一部分系统调用是可以避免的,因为现实中很多同步操作进行的时候根本不存在竞争,即某个进程从持有semaphore直至
30 释放semaphore的这段时间内,常常没有其它进程对同一semaphore有需求,在这种情况下,内核的参与本来是不必要的,
31 可是在传统机制下,持有semaphore必须先调用semop(2)进入内核去看看有没有人和它竞争,释放semaphore也必须调用semop(2)
32 进入内核去看看有没有人在等待同一semaphore,这些不必要的系统调用造成了大量的性能损耗。
33 设计思想
34 futex的解决思路是:在无竞争的情况下操作完全在user space进行,不需要系统调用,仅在发生竞争的时候进入内核去完成
35 相应的处理(wait 或者 wake up)。所以说,futex是一种user mode和kernel mode混合的同步机制,需要两种模式合作才能完成,
36 futex变量必须位于user space,而不是内核对象,futex的代码也分为user mode和kernel mode两部分,无竞争的情况下在user mode,
37 发生竞争时则通过sys_futex系统调用进入kernel mode进行处理
38 运行机制
39 当用户态产生锁的竞争或释放需要进行相关线程的调度操作时,会触发Futex系统调用进入内核,此时会将用户态锁的地址
40 传入内核,并在内核的Futex中以锁地址来区分用户态的每一把锁,因为用户态可用虚拟地址空间为1GiB,为了便于查找、
41 管理,内核Futex采用哈希桶来存放用户态传入的锁。
42
43 当前哈希桶共有80个,0~63号桶用于存放私有锁(以虚拟地址进行哈希),64~79号桶用于存放共享锁(以物理地址进行哈希),
44 私有/共享属性通过用户态锁的初始化以及Futex系统调用入参确定。
45
46 如下图: 每个futex哈希桶中存放被futex_list串联起来的哈希值相同的futex node,每个futex node对应一个被挂起的task,
47 node中key值唯一标识一把用户态锁,具有相同key值的node被queue_list串联起来表示被同一把锁阻塞的task队列。
48 @endverbatim
49 @image html https://gitee.com/weharmonyos/resources/raw/master/81/futex.png
50 * @attention Futex系统调用通常与用户态逻辑共同组成用户态锁,故推荐使用用户态POSIX接口的锁
51 * @version
52 * @author weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
53 * @date 2021-11-23
54 */
55/*
56 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
57 * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
58 *
59 * Redistribution and use in source and binary forms, with or without modification,
60 * are permitted provided that the following conditions are met:
61 *
62 * 1. Redistributions of source code must retain the above copyright notice, this list of
63 * conditions and the following disclaimer.
64 *
65 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
66 * of conditions and the following disclaimer in the documentation and/or other materials
67 * provided with the distribution.
68 *
69 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
70 * to endorse or promote products derived from this software without specific prior written
71 * permission.
72 *
73 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
74 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
75 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
76 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
77 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
78 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
79 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
80 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
81 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
82 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
83 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
84 */
85
86#include "los_futex_pri.h"
87#include "los_exc.h"
88#include "los_hash.h"
89#include "los_init.h"
90#include "los_process_pri.h"
91#include "los_sched_pri.h"
92#include "los_sys_pri.h"
93#include "los_mp.h"
94#include "los_mux_pri.h"
95#include "user_copy.h"
96
97
98#ifdef LOSCFG_KERNEL_VM
99
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) ///< 进程用户空间尾址
104
105/* private: 0~63 hash index_num
106 * shared: 64~79 hash index_num */
107#define FUTEX_INDEX_PRIVATE_MAX 64 ///< 0~63号桶用于存放私有锁(以虚拟地址进行哈希),同一进程不同线程共享futex变量,表明变量在进程地址空间中的位置
108///< 它告诉内核,这个futex是进程专有的,不可以与其他进程共享。它仅仅用作同一进程的线程间同步。
109#define FUTEX_INDEX_SHARED_MAX 16 ///< 64~79号桶用于存放共享锁(以物理地址进行哈希),不同进程间通过文件共享futex变量,表明该变量在文件中的位置
110#define FUTEX_INDEX_MAX (FUTEX_INDEX_PRIVATE_MAX + FUTEX_INDEX_SHARED_MAX) ///< 80个哈希桶
111
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)
115/// 单独哈希桶,上面挂了一个个 FutexNode
116typedef struct {
117 LosMux listLock;///< 内核操作lockList的互斥锁
118 LOS_DL_LIST lockList;///< 用于挂载 FutexNode (Fast userspace mutex,用户态快速互斥锁)
119} FutexHash;
120
121FutexHash g_futexHash[FUTEX_INDEX_MAX];///< 80个哈希桶
122
123/// 对互斥锁封装
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}
133
135{
136 UINT32 ret = LOS_MuxUnlock(lock);
137 if (ret != LOS_OK) {
138 PRINT_ERR("Futex unlock failed! ERROR: 0x%x!\n", ret);
139 return LOS_EINVAL;
140 }
141 return LOS_OK;
142}
143///< 初始化Futex(Fast userspace mutex,用户态快速互斥锁)模块
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}
159
160LOS_MODULE_INIT(OsFutexInit, LOS_INIT_LEVEL_KMOD_EXTENDED);///< 注册Futex模块
161
162#ifdef LOS_FUTEX_DEBUG
163STATIC VOID OsFutexShowTaskNodeAttr(const LOS_DL_LIST *futexList)
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}
189
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}
210#endif
211/// 通过用户空间地址获取哈希key
212STATIC INLINE UINTPTR OsFutexFlagsToKey(const UINT32 *userVaddr, const UINT32 flags)
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}
224/// 通过哈希key获取索引
225STATIC INLINE UINT32 OsFutexKeyToIndex(const UINTPTR futexKey, const UINT32 flags)
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}
238/// 设置快锁哈希key
239STATIC INLINE VOID OsFutexSetKey(UINTPTR futexKey, UINT32 flags, FutexNode *node)
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}
245//析构参数节点
246STATIC INLINE VOID OsFutexDeinitFutexNode(FutexNode *node)
247{
248 node->index = OS_INVALID_VALUE;
249 node->pid = 0;
251}
252/// 新旧两个节点交换 futexList 位置
253STATIC INLINE VOID OsFutexReplaceQueueListHeadNode(FutexNode *oldHeadNode, FutexNode *newHeadNode)
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}
262/// 将参数节点从futexList上摘除
264{
266}
267/// 从哈希桶中删除快锁节点
268STATIC VOID OsFutexDeleteKeyNodeFromHash(FutexNode *node, BOOL isDeleteHead, FutexNode **headNode, BOOL *queueFlags)
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}
301/// 从哈希桶上删除快锁
302VOID OsFutexNodeDeleteFromFutexHash(FutexNode *node, BOOL isDeleteHead, FutexNode **headNode, BOOL *queueFlags)
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}
329/// 这块代码谁写的? 这种命名 ...
330STATIC FutexNode *OsFutexDeleteAlreadyWakeTaskAndGetNext(const FutexNode *node, FutexNode **headNode, BOOL isDeleteHead)
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}
351/// 插入一把新Futex锁到哈希桶中,只有是新的key时才会插入,因为其实存在多个FutexNode是一个key
353{
354 FutexNode *headNode = NULL;
355 FutexNode *tailNode = NULL;
356 LOS_DL_LIST *futexList = NULL;
357 FutexHash *hashNode = &g_futexHash[node->index];
358
359 if (LOS_ListEmpty(&hashNode->lockList)) {
360 LOS_ListHeadInsert(&(hashNode->lockList), &(node->futexList));
361 goto EXIT;
362 }
363
364 headNode = OS_FUTEX_FROM_FUTEXLIST(LOS_DL_LIST_FIRST(&(hashNode->lockList)));
365 /* The small key is at the front of the queue */
366 if (node->key < headNode->key) {
367 LOS_ListHeadInsert(&(hashNode->lockList), &(node->futexList));
368 goto EXIT;
369 }
370
371 tailNode = OS_FUTEX_FROM_FUTEXLIST(LOS_DL_LIST_LAST(&(hashNode->lockList)));
372 if (node->key > tailNode->key) {
373 LOS_ListTailInsert(&(hashNode->lockList), &(node->futexList));
374 goto EXIT;
375 }
376
377 for (futexList = hashNode->lockList.pstNext;
378 futexList != &(hashNode->lockList);
379 futexList = futexList->pstNext) {
380 headNode = OS_FUTEX_FROM_FUTEXLIST(futexList);
381 if (node->key <= headNode->key) {
382 LOS_ListTailInsert(&(headNode->futexList), &(node->futexList));
383 break;
384 }
385
386 }
387
388EXIT:
389 return;
390}
391///< 从后往前插入快锁 Form写错了 @note_thinking
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}
418
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}
449
451{
452 UINT32 intSave;
453
454 SCHEDULER_LOCK(intSave);
455 *firstNode = OsFutexDeleteAlreadyWakeTaskAndGetNext(headNode, NULL, TRUE);
456 SCHEDULER_UNLOCK(intSave);
457
458 /* The head node is removed and there was originally only one node under the key */
459 if (*firstNode == NULL) {
461 LOS_ListInit(&(node->queueList));
462 return LOS_OK;
463 }
464
465 return LOS_OK;
466}
467///< 将快锁挂到任务的阻塞链表上
468STATIC INT32 OsFutexInsertTasktoPendList(FutexNode **firstNode, FutexNode *node, const LosTaskCB *run)
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}
497/// 由指定快锁找到对应哈希桶
499{
500 FutexHash *hashNode = &g_futexHash[node->index];//先找到所在哈希桶
501 LOS_DL_LIST *futexList = &(hashNode->lockList);
502 FutexNode *headNode = NULL;
503
504 for (futexList = futexList->pstNext;
505 futexList != &(hashNode->lockList);//判断循环结束条件,相等时说明跑完一轮了
506 futexList = futexList->pstNext) {
507 headNode = OS_FUTEX_FROM_FUTEXLIST(futexList);//拿到快锁节点实体
508 if ((headNode->key == node->key) && (headNode->pid == node->pid)) {//已经存在这个节点,注意这里的比较
509 return headNode;//是key和pid 一起比较,因为只有这样才能确定唯一性
510 }//详细讲解请查看 鸿蒙内核源码分析(内核态锁篇) | 如何实现快锁Futex(下)
511 }
512
513 return NULL;
514}
515///< 查找快锁并插入哈希桶中
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}
543/// 共享内存检查
544STATIC INT32 OsFutexKeyShmPermCheck(const UINT32 *userVaddr, const UINT32 flags)
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}
556
557STATIC INT32 OsFutexWaitParamCheck(const UINT32 *userVaddr, UINT32 flags, UINT32 absTime)
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}
586
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}
609/// 将快锁节点插入任务
610STATIC INT32 OsFutexInsertTaskToHash(LosTaskCB **taskCB, FutexNode **node, const UINTPTR futexKey, const UINT32 flags)
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}
625/// 将当前任务挂入等待链表中
626STATIC INT32 OsFutexWaitTask(const UINT32 *userVaddr, const UINT32 flags, const UINT32 val, const UINT32 timeout)
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}
692/// 设置线程等待 | 向Futex表中插入代表被阻塞的线程的node
693INT32 OsFutexWait(const UINT32 *userVaddr, UINT32 flags, UINT32 val, UINT32 absTime)
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}
708
709STATIC INT32 OsFutexWakeParamCheck(const UINT32 *userVaddr, UINT32 flags)
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}
730
731/* Check to see if the task to be awakened has timed out
732 * if time out, to weak next pend task.
733 * | 查看要唤醒的任务是否超时,如果超时,就唤醒,并查看下一个挂起的任务。
734 */
735STATIC VOID OsFutexCheckAndWakePendTask(FutexNode *headNode, const INT32 wakeNumber,
736 FutexHash *hashNode, FutexNode **nextNode, BOOL *wakeAny)
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}
768
769/*!
770 * @brief OsFutexWakeTask 唤醒任务
771 *
772 * @param flags
773 * @param futexKey
774 * @param newHeadNode
775 * @param wakeAny
776 * @param wakeNumber 唤醒数量
777 * @return
778 *
779 * @see
780 */
781STATIC INT32 OsFutexWakeTask(UINTPTR futexKey, UINT32 flags, INT32 wakeNumber, FutexNode **newHeadNode, BOOL *wakeAny)
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}
814/// 唤醒一个被指定锁阻塞的线程
815INT32 OsFutexWake(const UINT32 *userVaddr, UINT32 flags, INT32 wakeNumber)
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}
865
866STATIC INT32 OsFutexRequeueInsertNewKey(UINTPTR newFutexKey, INT32 newIndex, FutexNode *oldHeadNode)
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}
919
920STATIC VOID OsFutexRequeueSplitTwoLists(FutexHash *oldHashNode, FutexNode *oldHeadNode,
921 UINT32 flags, UINTPTR futexKey, INT32 count)
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}
958/// 删除旧key并获取头节点
960 UINTPTR newFutexKey, INT32 requeueCount, BOOL *wakeAny)
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}
994/// 检查锁在Futex表中的状态
995STATIC INT32 OsFutexRequeueParamCheck(const UINT32 *oldUserVaddr, UINT32 flags, const UINT32 *newUserVaddr)
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}
1021/// 调整指定锁在Futex表中的位置
1022INT32 OsFutexRequeue(const UINT32 *userVaddr, UINT32 flags, INT32 wakeNumber, INT32 count, const UINT32 *newUserVaddr)
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}
1083#endif
1084
STATIC INLINE VOID LOS_IntRestore(UINT32 intSave)
Restore interrupts. | 恢复到使用LOS_IntLock关闭所有中断之前的状态
Definition: los_hwi.h:337
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_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
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_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
LITE_OS_SEC_TEXT UINT32 LOS_MuxLock(LosMux *mutex, UINT32 timeout)
拿互斥锁,
Definition: los_mux.c:437
LITE_OS_SEC_TEXT_MINOR UINT32 OsNS2Tick(UINT64 nanoseconds)
纳秒转化成 tick
Definition: los_sys.c:125
VOID LOS_Schedule(VOID)
Trigger active task scheduling.
Definition: los_sched.c:469
STATIC INLINE VOID OsFutexDeleteKeyFromFutexList(FutexNode *node)
将参数节点从futexList上摘除
Definition: los_futex.c:263
FutexHash g_futexHash[FUTEX_INDEX_MAX]
80个哈希桶
Definition: los_futex.c:121
STATIC INT32 OsFutexWakeTask(UINTPTR futexKey, UINT32 flags, INT32 wakeNumber, FutexNode **newHeadNode, BOOL *wakeAny)
OsFutexWakeTask 唤醒任务
Definition: los_futex.c:781
STATIC INT32 OsFutexRecycleAndFindHeadNode(FutexNode *headNode, FutexNode *node, FutexNode **firstNode)
将快锁挂到任务的阻塞链表上
Definition: los_futex.c:450
VOID OsFutexNodeDeleteFromFutexHash(FutexNode *node, BOOL isDeleteHead, FutexNode **headNode, BOOL *queueFlags)
从哈希桶上删除快锁
Definition: los_futex.c:302
STATIC INT32 OsFutexLock(LosMux *lock)
对互斥锁封装
Definition: los_futex.c:124
STATIC VOID OsFutexDeleteKeyNodeFromHash(FutexNode *node, BOOL isDeleteHead, FutexNode **headNode, BOOL *queueFlags)
从哈希桶中删除快锁节点
Definition: los_futex.c:268
STATIC INT32 OsFutexWaitParamCheck(const UINT32 *userVaddr, UINT32 flags, UINT32 absTime)
Definition: los_futex.c:557
STATIC INT32 OsFutexUnlock(LosMux *lock)
初始化Futex(Fast userspace mutex,用户态快速互斥锁)模块
Definition: los_futex.c:134
STATIC INLINE UINTPTR OsFutexFlagsToKey(const UINT32 *userVaddr, const UINT32 flags)
通过用户空间地址获取哈希key
Definition: los_futex.c:212
STATIC INT32 OsFutexInsertTasktoPendList(FutexNode **firstNode, FutexNode *node, const LosTaskCB *run)
Definition: los_futex.c:468
STATIC INT32 OsFutexWakeParamCheck(const UINT32 *userVaddr, UINT32 flags)
Definition: los_futex.c:709
VOID OsFutexHashShow(VOID)
Definition: los_futex.c:190
STATIC INT32 OsFutexInsertFindFromFrontToBack(LOS_DL_LIST *queueList, const LosTaskCB *runTask, FutexNode *node)
Definition: los_futex.c:419
STATIC VOID OsFutexCheckAndWakePendTask(FutexNode *headNode, const INT32 wakeNumber, FutexHash *hashNode, FutexNode **nextNode, BOOL *wakeAny)
Definition: los_futex.c:735
INT32 OsFutexWait(const UINT32 *userVaddr, UINT32 flags, UINT32 val, UINT32 absTime)
设置线程等待 | 向Futex表中插入代表被阻塞的线程的node
Definition: los_futex.c:693
STATIC INT32 OsFutexWaitTask(const UINT32 *userVaddr, const UINT32 flags, const UINT32 val, const UINT32 timeout)
将当前任务挂入等待链表中
Definition: los_futex.c:626
LOS_MODULE_INIT(OsFutexInit, LOS_INIT_LEVEL_KMOD_EXTENDED)
注册Futex模块
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 OsFutexDeleteTimeoutTaskNode(FutexHash *hashNode, FutexNode *node)
Definition: los_futex.c:587
STATIC INLINE VOID OsFutexSetKey(UINTPTR futexKey, UINT32 flags, FutexNode *node)
设置快锁哈希key
Definition: los_futex.c:239
STATIC FutexNode * OsFutexDeleteAlreadyWakeTaskAndGetNext(const FutexNode *node, FutexNode **headNode, BOOL isDeleteHead)
这块代码谁写的? 这种命名 ...
Definition: los_futex.c:330
STATIC VOID OsFutexInsertNewFutexKeyToHash(FutexNode *node)
插入一把新Futex锁到哈希桶中,只有是新的key时才会插入,因为其实存在多个FutexNode是一个key
Definition: los_futex.c:352
STATIC INT32 OsFutexInsertFindFormBackToFront(LOS_DL_LIST *queueList, const LosTaskCB *runTask, FutexNode *node)
Definition: los_futex.c:392
STATIC INLINE VOID OsFutexReplaceQueueListHeadNode(FutexNode *oldHeadNode, FutexNode *newHeadNode)
新旧两个节点交换 futexList 位置
Definition: los_futex.c:253
UINT32 OsFutexInit(VOID)
Definition: los_futex.c:144
STATIC FutexNode * OsFindFutexNode(const FutexNode *node)
由指定快锁找到对应哈希桶
Definition: los_futex.c:498
STATIC INT32 OsFindAndInsertToHash(FutexNode *node)
Definition: los_futex.c:516
STATIC INLINE UINT32 OsFutexKeyToIndex(const UINTPTR futexKey, const UINT32 flags)
通过哈希key获取索引
Definition: los_futex.c:225
INT32 OsFutexRequeue(const UINT32 *userVaddr, UINT32 flags, INT32 wakeNumber, INT32 count, const UINT32 *newUserVaddr)
调整指定锁在Futex表中的位置
Definition: los_futex.c:1022
STATIC INT32 OsFutexInsertTaskToHash(LosTaskCB **taskCB, FutexNode **node, const UINTPTR futexKey, const UINT32 flags)
将快锁节点插入任务
Definition: los_futex.c:610
INT32 OsFutexWake(const UINT32 *userVaddr, UINT32 flags, INT32 wakeNumber)
唤醒一个被指定锁阻塞的线程
Definition: los_futex.c:815
STATIC INT32 OsFutexKeyShmPermCheck(const UINT32 *userVaddr, const UINT32 flags)
共享内存检查
Definition: los_futex.c:544
STATIC VOID OsFutexRequeueSplitTwoLists(FutexHash *oldHashNode, FutexNode *oldHeadNode, UINT32 flags, UINTPTR futexKey, INT32 count)
Definition: los_futex.c:920
STATIC VOID OsFutexShowTaskNodeAttr(const LOS_DL_LIST *futexList)
Definition: los_futex.c:163
STATIC INT32 OsFutexRequeueParamCheck(const UINT32 *oldUserVaddr, UINT32 flags, const UINT32 *newUserVaddr)
检查锁在Futex表中的状态
Definition: los_futex.c:995
STATIC INLINE VOID OsFutexDeinitFutexNode(FutexNode *node)
Definition: los_futex.c:246
LITE_OS_SEC_ALW_INLINE STATIC INLINE UINT32 LOS_HashFNV32aBuf(const VOID *buf, size_t len, UINT32 hval)
Definition: los_hash.h:79
VOID LOS_MpSchedule(UINT32 target)
Definition: los_mp.c:76
UINT32 OsMuxLockUnsafe(LosMux *mutex, UINT32 timeout)
Definition: los_mux.c:398
UINT32 OsMuxUnlockUnsafe(LosTaskCB *taskCB, LosMux *mutex, BOOL *needSched)
Definition: los_mux.c:527
LITE_OS_SEC_TEXT UINT32 LOS_GetCurrProcessID(VOID)
获取当前进程的进程ID
Definition: los_process.c:2161
STATIC INLINE VOID OsSchedUnlock(VOID)
STATIC INLINE LosTaskCB * OsCurrTaskGet(VOID)
INT32 OsSchedParamCompare(const LosTaskCB *task1, const LosTaskCB *task2)
Definition: los_sched.c:233
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
STATIC INLINE VOID OsTaskWakeClearPendMask(LosTaskCB *resumeTask)
清除事件阻塞掩码,即任务不再等待任何事件.
Definition: los_task_pri.h:298
SPIN_LOCK_S g_taskSpin
unsigned long PADDR_T
Definition: los_typedef.h:207
signed int INT32
Definition: los_typedef.h:60
unsigned long VADDR_T
Definition: los_typedef.h:208
long unsigned int UINT64
Definition: los_typedef.h:66
unsigned long UINTPTR
Definition: los_typedef.h:68
unsigned int UINT32
Definition: los_typedef.h:57
size_t BOOL
Definition: los_typedef.h:88
PADDR_T LOS_PaddrQuery(VOID *vaddr)
通过虚拟地址查询映射的物理地址
Definition: los_vm_map.c:550
单独哈希桶,上面挂了一个个 FutexNode
Definition: los_futex.c:116
LosMux listLock
内核操作lockList的互斥锁
Definition: los_futex.c:117
LOS_DL_LIST lockList
用于挂载 FutexNode (Fast userspace mutex,用户态快速互斥锁)
Definition: los_futex.c:118
每个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
UINTPTR key
Definition: los_futex_pri.h:78
UINT32 index
Definition: los_futex_pri.h:79
LOS_DL_LIST futexList
Definition: los_futex_pri.h:84
UINT32 pid
Definition: los_futex_pri.h:80
LOS_DL_LIST pendList
Definition: los_futex_pri.h:81
struct LOS_DL_LIST * pstPrev
Definition: los_list.h:83
struct LOS_DL_LIST * pstNext
Definition: los_list.h:84
Definition: los_mux.h:73
UINT32(* wait)(LosTaskCB *runTask, LOS_DL_LIST *list, UINT32 timeout)
任务等待
VOID(* wake)(LosTaskCB *taskCB)
任务唤醒
UINT32 taskID
const SchedOps * ops
UINT16 taskStatus
size_t LOS_ArchCopyFromUser(void *dst, const void *src, size_t len)
Definition: user_copy.c:58