1.PolarDB-X 源码解读(七):私有协议连接的文源一生(CN篇)
2.FFmpeg 流媒体处理 - 收流与推流
3.FPGA高端项目:FPGA基于GS2971+GS2972架构的SDI视频收发+HLS多路视频融合叠加,提供1套工程源码和技术支持
4.如何在手机上快速预览OfficePDF等文档你只需要一个应用DocsApp1
5.紫光同创FPGA实现HSSTLP高速接口通信,码收码8b/10b编解码数据回环,录源提供PDS工程源码和技术支持
6.Linux 中断( IRQ / softirq )基础:原理及内核实现
PolarDB-X 源码解读(七):私有协议连接的文源一生(CN篇)
通过前文的介绍,大家基本了解了一条SQL在polardbx-sql中的码收码解析和执行流程。由于polardbx-sql是录源qq滑动识别源码无状态的计算节点,真正数据需要从存储节点传输到计算节点,文源这部分工作由私有协议完成。码收码本文将详细介绍从发送请求到存储节点,录源接收返回数据的文源完整流程,重点在于私有协议连接的码收码生命周期和关键代码解析。
概述
为了提高数据节点本地计算能力,录源同时减少网络数据传输量,文源计算节点会尽可能下推计算内容。码收码一个逻辑表可能需要多个物理分片,录源因此计算节点与存储节点的请求会话数量会随着分片数增加而增加。传统MySQL协议+连接池架构已不能满足PolarDB-X的需求,因此私有协议在这一需求场景下应运而生。
如图所示,私有协议采用连接与会话分离的RPC协议设计理念,支持多个会话在同一个TCP通道中并行运行,具备流控机制、全双工响应式工作模式和高吞吐、可扩展等特性。
更多关于私有协议解决上述问题的设计详情,可以参考《PolarDB-X私有协议设计》一文。本文主要从代码层面详细描述私有协议的工作流程。
我们将从计算节点和存储节点两个角度完整解析私有协议连接的生命周期。篇幅限制,本文仅关注计算节点上私有协议的处理,存储节点部分将在后续文章中详细说明。
计算节点
计算节点作为私有协议的客户端,负责发送下推请求,并接收返回的数据。
网络层框架
PolarDB-X私有协议网络层采用定制化Reactor框架实现,基于Java的NIO,改进自polardbx-sql中的Reactor框架。网络层初始化时,设置CPU核心数的2倍(上限为)作为NIOProcessor,每个Reactor使用独立的堆外内存池作为收发包缓冲,总缓冲内存大小限制为堆内存大小的%。
NIO接收的包直接调用注册的处理函数,发送数据仅写入send buf,网络写入由单独线程完成。线程优先写入TCP send buf,当无法写入时,注册OP_WRITE事件等待可写后再写入剩余内容。
数据包的编码和解码在NIOClient中实现。为实现最佳性能,解包流程直接在堆外内存上进行,使用protobuf对流直接解析,将结果放入堆内。堆外内存被切分为KB chunk,每个Reactor独占一个chunk,连续解析和复用,最大化接收、解析效率。对于特大包,额外构造堆内大buffer接收和解析,回退标志在定时任务中重置,连续s无超大包时释放堆内内存,恢复高性能堆外KB buffer接收。
请求发送集成在NIOClient中,writer优先尝试写入发送缓冲队列尾部的buffer,不足时新申请buffer填充并追加到队尾。buffer来自预分配的堆外缓冲池,超过chunk大小时分配堆内buf进行序列化。
同时,NIOClient负责TCP连接的建立和断开资源释放,作为独立的底层网络资源管理实现。
连接及会话
网络层之后,我们聚焦连接与会话分离的具体实现。通过剥离连接及收发包的具体实现,连接和会话的管理变得更加清晰简洁。
首先,一个TCP连接的逻辑抽象结构在XClient中实现,为避免误解,取名为client与JDBC中的Connection区别。该类管理TCP连接和并行运行的会话,负责TCP完整生命周期的希望ol源码管理、认证鉴权,并维护公共信息。其中,workingSessionMap记录了连接上并行运行的所有会话映射关系,可快速通过会话ID找到对应的会话抽象结构XSession。
XSession提供了所有会话相关的请求函数和信息存储,包括执行计划请求、SQL查询请求、SQL更新请求、TSO请求、会话变量处理、数据包处理及异步唤醒等。
连接池及全局单例管理器
为了提高性能,TCP连接和会话的复用必不可少。由于连接和会话的解绑,连接池不仅缓存了到计算节点的TCP连接,也缓存了到计算节点的会话。
XClientPool管理到一个存储节点的连接池,通过IP,端口,用户名三元组唯一确定目标存储节点,同时存储该节点的全部TCP连接(XClient)和建立的会话(XSession)。
XClientPool实现存储节点会话获取,对应JDBC接口中的getConnection,同时实现连接和会话生命周期管理、连接探活、会话预分配等功能。实现单个存储节点连接池后,XConnectionManager维护目标存储节点三元组到实例连接池的映射,管理定时任务线程池,实现定时探活、会话&连接最长生命控制以及连接池预热等功能。
JDBC兼容层
新的SQL协议层对上层使用者要求较高,为了提高开发效率,私有协议提供兼容JDBC的使用方法,实现从JDBC平滑切换至私有协议,并支持协议热切换。
JDBC兼容层代码目录在compatible目录下,Connection继承在XConnection文件中。提供包括DataSource、Connection、Statement、PreparedStatement、ResultSet、ResultSetMetaData在内的大部分常用接口函数实现,不支持的函数会明确抛出异常避免误用。
整体关系
至此,私有协议计算节点端的大部分结构已说明完成。给出一个整体的关系图。
私有协议连接的一生(CN视角)
了解了私有协议各层实现后,我们以发到存储节点的请求为例,完整梳理执行流程。绕开计算节点复杂流程,直接运行代码示例(注:需将com.alibaba.polardbx.rpc.XConfig#GALAXY_X_PROTOCOL设置为true)。
直接运行playground看到预期的select 1的结果。接下来,我们深入跟踪说明。
数据源初始化
要使用私有协议,需要初始化对应存储节点的XDataSource。构造过程中,XDataSource会到XConnectionManager注册新的实例连接池,已存在的连接池引用计数加一。
获取Connection
当需要执行查询时,首先获取会话。无论是显式开启事务还是使用auto commit事务,会话都是执行请求的最小上下文。通过XDataSource的getConnection方法获取到对应存储节点的会话。XDataSource根据存储的IP,端口,用户名三元组查找到XConnectionManager中的连接池,在最高并发检查后,会话获取逻辑在XClientPool实现。首先尝试在空闲会话池中拿会话,通过重置检查和初始化后返回给调用者。大部分场景下,ConcurrentLinkedQueue提供较好的并发性能。
在代码场景下,数据源刚新建,后台定时任务未运行,rpgmv存档源码流程进入连接创建流程。会有一把大锁锁住连接池,在TCP连接未达上限且没有超时的情况下,快速新建一个XClient占坑。若超限,则进入busy waiting循环。真正的TCP connect(waitChannel)在锁外被调用,首先client以阻塞模式带超时方式connect,然后切换为非阻塞模式,round robin策略注册到NIOProcesser上,返回时,TCP连接已建立。
为了兼顾安全和性能,连接鉴权在TCP建连后只用做一次,会话创建不需要鉴权。鉴权在initClient中完成,发送SESS_AUTHENTICATE_START_VALUE包,后续校验由回调完成。认证采用标准的MySQL认证流程,server端返回challenge值,库名、用户名和加盐hash后的密码返回给MySQL即可完成认证。
至此,到存储节点的TCP连接已建立,创建会话是一个异步流程。在创建新XClient时,XConnection已new好,通过下断点跟进去可看到newXSession流程,分配session id,设置状态为init,将XSession绑定到XConnection上。
最后,XConnection经过初始化(重置auto commit状态)、重置默认DB、默认字符集(lazy操作)和统计信息记录,返回给用户使用。
发送查询请求
拿到初始化好的兼容JDBC的Connection,为了简化流程,直接调用XConnection中的execQuery。XConnection的execQuery包装了XSession的execQuery,执行前执行了设置流式模式。
首先记录调用信息进行统计,进入关键的initForRequest流程。XSession初始化流程lazy,仅分配session id,设置状态为Init,真正创建session时发送SESS_NEW给server,绑定新session和session id。如果session已复用,则状态为Ready。
执行字符集更改的lazy操作,session可能在其他请求中切换字符集,根据目标字符集和当前字符集对比,决定是否发送额外的字符集更改请求。
经过一系列变量设置、lazy DB设置和protobuf包构造,请求发送到存储节点执行。发送后,同步生成XResult负责结果解析,同时XResult按照请求顺序依次拉链表,确保结果与请求一一对应。
请求流水线结构如下图所示,处理完成前序请求后,才能解析后续结果。
接收结果集
请求已发送到存储节点执行,拿到XResult,通过XResult收集查询结果集。XResult与发送请求一一对应,存储节点处理也是在会话上排队进行,不会影响流水线上其他请求的返回,保证流水线正常工作。
首先,查看结果集处理的状态机,主要状态包括获取元数据、获取数据行、获取额外信息等,顺序固定,根据请求类型,部分环节可能被省略。dz cs 源码报错处理贯穿整个状态机,任何报错信息都会导致状态机进入错误处理环节。
对于非流式数据读取,请求结束时主动调用finishBlockMode将所有数据读出并缓存到rows中。对于流式执行的情况,结果集状态机消费数据包队列由XResult的next函数推动,内部函数internalFetchOneObject递归调用前序XResult,消费前序请求结果,从数据包队列中消费并推动状态机流转。
对于查询,首先收到RESULTSET_COLUMN_META_DATA包,表示返回数据列定义,一个包表示一列。元数据包后,收到包含数据行的RESULTSET_ROW包,一个包对应一行。数据行传输完成后,server端发送RESULTSET_FETCH_DONE标示数据发送完成。请求结束前,NOTICE包用于告知客户端rows affected等信息。最后,SQL_STMT_EXECUTE_OK包标示请求结束。
至此,完整请求处理完成,控制台应显示查询结果。
总结
本文详细描述了私有协议连接流程中的关键点和关键数据结构,相信通过本文描述,大家掌握了私有协议连接流程的基本点,在调试和修改使用中能够更加得心应手。虽然本文篇幅较长,但实际使用中涉及更多高级特性的使用,如多请求流水线、流控、执行计划传输、chunk结果集传输等。通过本文,我们对私有协议连接流程有了深入理解,为在实际场景中应用提供坚实基础。
FFmpeg 流媒体处理 - 收流与推流
流媒体技术的定义与应用
流媒体,作为多媒体应用技术的一种,指的是通过网络进行分段传输的连续媒体数据,实现即时播放的一种技术与过程。这种技术使得数据包能像流水一样快速传输,避免了必须下载整个媒体文件的传统方式。关于流媒体的基础概念,可参考观止云的“流媒体|从入门到出家”系列文章,了解更多深入信息。
FFmpeg中的流媒体处理层次
FFmpeg在处理音视频数据时,划分了四个层次:协议层、容器层、编码层和原始数据层。协议层提供网络协议收发功能,包括libavformat库与第三方库的支持;容器层处理各种封装格式,由libavformat库提供;编码层负责音视频编码和解码,由libavcodec库与第三方编解码库支持;原始数据层处理未编码的原始音视频帧,由libavfilter库提供支持。本文提及的收流与推流功能,属于协议层的处理。
FFmpeg的协议与封装格式处理
在FFmpeg中,libavformat库提供了丰富的协议处理和封装格式处理功能。在打开输入/输出时,FFmpeg会根据URL来探测输入/输出格式,选择合适的协议和封装格式。例如,输出URL为"rtmp://..0./live"时,FFmpeg会确定使用rtmp协议,封装格式为flv。
流媒体系统中的角色
流媒体系统涉及三个主要角色:流媒体服务器、推流客户端和收流客户端。推流客户端是内容生产者,收流客户端是内容消费者。推流客户端将内容推送到流媒体服务器,收流客户端则从流媒体服务器获取内容。
收流与推流功能
当输入为网络流,输出为本地文件时,实现收流功能,即将网络流存储为本地文件;当输入为本地文件,输出为网络流时,实现推流功能,Elastic search源码即将本地文件推送到网络;当输入和输出均为网络流时,实现转流功能,即将一个流媒体服务器上的流推送到另一个流媒体服务器。
相关视频推荐
相关视频推荐
免费学习地址
免费分享资料包、大厂面试题、技术视频和学习路线图,资料包括(C/C++,Linux,FFmpeg webRTC rtmp hls rtsp ffplay srs 等等)有需要的可以点击加群免费领取哦~
源码与转封装例程
源码与转封装例程大部分相同,可视为转封装例程的增强版。收流代码与打开普通文件的代码无异,FFmpeg能识别流协议及封装格式,使用相应的协议层代码接收流,处理后的数据与普通文件内容一致。推流需要注意封装格式指定和流媒体服务器的处理速度。
测试与验证
测试需要搭建流媒体服务器,推荐使用nginx-rtmp服务器。搭建时,可使用docker镜像简化过程。通过配置docker服务、镜像加速、拉取nginx-rtmp镜像、打开容器、防火墙添加例外端口等步骤完成搭建。测试文件下载、ffmpeg推流、ffplay收流播放,验证服务器功能。
编译与测试
下载例程源码后,执行shell命令下载,并在源码目录执行./compile.sh生成streamer可执行文件。测试文件下载与推流、收流功能,确保系统正常运行。
遗留问题
推流和收流过程中,可能出现结束信息输出,提示程序退出。此类问题通常与系统资源或配置相关,需要根据实际情况进行排查和调整。
FPGA高端项目:FPGA基于GS+GS架构的SDI视频收发+HLS多路视频融合叠加,提供1套工程源码和技术支持
FPGA高端项目:FPGA基于GS+GS架构的SDI视频收发+HLS多路视频融合叠加,提供1套工程源码和技术支持
前言
在FPGA的SDI视频编解码领域,有两种主要方案:一是采用专用编解码芯片(如GS接收器与GS发送器),其优点是简化设计,易于实现,但成本相对较高;二是利用FPGA的逻辑资源自定义SDI编解码,通过Xilinx系列FPGA的GTP/GTX资源进行串行/并行转换,并利用SMPTE SDI资源完成SDI编码与解码,此方案的优势在于高效利用FPGA资源,但对开发者的技术要求更高。在这里,我们提供了一套针对Xilinx Zynq FPGA的解决方案,包括硬件开发板、工程源码与技术支持。
设计概述
本设计基于Xilinx Zynq FPGA,采用GS作为SDI视频接收器,将同轴串行SDI视频解码为BT格式,并转换为HDMI输出。输入源为HD-SDI相机,支持SD-SDI、HD-SDI、3G-SDI等多种格式。解码后的视频经BT转RGB模块转换为RGB格式,随后通过HLS多路视频融合叠加技术,叠加第二路视频,并进行缩放、透明度配置等操作,最终输出为3G-SDI视频格式。
实现流程
1. 视频解码:使用GS接收HD-SDI信号,并解码为BT格式视频。
2. 视频转换:将BT格式视频转换为RGB格式,以便后续处理。
3. 多路视频融合叠加:通过HLS技术,将第二路视频进行缩放、透明度配置后与第一路视频融合叠加。
4. 编码输出:使用GS编码器将处理后的RGB视频转换为SDI信号输出,通过SDI转HDMI盒子展示在显示器上。
工程源码与技术支持
本项目提供完整工程源码与技术支持,包括硬件设计、软件开发、上板调试等全过程。源码涵盖硬件配置、视频处理算法、图像缓存、多路视频融合叠加、编码输出等关键环节。此外,还提供详细的工程设计文档,以便用户快速理解并移植至自定义项目中。
注意事项与移植指南
项目移植时需注意FPGA型号、开发环境版本及硬件配置差异。对于不同的FPGA型号,可能需要调整相应的硬件配置和IP锁。此外,当开发环境版本不一致时,需确保与工程源码版本兼容,可通过升级开发环境或调整工程配置解决。对于纯FPGA项目移植至Zynq系列FPGA,需添加Zynq软核。
总结
本项目旨在提供一套完整的FPGA SDI视频处理解决方案,涵盖硬件设计、软件实现、工程源码与技术支持,适用于毕业设计、项目开发,以及医疗、军工等领域的图像处理应用。通过提供详细的工程源码和指导文档,帮助用户快速掌握SDI视频收发与多路视频融合叠加技术。
如何在手机上快速预览OfficePDF等文档你只需要一个应用DocsApp1
智能手机越来越强大,我们在移动设备上可以随时随地通过各种方式收发文件。
但收发便利并不意味着可以即时处理。为了阅读同事发过来的 Office 文档,你需要安装 WPS 甚至微软办公三件套;为了阅读 PDF 你需要安装 PDF 阅读器;那如果还需要阅读编程代码源文件,那么代码编辑器似乎也必不可少——仅仅是打开这些文档,我们就需要在手机上安装至少三种以上的应用……
而在很多使用场景中,我们只是希望可以在手机上尽快看到文档并做出回馈而已。
因而使用这款名为 Docs 的应用显然更为合适,它支持常见的 Office 办公文档和 PDF 文档,除此之外还可以打开那些编程代码源文件:HTML、XML、PHP、CPP 以及 Java,足以解决少开发者在手机上进行源码阅读的需求。
强大的功能下对应的是其「轻巧」的身材以及「飞快」的文档打开速度。仅 MB 的应用大小却支持如此之多的文件格式,对比那些动辄上百 MB 的微软 Office 套件优势明显;而让我见识到其「飞快」则是对大体积文档的支持,尤其是当我发现一份近 MB 的 PDF 文档在 Docs 可以在两秒之内完全打开后,我觉得他可以完全胜任我那苛刻的文档预览需求。
仅仅只是预览查看办公文档与程序源码?其实 Docs 还可以兼作轻量级的「文档管理器」,打开 Docs 你会觉得倍感熟悉:交互界面和 Android 原生文档管理器几乎一致,唯一的区别在于 Docs 会扫描手机存储空间中支持的文档文件,并通过分类的形式就进行整理。无论是你是从哪里下载的文档,存储在哪个文件夹下,打开 Docs 无需进行搜索,只要找到对应的分类就可以看到文件,非常的方便。
但作为一款主打多格式文档预览的应用,Docs 所有的功能特性也就到此为止。对于更深层次的编辑需求,我们可以在使用 Docs 的过程中调用系统分享接口来选择使用其他编辑工具。
如果你和我一样,纠结于在 Android 平台上找到一款多种文档的查看器,那么轻巧的 Docs 绝对是你的首选:小巧的应用体积、极快的文档打开速度,非常适合在一些轻量化的办公场合中快速阅读文档。至于文档编辑等「重办公场景使用」,还是交给那些专业的工具来搞定吧!
你可以在 Play 应用商店下载到这款免费应用。
紫光同创FPGA实现HSSTLP高速接口通信,8b/b编解码数据回环,提供PDS工程源码和技术支持
紫光同创FPGA实现HSSTLP高速接口通信,8b/b编解码数据回环,提供PDS工程源码和技术支持
在高速接口通信领域,紫光同创的FPGA展现出其独特优势。HSSTLP(High-Speed Serial Transceiver)高速接口协议,结合8b/b编解码技术,实现了数据回环,提供了PDS(Pango Design Suite)工程源码和技术支持。本文将深入探讨紫光同创FPGA在实现HSSTLP高速接口通信的方案,以及如何通过PDS工程实现数据回环测试。
### 1. 前言
紫光同创的FPGA在国产半导体领域迅速崛起,成为自主可控、性价比高、响应迅速的代表。本文旨在介绍如何利用紫光同创的PG2LH-6FBG FPGA实现HSSTLP高速接口通信,提供详细的工程实现方案和源码支持。
### 2. 紫光同创FPGA高速接口解决方案
紫光同创的FPGA通过HSSTLP IP核文件实现高速接口通信,将PCIE IP配置为8b/b编解码协议,支持1.G单线线速。用户可根据需要调整速率进行测试,生成Example工程并进行修改,即可完成数据回环测试。工程源码和技术支持旨在帮助开发者实现高速接口通信的基础,为更高级的应用场景打下坚实基础。
### 3. 工程源码与技术支持
本文提供完整的PDS .4版本工程源码和技术支持,覆盖紫光同创FPGA实现HSSTLP高速接口通信的整个流程。用户可以轻松移植该工程,应用于医疗、军工等行业的高速接口或图像处理领域。
### 4. HSSTLP详解
HSSTLP是紫光同创FPGA集成的串行高速收发器,性能与Xilinx的GTP相媲美。其支持PCI Express、XAUI、千兆以太网、CPRI、SRIO等协议,每通道最高可达6.6 Gb/s传输速率。HSSTLP由两个PLL和四个收发LANE组成,每个LANE包括四个关键组件:PCS Transmitter、PMA Transmitter、PCS Receiver、PMA Receiver,共同实现高速数据的收发。
### 5. 工程设计与实现
本文详细描述了紫光同创FPGA实现HSSTLP高速接口通信的方案,包括HSSTLP的基本结构、时钟管理、PCS与PMA组件的详细功能,以及接口说明。硬件设计部分展示了如何在开发板上实现FPGA与光纤接口SFP的连接,并提供了HSSTLP IP调用和配置的步骤。此外,提供了完整的工程源码和上板调试验证方法,确保了工程的可移植性和实用性。
### 6. PDS工程详解与代码获取
紫光同创FPGA的PDS工程源码包含了从IP核添加、配置到Example工程生成的完整流程。工程已综合编译完成,资源消耗合理。获取代码的方式为通过私信方式提供某度网盘链接,确保了代码的分发安全与便捷性。
总之,本文通过深入解析紫光同创FPGA实现HSSTLP高速接口通信的全过程,提供了完整的工程源码和技术支持,旨在帮助开发者快速实现高速接口通信应用,推动国产FPGA在高精尖领域的自主可控发展。
Linux 中断( IRQ / softirq )基础:原理及内核实现
中断(IRQ),尤其是软中断(softirq)的广泛用途之一是网络数据包的接收与发送,但其应用场景并非单一。本文将全面整理中断(IRQ)与软中断(softirq)的基础知识,这些内容与网络数据包处理虽无直接联系,但整理本文旨在更深入地理解网络数据包处理机制。
什么是中断?
CPU 通过时分复用处理多任务,其中包括硬件任务,如磁盘读写、键盘输入,以及软件任务,如网络数据包处理。CPU 在任何时刻只能执行一个任务。当某个硬件或软件任务当前未被执行,但希望CPU立即处理时,会向CPU发送中断请求——希望CPU暂停手头工作,优先服务“我”。中断以事件形式通知CPU,因此常看到“在XX条件下会触发XX中断事件”的表述。
中断分为两类:
管理中断的设备:Advanced Programmable Interrupt Controller(APIC)。
硬中断的中断处理流程
中断随时发生,处理流程如下:
Maskable and non-maskable
Maskable interrupts 在x_上可以通过sti/cli指令来屏蔽(关闭)和恢复:
在屏蔽期间,这种类型的中断不会触发新的中断事件。大部分IRQ都属于这种类型。例如,网卡的收发包硬件中断。
Non-maskable interrupts 不可屏蔽,因此属于更高优先级的类型。
问题:执行速度与逻辑复杂性之间的矛盾
IRQ处理器的两个特点如下:
存在内在矛盾。
解决方式:中断的推迟处理(deferred interrupt handling)
传统解决方式是将中断处理分为两部分:
这种方式称为中断的推迟处理或延后处理。现在已是一个通用术语,涵盖各种推迟执行中断处理的方式。中断分为两部分处理:
在Linux中,有三种推迟中断(deferred interrupts):
具体细节将在后续介绍。
软中断与软中断子系统
软中断是内核子系统的一部分:
每个CPU上会初始化一个ksoftirqd内核线程,负责处理各种类型的softirq中断事件;
使用cgroup ls或ps -ef都能看到:
软中断事件的handler提前注册到softirq子系统,注册方式为open_softirq(softirq_id, handler)
例如,注册网卡收发包(RX/TX)软中断处理函数:
软中断占用了CPU的总开销:可以使用top查看,第三行倒数第二个指标是系统的软中断开销(si字段):
Linux内核源码分析学习地址:ke.qq.com/course/...
文章福利小编推荐自己的Linux内核源码分析交流群:点击加入整理了一些个人觉得比较好的学习书籍、视频资料共享在群文件里面,有需要的可以自行添加哦!
主处理
smpboot.c类似于事件驱动的循环,会调度ksoftirqd线程执行pending的软中断。ksoftirqd内部会进一步调用到__do_softirq,
避免软中断占用过多CPU
软中断的潜在影响:推迟执行的部分(如softirq)可能会占用较长时间,在这段时间内,用户空间线程只能等待。反映在top中,si占比。
不过softirq调度循环对此有所改进,通过budget机制来避免softirq占用过多CPU时间。
硬中断-软中断调用栈
softirq是一种推迟中断处理机制,将IRQ的大部分处理逻辑推迟在这里执行。有两条路径都会执行到softirq主处理逻辑__do_softirq():
1、CPU调度到ksoftirqd线程时,会执行到__do_softirq();
2、每次IRQ handler退出时:do_IRQ()->...
do_IRQ是内核中主要的IRQ处理方式。它执行结束时,会调用exiting_irq(),这会展开成irq_exit()。后者会检查是否pending有softirq,如果有,则唤醒:
进而会使CPU执行到__do_softirq。
软中断触发执行的步骤
总结,每个软中断会经过以下阶段:
以收包软中断为例,IRQ handler并不执行NAPI,只是触发它,在内部会执行到raiseNET_RX_SOFTIRQ;真正的执行在softirq,会调用网卡的poll()方法收包。IRQ handler中会调用napi_schedule(),然后启动NAPI poll()。
需要注意的是,虽然IRQ handler所做的工作很少,但处理这个包的softirq和IRQ在同一CPU上运行。这意味着,如果大量的包都放在同一个RX队列,虽然IRQ开销可能不多,但该CPU仍然会非常繁忙,都花费在softirq上。解决方式:RPS。它不会降低延迟,只是将包重新分配:RXQ->CPU。
三种推迟执行方式(softirq/tasklet/workqueue)
提到,Linux中的三种推迟中断执行方式:
其中:
前面已经看到,Linux在每个CPU上创建了一个ksoftirqd内核线程。
softirqs是在Linux内核编译时确定的,例如网络收包对应的NET_RX_SOFTIRQ软中断。因此是一种静态机制。如果想添加一种新softirq类型,需要修改并重新编译内核。
内部组织
内部由一个数组(或称为向量)管理,每个软中断号对应一个softirq handler。数组与注册:
在5.中所有类型的softirq:
也就是在cat /proc/softirqs看到的哪些。
触发(唤醒)softirq
以收包软中断为例,IRQ handler并不执行NAPI,只是触发它,在内部会执行到raiseNET_RX_SOFTIRQ;真正的执行在softirq,会调用网卡的poll()方法收包。IRQ handler中会调用napi_schedule(),然后启动NAPI poll()。
如果对内核源码有一定了解,会发现softirq使用非常有限,原因之一是它是静态编译的,依赖内置的ksoftirqd线程来调度内置的9种softirq。如果想添加一种新功能,就得修改并重新编译内核,开发成本很高。
实际上,实现推迟执行的更常用方式是tasklet。它构建在softirq机制之上,具体来说就是使用了两种softirq:
换句话说,tasklet是在运行时(runtime)创建和初始化的softirq,
内核软中断子系统初始化了两个per-cpu变量:
tasklet再执行针对list的循环:
tasklet在内核中的使用非常广泛。不过,后面又出现了第三种方式:workqueue。
这也是一种推迟执行机制,与tasklet有些相似,但有显著不同。
使用场景
简而言之,workqueue子系统提供了一个接口,通过该接口可以创建内核线程来处理从其他地方enqueue过来的任务。这些内核线程称为worker threads,内置的per-cpu worker threads:
结构体
kworker线程调度workqueues,原理与ksoftirqd线程调度softirqs类似。然而,我们可以为workqueue创建新的线程,而softirq则不行。
参考资料引用链接
[1]
中断与中断处理:0xax.gitbooks.io/linux-...
作者:赵亚楠 原文:arthurchiao.art/blog/li...来源:云原生实验室
suricata中的线程管理分析
在深入研究suricata的多线程处理之前,我们首先需要了解其内部的线程结构。《suricata中DPDK收发包源码分析2》和《suricata中command的实现分析和自定义命令方法》两篇文章中已有所涉及,但这里我们将重点关注与DPDK workers模式收包相关的线程。
在runmodes.c文件中,定义了几个关键线程,主要包括收包线程(TmThreadCreatePacketHandler),FlowManager和FlowRecycler线程(TmThreadCreateMgmtThreadByName),StatsMgmtThread和StatsWakeupThread线程(TmThreadCreateMgmtThread),以及UnixManager线程(TmThreadCreateCmdThreadByName)。其他非DPDK相关的线程暂时忽略。
创建线程的过程如下:首先,创建ThreadVar变量,指定线程类型和入口函数,如TmThreadCreatePacketHandler、TmThreadCreateMgmtThread等。然后,根据线程类型调用TmThreadSetSlots,决定使用哪个入口函数。接着,将相关模块加入到线程变量的tm_slots链表,通过TmThreadSpawn启动线程。线程启动后,根据线程类型执行不同的逻辑:收包线程负责接收和处理报文,管理线程执行特定的管理任务。
你可以通过top工具观察suricata创建的实际线程,它们与理论上的线程名称是一致的。此外,自定义命令功能允许我们查看线程列表和指定线程的slots,例如使用"threads-list"和"slots-list"命令。
至此,suricata的线程管理机制已经清晰呈现。如果有任何疑问或需要自定义命令源码的指导,欢迎加入网络技术开发交流群,记得关注我们的内容哦。
开源即时通讯GGTalk源码剖析之:客户端全局缓存及本地存储
继上篇详细介绍了 GGTalk 内置的虚拟数据库,本文将深入探讨 GGTalk 客户端的全局缓存及本地存储机制。对于还没有获取GGTalk源码的朋友,文章底部附有下载链接。
一. GGTalk 客户端缓存设计
核心在于ClientGlobalCache类,它在内存中保存用户和群组数据。此类接受泛型参数TUser和TGroup,且限定TUser和TGroup需实现特定接口,还继承自BaseGlobalCache类。三个私有字段分别用于存储用户、群组和缓存信息。
构造函数接收五个参数,用于初始化私有字段,并调用父类BaseGlobalCache的Initialize方法,实现缓存初始化逻辑。
二. GGTalk 客户端本地持久化存储
BaseGlobalCache类中,originUserLocalPersistence字段负责本地文件存储。它包含四个属性,代表好友列表、群组列表、快捷回复列表和最近联系人/群列表。
Load和Save方法用于读写本地文件,将数据存入或从文件加载。在了解本地缓存的核心概念后,回到Initialize方法,读取本地文件数据,缓存到内存中。
三. 更新本地缓存
在用户登录或断线重连时,系统会比较本地缓存与服务器数据,更新缺失或过时的信息。当缓存中只有用户自己时,会从服务器加载所有联系人;当存在其他数据时,会更新本地缓存以反映服务器最新状态。
四. 总结
GGTalk客户端缓存流程包括读取本地缓存、从服务器加载更新数据,以及在窗口关闭时将当前用户数据缓存。下篇将解析消息收发及处理机制。
敬请期待:《GGTalk 开源即时通讯系统源码剖析之:消息收发及处理》。底部链接提供下载GGTalk源码。
linux内核通信核心技术:Netlink源码分析和实例分析
Linux内核通信核心技术:Netlink源码分析和实例分析
什么是netlink?Linux内核中一个用于解决内核态和用户态交互问题的机制。相比其他方法,netlink提供了更安全高效的交互方式。它广泛应用于多种场景,例如路由、用户态socket协议、防火墙、netfilter子系统等。
Netlink内核代码走读:内核代码位于net/netlink/目录下,包括头文件和实现文件。头文件在include目录,提供了辅助函数、宏定义和数据结构,对理解消息结构非常有帮助。关键文件如af_netlink.c,其中netlink_proto_init函数注册了netlink协议族,使内核支持netlink。
在客户端创建netlink socket时,使用PF_NETLINK表示协议族,SOCK_RAW表示原始协议包,NETLINK_USER表示自定义协议字段。sock_register函数注册协议到内核中,以便在创建socket时使用。
Netlink用户态和内核交互过程:主要通过socket通信实现,包括server端和client端。netlink操作基于sockaddr_nl协议套接字,nl_family制定协议族,nl_pid表示进程pid,nl_groups用于多播。消息体由nlmsghdr和msghdr组成,用于发送和接收消息。内核创建socket并监听,用户态创建连接并收发信息。
Netlink关键数据结构和函数:sockaddr_nl用于表示地址,nlmsghdr作为消息头部,msghdr用于用户态发送消息。内核函数如netlink_kernel_create用于创建内核socket,netlink_unicast和netlink_broadcast用于单播和多播。
Netlink用户态建立连接和收发信息:提供测试例子代码,代码在github仓库中,可自行测试。核心代码包括接收函数打印接收到的消息。
总结:Netlink是一个强大的内核和用户空间交互方式,适用于主动交互场景,如内核数据审计、安全触发等。早期iptables使用netlink下发配置指令,但在iptables后期代码中,使用了iptc库,核心思路是使用setsockops和copy_from_user。对于配置下发场景,netlink非常实用。
链接:内核通信之Netlink源码分析和实例分析