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

linux 其他版本RCU

1、不可抢占RCU

如果我们的需求是“不管内核是否编译了可抢占RCU,都要使用不可抢占RCU”,那么应该使用不可抢占RCU的专用编程接口。
读者使用函数rcu_read_lock_sched()标记进入读端临界区,使用函数rcu_read_unlock_ sched()标记退出读端临界区。读端临界区可以嵌套。
在读端临界区里面应该使用宏rcu_dereference_sched(p)访问指针,这个宏封装了数据依赖屏障,即只有阿尔法处理器需要的读内存屏障。
写者可以使用下面4个函数。
(1)使用函数synchronize_sched()等待宽限期结束,即所有读者退出读端临界区,然后写者执行下一步操作。这个函数可能睡眠。
(2)使用函数synchronize_sched_expedited()等待宽限期结束。和函数synchronize_sched()的区别是:该函数会向其他处理器发送处理器间中断请求,强制宽限期快速结束。
(3)使用函数call_rcu_sched()注册延后执行的回调函数,把回调函数添加到RCU回调函数链表中,立即返回,不会阻塞。
(4)使用函数rcu_barrier_sched()等待使用call_rcu_sched注册的所有回调函数执行完。这个函数可能睡眠。
不可抢占 RCU 通过以下事件观察到静止状态。
(1)进程调度器调度进程。因为不可抢占 RCU 的读端临界区禁止内核抢占,所以进程调度器不会在读端临界区里面调度进程。如果进程调度器调度进程,处理器一定不在读端临界区里面。
(2)当前进程正在用户模式下运行。
(3)处理器空闲,正在执行空闲线程。


2、加速版不可抢占RCU

加速版不可抢占RCU在软中断很多的情况下可以缩短宽限期。

读者使用函数rcu_read_lock_bh()标记进入读端临界区,使用函数rcu_read_unlock_bh()标记退出读端临界区。读端临界区可以嵌套。

在读端临界区里面应该使用宏rcu_dereference_bh(p)访问指针,这个宏封装了数据依赖屏障,即只有阿尔法处理器需要的读内存屏障。

写者可以使用下面4个函数。

(1)使用函数synchronize_rcu_bh()等待宽限期结束,即所有读者退出读端临界区,然后写者执行下一步操作。这个函数可能睡眠。

(2)使用函数synchronize_rcu_bh_expedited()等待宽限期结束。和函数synchronize_rcu_ bh()的区别是:该函数会向其他处理器发送处理器间中断请求,强制宽限期快速结束。

(3)使用函数call_rcu_bh注册延后执行的回调函数,把回调函数添加到RCU回调函数链表中,立即返回,不会阻塞。

(4)使用函数rcu_barrier_bh()等待使用call_rcu_bh注册的所有回调函数执行完。这个函数可能睡眠。

加速版不可抢占 RCU 通过以下事件观察到静止状态。

(1)执行完软中断。因为 RCU-bh 的读端临界区禁止软中断,所以进程在读端临界区里面不会被软中断抢占。考虑到软中断也可能执行读端临界区,所以执行完软中断的时候, 处理器一定不在读端临界区里面。

(2)当前进程正在用户模式下运行。

(3)处理器空闲,正在执行空闲线程。

(4)处理器没有执行软中断或没有禁止软中断的代码区域。

3、链表操作的RCU版本

RCU最常见的使用场合是保护大多数时候读的双向链表。内核实现了链表操作的RCU版本,这些操作封装了内存屏障。

内核实现了4种双向链表。

(1)链表“list_head”。

(2)链表“hlist”:和链表“list_head”相比,优势是头节点只有一个指针,节省内存。

(3)链表“hlist_nulls”。hlist_nulls是hlist的变体,区别是:链表hlist的结束符号是一个空指针;链表hlist_nulls的结束符号是“ (1UL | (((long)value) << 1)) ”,最低位为1,value是嵌入的值,比如散列桶的索引。

(4)链表“hlist_bl”。hlist_bl是hlist的变体,链表头节点的最低位作为基于位的自旋锁保护链表。

链表“list_head”常用的操作如下。

(1)list_for_each_entry_rcu(pos, head, member)

遍历链表,这个宏封装了只有阿尔法处理器需要的数据依赖屏障。

(2)void list_add_rcu(struct list_head *new, struct list_head *head)

把节点添加到链表首部。

(3)void list_add_tail_rcu(struct list_head *new, struct list_head *head)

把节点添加到链表尾部。

(4)void list_del_rcu(struct list_head *entry)

把节点从链表中删除。

(5)void list_replace_rcu(struct list_head *old, struct list_head *new)

用新节点替换旧节点。

链表“hlist”常用的操作如下。

(1)hlist_for_each_entry_rcu(pos, head, member)

遍历链表。

(2)void hlist_add_head_rcu(struct hlist_node *n, struct hlist_head *h)

把节点添加到链表首部。

(3)void hlist_add_tail_rcu(struct hlist_node *n, struct hlist_head *h)

把节点添加到链表尾部。

(4)void hlist_del_rcu(struct hlist_node *n)

把节点从链表中删除。

(5)void hlist_replace_rcu(struct hlist_node *old, struct hlist_node *new)

用新节点替换旧节点。

链表“hlist_nulls”常用的操作如下。

(1)hlist_nulls_for_each_entry_rcu(tpos, pos, head, member)

遍历链表。

(2)void hlist_nulls_add_head_rcu(struct hlist_nulls_node *n, struct hlist_nulls_head *h)

把节点添加到链表首部。

(3)void hlist_nulls_add_tail_rcu(struct hlist_nulls_node *n, struct hlist_nulls_head *h)

把节点添加到链表尾部。

(4)void hlist_nulls_del_rcu(struct hlist_nulls_node *n)

把节点从链表中删除。

链表“hlist_bl”常用的操作如下。

(1)hlist_bl_for_each_entry_rcu(tpos, pos, head, member)

遍历链表。

(2)void hlist_bl_add_head_rcu(struct hlist_bl_node *n, struct hlist_bl_head *h)

把节点添加到链表首部。

(3)void hlist_bl_del_rcu(struct hlist_bl_node *n)

把节点从链表中删除。

4、slab缓存支持RCU

创建slab缓存的时候,可以使用标志SLAB_TYPESAFE_BY_RCU(旧的名称是SLAB_ DESTROY_BY_RCU),延迟释放slab页到RCU宽限期结束,例如:
struct kmem_cache *anon_vma_cachep;
anon_vma_cachep = kmem_cache_create("anon_vma", sizeof(struct anon_vma),
                   0, SLAB_TYPESAFE_BY_RCU|SLAB_PANIC|SLAB_ACCOUNT,
                   anon_vma_ctor);
注意:标志SLAB_TYPESAFE_BY_RCU只会延迟释放slab页到RCU宽限期结束,但是不会延迟对象的释放。当调用函数kmem_cache_free()释放对象时,对象的内存被释放了,可能立即被分配给另一个对象。如果使用散列表,新的对象可能加入不同的散列桶。所以查找对象的时候一定要小心。
 
针对使用函数kmalloc()从通用slab缓存分配的对象,提供了函数“kfree_rcu(ptr, rcu_ head)”来延迟释放对象到RCU宽限期结束,参数rcu_head是指针ptr指向的结构体里面类型为“struct rcu_head”的成员的名称。例如:
typedef struct {
    struct list_head link;
    struct rcu_head rcu;
    int key;
    int val;
} test_entry;
test_entry *p;
p = kmalloc(sizeof(test_entry), GFP_KERNEL);

kfree_rcu(p, rcu);
 
举例说明,假设对象从设置了标志SLAB_TYPESAFE_BY_RCU的slab缓存分配内存,对象加入散列表,散列表如下:
struct hlist_nulls_head table[TABLE_SIZE];
初始化散列桶的时候,把散列桶索引嵌入到链表结束符号中,其代码如下:
for (i = 0; i < TABLE_SIZE; i++) {
     INIT_HLIST_NULLS_HEAD(&table[i], i);
}
查找对象的算法如下:
1      head = &table[slot];
2      rcu_read_lock();
3   begin:
4      hlist_nulls_for_each_entry_rcu(obj, node, head, hash_node) {
5         if (obj->key == key) {
6            if (!atomic_inc_not_zero(obj->refcnt)) {
7               goto begin;
8            }
9   
10           if (obj->key != key) {
11               put_ref(obj);
12               goto begin;
13            }
14            goto out;
15     } 
16   
17     if (get_nulls_value(node) != slot) {
18        goto begin;
19     }
20     obj = NULL;
21   
22   out:
23      rcu_read_unlock();
第6~8行代码,找到对象以后,如果引用计数不是0,把引用计数加一;如果引用计数是0,表示对象已经被释放,应该在散列桶中重新查找对象。
第10~13行代码,把引用计数加1以后,需要重新比较关键字。如果关键字不同,说明对象的内存被释放以后立即分配给新的对象,应该在散列桶中重新查找对象。
第17~19行代码,如果遍历完一个散列桶,没有找到对象,那么需要比较链表结束符号中嵌入的散列桶索引。如果不同,说明对象的内存被释放以后立即分配给新的对象,新对象的散列值不同,加入了不同的散列桶。需要在散列桶中重新查找对象。
插入对象的算法如下:
obj = kmem_cache_alloc(cachep);
if (obj == NULL) {
     return -ENOMEM;
}
obj->key = key;
atomic_set(&obj->refcnt, 1);
lock_chain(); /* 通常是spin_lock() */
hlist_nulls_add_head_rcu(&obj->hash_node, &table[slot]);
unlock_chain(); /* 通常是spin_unlock() */
删除对象的算法如下:
if (atomic_dec_and_test(obj->refcnt)) {
    lock_chain(); /* 通常是spin_lock() */
    hlist_nulls_del_rcu(&obj->hash_node);
    unlock_chain(); /* 通常是spin_unlock() */
    kmem_cache_free(cachep, obj);
}

RCU在内核源码中的使用可以阅读trie路由模块。

相关文章:

linux 其他版本RCU

1、不可抢占RCU 如果我们的需求是“不管内核是否编译了可抢占RCU&#xff0c;都要使用不可抢占RCU”&#xff0c;那么应该使用不可抢占RCU的专用编程接口。 读者使用函数rcu_read_lock_sched()标记进入读端临界区&#xff0c;使用函数rcu_read_unlock_ sched()标记退出读端临界…...

【单调栈】LeetCode:2818操作使得分最大

作者推荐 map|动态规划|单调栈|LeetCode975:奇偶跳 涉及知识点 单调栈 题目 给你一个长度为 n 的正整数数组 nums 和一个整数 k 。 一开始&#xff0c;你的分数为 1 。你可以进行以下操作至多 k 次&#xff0c;目标是使你的分数最大&#xff1a; 选择一个之前没有选过的 非…...

uniapp 添加分包页面,配置分包预下载

为什么要分包 ? 分包即将小程序代码分成多个部分打包&#xff0c;可以减少小程序的加载时间&#xff0c;提升用户体验 添加分包页面 比较便捷的方法是使用vscode插件 uni-create-view 新建分包文件夹 以在我的页面&#xff0c;添加分包的设置页面为例&#xff0c;新建文件夹 s…...

成功案例分享:物业管理小程序如何助力打造智慧社区

随着科技的进步和互联网的普及&#xff0c;数字化转型已经渗透到各个行业&#xff0c;包括物业管理。借助小程序这一轻量级应用&#xff0c;物业管理可以实现线上线下服务的无缝对接&#xff0c;提升服务质量&#xff0c;优化用户体验。本文将详细介绍如何通过乔拓云网设计小程…...

Electron执行本地cmd命令

javascript执行本地cmd命令,javascript代码怎么执行_js调用本机cmd-CSDN博客 使用 Node.js 打开本地应用_nodejs启动应用-CSDN博客 笔记:nodejs脚本唤醒本地应用程序或者调用命令-CSDN博客 electron调起本地应用_electron 调用本地程序-CSDN博客 命令行打开vscode 你可以使用…...

YOLOv8改进 | 主干篇 | 利用MobileNetV3替换Backbone(轻量化网络结构)

一、本文介绍 本文给大家带来的改进机制是MobileNetV3&#xff0c;其主要改进思想集中在结合硬件感知的网络架构搜索&#xff08;NAS&#xff09;和NetAdapt算法&#xff0c;以优化移动设备CPU上的性能。它采用了新颖的架构设计&#xff0c;包括反转残差结构和线性瓶颈层&…...

MATLAB Mobile - 使用预训练网络对手机拍摄的图像进行分类

系列文章目录 前言 此示例说明如何使用深度学习对移动设备摄像头采集的图像进行分类。 在您的移动设备上安装和设置 MATLAB Mobile™。然后&#xff0c;从 MATLAB Mobile 的“设置”登录 MathWorks Cloud。 在您的设备上启动 MATLAB Mobile。 一、在您的设备上安装 MATLAB M…...

LangChain入门指南:定义、功能和工作原理

LangChain入门指南&#xff1a;定义、功能和工作原理 引言LangChain是什么&#xff1f;LangChain的核心功能LangChain的工作原理LangChain实际应用案例如何开始使用LangChain 引言 在人工智能的浪潮中&#xff0c;语言模型已成为推动技术革新的重要力量。从简单的文本生成到复…...

关键字:import关键字

在 Java 中&#xff0c;import关键字用于导入类或接口&#xff0c;使你可以在代码中使用它们而无需完全限定其名称。以下是使用import关键字的示例代码&#xff1a; 在上述示例中&#xff0c;通过使用import关键字导入了java.util.ArrayList类&#xff0c;这样就可以在代码中直…...

【C#】.net core 6.0 通过依赖注入注册和使用上下文服务

给自己一个目标&#xff0c;然后坚持一段时间&#xff0c;总会有收获和感悟&#xff01; 请求上下文是指在 Web 应用程序中处理请求时&#xff0c;包含有关当前请求的各种信息的对象。这些信息包括请求的头部、身体、查询字符串、路由数据、用户身份验证信息以及其他与请求相关…...

关于redis单线程和IO多路复用的理解

首先&#xff0c;Redis是一个高性能的分布式缓存中间件。其复杂性不言而喻&#xff0c;对于Redis整体而言肯定不是只有一个线程。 我们常说的Redis 是单线程&#xff0c;主要是指 Redis 在网络 IO和键值对读写是采用一个线程来完成的&#xff0c;这也是 Redis 对外提供键值存储…...

第四十一章 XML 映射参数摘要

文章目录 第四十一章 XML 映射参数摘要 第四十一章 XML 映射参数摘要 TopicParameters启用 XML 映射。XMLENABLED 类参数将属性映射到元素或属性。XMLPROJECTION property parameter ("NONE", "ATTRIBUTE", "XMLATTRIBUTE", "CONTENT"…...

redis之五种基本数据类型

一) 字符串(String) 1 使用场景 2 编码 3 编码转换 二) List(列表) 1 使用场景 2 编码 三) Set(无序集合) 1 使用场景 2 编码 3 编码转换 四) ZSet(有序集合) 1 使用场景 2 编码 3 编码转换 五) Hash 1 使用场景 2 编码 3 编码转换 五种基本数据类型 redis…...

RocketMQ系统性学习-RocketMQ高级特性之消息大量堆积处理、部署架构和高可用机制

&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308; 【11来了】文章导读地址&#xff1a;点击查看文章导读&#xff01; &#x1f341;&#x1f341;&#x1f341;&#x1f341;&#x1f341;&#x1f341;&#x1f3…...

Angular 进阶之五: Signals到底用不用?

Angular 在V16的时候推出了Signals&#xff0c;在17正式作为主打功能之一强烈推荐&#xff0c;看过了各种博主的各种科普文章也没说明白&#xff0c;到底这东西值不值得用&#xff1f;毕竟项目大了&#xff0c;重构代码也不是闹着玩儿的。各种科普文章主要在说两点&#xff1a;…...

构建数字化金融生态系统:云原生的创新方法

内容来自演讲&#xff1a;曾祥龙 | DaoCloud | 解决方案架构师 摘要 本文探讨了金融企业在实施云原生体系时面临的挑战&#xff0c;包括复杂性、安全、数据持久化、服务网格使用和高可用容灾架构等。针对网络管理复杂性&#xff0c;文章提出了Spiderpool开源项目&#xff0c;…...

前端性能优化五:css和js位置

1. 精简HTML代码: ①. css链接文件尽量放在页面头部:a. css的加载不会阻塞DOM Tree的解析.b. 但会阻塞DOM Tree渲染,也会阻塞后面JS的执行.c. 将css放在任何body元素之前:(1). 可以确保在文档中解析了所有css的样式包括内联样式和外联的.(2). 减少了浏览器必须重排文档的次数.…...

苏州耕耘无忧物联网:降本增效,设备维护管理数字化转型的引领者

随着科技的快速发展和工业4.0的推动&#xff0c;设备维护管理已经从传统的被动式、经验式维护&#xff0c;转向了更加积极主动、数据驱动的维护模式。在这个过程中&#xff0c;苏州耕耘无忧物联科技有限公司以其深厚的技术积累和丰富的管理经验&#xff0c;引领着设备维护管理数…...

15个热门的开源数据可视化项目

数据可视化(即 BI仪表盘)是图形表示的数据。它涉及产生将表示的数据之间的关系传达给图像查看者的图像。这种通信是通过在可视化过程中使用图形标记和数据值之间的系统映射来实现的。该映射建立了如何在视觉上表示数据值,确定图形标记的属性(例如大小或颜色)如何以及在多大程…...

【第七在线】数据分析与人工智能在商品计划中的应用

随着技术的不断进步&#xff0c;数据分析和人工智能&#xff08;AI&#xff09;已经成为了现代商品计划的关键组成部分。在服装行业&#xff0c;这两项技术正在帮助企业更好地理解市场需求、优化库存管理、提高生产效率和提供更好的客户体验。本文将深入探讨数据分析和人工智能…...

开发提效新组合:用Cursor编写核心逻辑,快马平台一键生成完整企业级项目

今天想和大家分享一个提升开发效率的实用组合&#xff1a;用Cursor编写核心业务逻辑&#xff0c;再通过InsCode(快马)平台一键生成完整项目。最近在开发一个企业内部工时管理系统时&#xff0c;这套组合拳帮我节省了大量重复劳动时间。 1. 为什么选择这个技术组合 开发企业级…...

AI辅助开发winner1300图像处理:用自然语言描述自动生成并行滤波代码

今天尝试用AI辅助开发一个基于winner1300框架的图像并行处理项目&#xff0c;整个过程比想象中顺利很多。记录下这个用自然语言描述就能生成完整代码的神奇体验。 项目需求分析 我需要实现一个能同时应用高斯模糊和边缘检测滤镜的图像处理工具。核心难点在于如何利用winner1300…...

万象视界灵坛实战教程:构建小红书爆款笔记封面图‘高点击率特征’预测模型

万象视界灵坛实战教程&#xff1a;构建小红书爆款笔记封面图高点击率特征预测模型 1. 项目背景与价值 在内容创作领域&#xff0c;封面图的质量直接影响用户点击率。小红书平台数据显示&#xff0c;优质封面图能带来300%以上的点击率提升。然而&#xff0c;传统封面设计依赖人…...

MySQL数据库基础聚合函数

聚合函数...

Pixel Epic动态卷轴技术揭秘:TextIteratorStreamer流式输出实现原理与调优

Pixel Epic动态卷轴技术揭秘&#xff1a;TextIteratorStreamer流式输出实现原理与调优 1. 引言&#xff1a;像素史诗的独特体验 Pixel Epic&#xff08;像素史诗&#xff09;作为一款研究报告辅助终端&#xff0c;最引人注目的特点莫过于其独特的"动态卷轴"输出效果…...

从真题到实战:拆解CCF-GESP C++三级核心考点与避坑指南

1. 数据编码&#xff1a;从ASCII到UTF-8的实战解析 在CCF-GESP C三级考试中&#xff0c;数据编码是必考的核心知识点。很多同学第一次接触这个概念时容易懵圈——不就是存个字符吗&#xff0c;怎么还有这么多门道&#xff1f;其实理解编码就像学外语&#xff0c;ASCII是基础英语…...

Obsidian LaTeX Suite终极指南:让数学公式编辑如行云流水

Obsidian LaTeX Suite终极指南&#xff1a;让数学公式编辑如行云流水 【免费下载链接】obsidian-latex-suite Make typesetting LaTeX as fast as handwriting through snippets, text expansion, and editor enhancements 项目地址: https://gitcode.com/gh_mirrors/ob/obsi…...

储能电站EMS系统实战指南:从硬件选型到软件配置的完整避坑手册

储能电站EMS系统实战指南&#xff1a;从硬件选型到软件配置的完整避坑手册 在新能源行业快速发展的今天&#xff0c;储能电站作为电力系统中的关键调节单元&#xff0c;其能量管理系统&#xff08;EMS&#xff09;的稳定性和智能化水平直接决定了电站的经济效益和运行安全。然而…...

Python从入门到精通(第14章):迭代器与生成器

开头导语 这是本系列第14章。前面你已经用过很多次迭代器和生成器——for x in data 的背后是什么,map 返回的对象为什么不能下标访问,range 为什么不会占很多内存——这些问题的答案都在本章。通过亲手实现一个迭代器类,你会对 Python 迭代协议有清晰的认识,遇到相关错误…...

Arctic与ArcticDB对比分析:为何选择下一代数据存储方案

Arctic与ArcticDB对比分析&#xff1a;为何选择下一代数据存储方案 【免费下载链接】arctic High performance datastore for time series and tick data 项目地址: https://gitcode.com/gh_mirrors/ar/arctic 在金融数据分析和时间序列处理领域&#xff0c;高性能数据…...