带你走进linux内核中断子系统—workqueue

Linux内核中断子系统的工作队列模块是内核提供的基于工作队列的工作调度机制。
本文将带您详细了解Workqueue模块的组件及其实现。

数据结构概述:

数据结构包括“structwork_struct”、“structworkqueue_struct”、“structworker”和“structworker_pool”等。

structwork_struct用于描述工作和是最小的计划工作单元。
当一个工作被添加到工作队列时,它就会由相应的内核线程执行。
其关键字段包括数据指针(data)等。

structworkqueue_struct是工作队列的核心数据结构,包括工作队列配置信息和工作队列管理功能。
关键字段的引入包括标志位、内存池、回收线程等。

structworker代表一个用来执行工作的线程,包括状态信息、优先级等。

structworker_poolManaged一组工作人员,是工作队列系统中的关键组件,用于管理工作人员的创建、状态迁移和销毁。

pool_workqueue用于连接workqueue和worker_pool。
它实现工作队列和工作人员之间的工作分配和管理。

流程分析:

初始化过程主要分为两步:第一,“workqueue_init_early”完成,主要初始化标志位和内存池,第二,在“workqueue_init”中添加worker_pool创建对于第一个工作线程,通过“create_worker”创建内核线程,并将名称指定为“kworker/XX:YYH”或“kworker/uZZ:YY”在。

工作调度过程包括两个阶段:将工作添加到工作队列和执行工作线程。
当执行schedule_work接口时,工作被放置在特定线程的工作列表中等待执行。
执行是通过“worker_thread”函数实现的,“process_one_worker”是工作的处理函数。

动态管理包括改变worker状态(运行状态-挂起状态、挂起状态-运行状态)以及动态添加和删除worker。
不活动的worker会被定期处理并在一段时间后销毁,或者在内核线程运行时根据需要动态创建新的worker。

编程示例:

在Linux内核版本4.14.87中,通过直接调度工作项执行线程的核心绑定执行手动调整工作示例代码分析失败,因为工作队列调度不没有热支持机制,使用最后执行线程所在的worker_pool并将工作项放入工作列表中或通过pool_workqueue推迟插入worker_pool执行列表。

从Linux源码看Socket(TCP)的listen及连接队列

了解Linux内核的套接字(TCP)“监听”和连接排队机制是深入理解网络编程的关键。
本文基于Linux3.10内核版本,从源码角度分析服务器端socket“监听”的具体实现。
建立服务器端socket需要四个步骤:socket、bind、listen、accept。
本文重点关注“倾听”步骤,并详细探讨其内在机制。
您可以通过套接字系统调用创建基于TCP的套接字。
这里直接展示了与TCPSocket相关的操作函数。
接下来,我们将详细讨论“listen”系统调用。
注意glibc的INLINE_SYSCALL对返回值进行了封装,只保留0和-1两个结果,并在errno中记录错误码的绝对值。
其中backlog参数很重要,如果设置错误,可能会出现隐藏的陷阱。
对于Java开发人员来说,框架的默认backlog值很小(默认为50),因此这可能会导致行为上的细微差异。
进入内核源代码堆栈,我们看到内核调整了backlog值,将其限制为不超过内核参数中设置的somaxconn值。
核心调用程序是inet_listen。
非fastopen逻辑(fastopen将在单独的章节中详细讨论)最终调用inet_csk_listen_start将sock链接到全局listenhash表,以高效处理SYN数据包。
值得注意的是,SO_REUSEPORT特性允许不同的socket监听同一个端口,以实现内核级的负载均衡。
在Nginx1.9.1版本中启用此功能可将性能提高3倍。
半耦合和全耦合队列是连接处理的重要组成部分。
经常提到的sync_queue和accept_queue并不能说明全部情况。
sync_queue实际上是syn_table,完整的连接队列是icsk_accept_queue。
在三向握手过程中,这两个队列承担不同的角色。
在连接处理中,除了qlen和sk_ack_backlog计数器外,qlen_young计数器用于某些场景的统计。
SYN_ACK重传定时器在内核中以200ms的间隔运行,以保证连接建立过程的稳定性。
半连接队列的存在是为了抵抗半连接攻击,避免消耗大量的内存资源。
通过syn_cookie机制,内核可以有效防御此类攻击。
全连接队列的最大长度是有限的,超过somaxconn值的连接会被内核丢弃。
如果未启用tcp_abort_on_overflow功能,则客户端在进行调用之前可能不会意识到连接已断开。
启用此功能或增加积压值是解决此问题的策略。
backlog参数影响半连接队列的容量并允许内核提交验证时会出现常见的内存溢出警告。
综上所述,TCP协议经过几十年的演变,变得越来越复杂,深读源码成为分析问题的重要途径。
本文对Linux内核的套接字(TCP)“监听”和连接排队机制进行了深入分析,目的是帮助开发者更好地理解网络编程。