当前位置: 首页 > news >正文

Linux osq_lock

文章目录

  • osq_lock函数
    • 相关数据结构
    • 11虚线处
    • 22虚线处
    • step A
    • step B
    • step C
  • 为什么next指针不可靠
  • 参考

内核版本:5.15

osq_lock(optimistic spin queue)当内核配置CONFIG_MUTEX_SPIN_ON_OWNER时,mutex支持乐观自旋,osq成员就是乐观自旋需要持有的MCS锁队列。

osq_lock函数

bool osq_lock(struct optimistic_spin_queue *lock)
{struct optimistic_spin_node *node = this_cpu_ptr(&osq_node);struct optimistic_spin_node *prev, *next;int curr = encode_cpu(smp_processor_id());int old;node->locked = 0;node->next = NULL;node->cpu = curr;old = atomic_xchg(&lock->tail, curr);if (old == OSQ_UNLOCKED_VAL)return true;prev = decode_cpu(old);node->prev = prev;smp_wmb();WRITE_ONCE(prev->next, node);
//------------------11------------------------if (smp_cond_load_relaxed(&node->locked, VAL || need_resched() ||vcpu_is_preempted(node_cpu(node->prev))))return true;
//------------------22------------------------/* unqueue *//** Step - A  -- stabilize @prev*/for (;;) {if (data_race(prev->next) == node &&cmpxchg(&prev->next, node, NULL) == node)break;if (smp_load_acquire(&node->locked))return true;cpu_relax();prev = READ_ONCE(node->prev);}/** Step - B -- stabilize @next*/next = osq_wait_next(lock, node, prev);if (!next)return false;/** Step - C -- unlink*/WRITE_ONCE(next->prev, prev);WRITE_ONCE(prev->next, next);return false;
}

相关数据结构

//per cpu 变量
struct optimistic_spin_node {struct optimistic_spin_node *next, *prev;int locked; /* 1 if lock acquired */int cpu; /* encoded CPU # + 1 value */
};//cpu共享变量
struct optimistic_spin_queue {/** Stores an encoded value of the CPU # of the tail node in the queue.* If the queue is empty, then it's set to OSQ_UNLOCKED_VAL.*/atomic_t tail;
};

11虚线处

将本CPU所在percpu的node节点加入node链表的尾部,并修改queue类型的lock->tail指向自己,如下图的两种情况将节点d加入:
在这里插入图片描述

22虚线处

自选等待。如果node->locked==1,return true 即获得锁成功,直接返回;如果虚拟cpu被抢占或需要调度,smp_cond_load_relaxed函数返回false,其逻辑如下:

	if (smp_cond_load_relaxed(&node->locked, VAL || need_resched() ||vcpu_is_preempted(node_cpu(node->prev))))return true;

在这里插入图片描述
往下走step A / step B / step C完成unqueue也即退出自旋。

step A

等待稳定前节点,然后断开前节点对自身的指向。

	for (;;) {if (data_race(prev->next) == node && //为什么要做这个判断?cmpxchg(&prev->next, node, NULL) == node)break;if (smp_load_acquire(&node->locked))return true;cpu_relax();prev = READ_ONCE(node->prev);}

第一个if为什么要判断?因为会出现data_race(prev->next)==0的情况。原因请看为什么next指针不可靠章节

step B

等待稳定后节点,然后断开自己指向的后节点,如果lock->tail指向自己,修改为指向前一个或空。
osq_wait_next中的for循环:

	for (;;) {if (atomic_read(&lock->tail) == curr &&atomic_cmpxchg_acquire(&lock->tail, curr, old) == curr) {break;}if (node->next) {next = xchg(&node->next, NULL);if (next)break;}cpu_relax();}

node->next已经不为空了,为什么还要if (next)的判断?原因请看为什么next指针不可靠章节

step C

断开自己,具体动作为将前后节点互相指向。

为什么next指针不可靠

在这里插入图片描述
这里假定获得锁的是a,当前正在退出自旋的是c,它的退出过程是上图的1->2->3->4,具体对应的代码正是step A/B/C。

回到step A中data_race(prev->next)==0的情况是怎么出现的,此时c在退出队列,同时b也在自己的CPU上退出,也会经历跟c一样的1->2->3->4的过程,如果此时b
正发生了c中2,也即b->next=0,此时c就要等b完成退出并b的前后搭建好,就像c的3和4。

回到step B中node->next已经不为空了,还要if (next)判断的情况。

参考

【进程同步】osq锁

http://www.dtcms.com/a/482867.html

相关文章:

  • SSM共享汽车管理系统300fw(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
  • Docker安装部署FileBrowser
  • 基于单片机频率周期脉宽测量系统Proteus仿真(含全部资料)
  • wap网站制作模板电影网站开发api
  • xss-labs通关(2)
  • 前后端分离项目前端页面开发远程调试代理解决跨域问题方法
  • 商城网站都有哪 些功能企业网站搭建方案
  • AI让404变品牌秀场:用提示词秒生成个性化错误文案
  • [2025.10.14]Win11.25H2企业版26220.6780深度精简优化 PIIS出品 1.9GB
  • Python路径操作革命:拥抱pathlib
  • 逻辑学是什么浅谈
  • 在阿里巴巴上做网站要多少钱阿里巴巴网站官网
  • 在 orin 上 安装了 miniconda 如何使用 orin 内置的 opencv
  • keil工具详细入门教学
  • 招聘网站开发方案doc蒸丞文化传媒有限公司网页设计
  • Linux中NUMA节点初始化内存相关参数的实现
  • [Backstage] 后端服务 | 示例插件
  • 黑马商城day2-Docker
  • 赤水市住房和城乡建设局网站网站建设费专票会计分录
  • 前端页面权限管控-高阶组件
  • 什么是脚本语言?
  • AI智能体
  • 企业准备扩大规模时,如何选择第三方物流(3PL)合作伙伴
  • 阮一峰《TypeScript 教程》学习笔记——简介
  • Scope作用域
  • 网页设计网站名字上海企业电话查询
  • 论文阅读-IDFUZZ: Intelligent Directed Grey-box Fuzzing
  • [论文阅读]Progent: Programmable Privilege Control for LLM Agents
  • 内蒙古建设厅官网站自建本地网站服务器wordpress
  • 【愚公系列】《人工智能70年》078-AI塑造新人生(教育史上的“一场数字海啸“)