softirq属于底半步的一种方式,软中断是相对于硬中断的。

在中断的下半部机制中,软中断是执行效率最快的,同时,相对来说对于开发者也是最麻烦的,它的麻烦在于两个因素:

  • 同一个软中断支持在不同的 cpu 上并发执行,这也就导致了软中断执行的代码需要考虑 SMP 下的并发,实现上要更复杂。
  • 软中断不支持动态的定义,只能将软中断静态地编译到内核镜像中,而不能使用外部模块加载的方式

它的执行效率也体现在两点上:

  • 因为支持 cpu 上并发执行,所以通常情况下不需要等待(tasklet无法并发执行,且有其他限制),但是硬中断能抢占它执行。
  • 通常情况下软中断执行在中断上下文中,硬中断结束之后会立马执行软中断,为什么说是通常情况下运行在中断上下文而不是一定运行在中断上下文?这是因为在特殊情况下,软中断也会由内核线程(ksoftirqd)来实现

本文主要讲内核线程的ksoftirq创建和执行

softirq的初始化流程如下

spawn_ksoftirqd创建于SMP初始化之前,借助smpboot_register_percpu_thread创建了每CPU内核线程ksoftirqd/xx

tatic struct smp_hotplug_thread softirq_threads = {.store           = &ksoftirqd, //struct task_struct __percpu    **store;.thread_should_run  = ksoftirqd_should_run, //判断是否有软中断pending,有的话执行下面的thread_fn.thread_fn       = run_ksoftirqd, //<---smpboot_thread_fn thread.thread_comm     = "ksoftirqd/%u",
};static __init int spawn_ksoftirqd(void)
{register_cpu_notifier(&cpu_nfb);BUG_ON(smpboot_register_percpu_thread(&softirq_threads));//每个cpu创建一个线程,softirq--->smpboot//Register a per_cpu thread related to hotplugreturn 0;
}
early_initcall(spawn_ksoftirqd);
/*** smpboot_register_percpu_thread - Register a per_cpu thread related to hotplug* @plug_thread:   Hotplug thread descriptor** Creates and starts the threads on all online cpus.*/
int smpboot_register_percpu_thread(struct smp_hotplug_thread *plug_thread)
{unsigned int cpu;int ret = 0;get_online_cpus();mutex_lock(&smpboot_threads_lock);for_each_online_cpu(cpu) {ret = __smpboot_create_thread(plug_thread, cpu);//creat threadif (ret) {smpboot_destroy_threads(plug_thread);goto out;}smpboot_unpark_thread(plug_thread, cpu);}list_add(&plug_thread->list, &hotplug_threads);//add to global list head
out:mutex_unlock(&smpboot_threads_lock);put_online_cpus();return ret;
}
static int
__smpboot_create_thread(struct smp_hotplug_thread *ht, unsigned int cpu)
{struct task_struct *tsk = *per_cpu_ptr(ht->store, cpu);struct smpboot_thread_data *td;//thread related dataif (tsk)return 0;td = kzalloc_node(sizeof(*td), GFP_KERNEL, cpu_to_node(cpu));if (!td)return -ENOMEM;td->cpu = cpu;td->ht = ht;//ht-->td(smpboot_thread_data)tsk = kthread_create_on_cpu(smpboot_thread_fn, td, cpu,ht->thread_comm);//create cpu 关联的线程 smpboot_thread_fnif (IS_ERR(tsk)) {kfree(td);return PTR_ERR(tsk);}get_task_struct(tsk);*per_cpu_ptr(ht->store, cpu) = tsk;if (ht->create) {/** Make sure that the task has actually scheduled out* into park position, before calling the create* callback. At least the migration thread callback* requires that the task is off the runqueue.*/if (!wait_task_inactive(tsk, TASK_PARKED))WARN_ON(1);elseht->create(cpu);}return 0;
}
/*** smpboot_thread_fn - percpu hotplug thread loop function* @data:    thread data pointer** Checks for thread stop and park conditions. Calls the necessary* setup, cleanup, park and unpark functions for the registered* thread.** Returns 1 when the thread should exit, 0 otherwise.*/
static int smpboot_thread_fn(void *data)
{struct smpboot_thread_data *td = data;struct smp_hotplug_thread *ht = td->ht;while (1) {set_current_state(TASK_INTERRUPTIBLE);preempt_disable();if (kthread_should_stop()) {__set_current_state(TASK_RUNNING);preempt_enable();if (ht->cleanup)ht->cleanup(td->cpu, cpu_online(td->cpu));kfree(td);return 0;}if (kthread_should_park()) {__set_current_state(TASK_RUNNING);preempt_enable();if (ht->park && td->status == HP_THREAD_ACTIVE) {BUG_ON(td->cpu != smp_processor_id());ht->park(td->cpu);td->status = HP_THREAD_PARKED;}kthread_parkme();/* We might have been woken for stop */continue;}BUG_ON(td->cpu != smp_processor_id());/* Check for state change setup */switch (td->status) {case HP_THREAD_NONE:__set_current_state(TASK_RUNNING);preempt_enable();if (ht->setup)ht->setup(td->cpu);td->status = HP_THREAD_ACTIVE;continue;case HP_THREAD_PARKED:__set_current_state(TASK_RUNNING);preempt_enable();if (ht->unpark)ht->unpark(td->cpu);td->status = HP_THREAD_ACTIVE;continue;}if (!ht->thread_should_run(td->cpu)) {//ksoftirqd_should_run,返回0代表没有软中断pendingpreempt_enable_no_resched();schedule();} else {//非0代表有softirq处于pending状态__set_current_state(TASK_RUNNING);preempt_enable();ht->thread_fn(td->cpu); //run_ksoftirqd}}
}
static int ksoftirqd_should_run(unsigned int cpu)
{return local_softirq_pending();
}static void run_ksoftirqd(unsigned int cpu)
{local_irq_disable();//关cpu的中断if (local_softirq_pending()) {/** We can safely run softirq on inline stack, as we are not deep* in the task stack here.*/__do_softirq();local_irq_enable();//开本地cpu中断cond_resched_rcu_qs();return;}local_irq_enable();
}
typedef struct {unsigned int __softirq_pending;
} ____cacheline_aligned   irq_cpustat_t;#ifndef __ARCH_IRQ_STAT
extern irq_cpustat_t irq_stat[];        /* defined in asm/hardirq.h */
#define __IRQ_STAT(cpu, member) (irq_stat[cpu].member)
#endif/* arch independent irq_stat fields */  //检查本地CPU否有软中断在pending状态
#define local_softirq_pending() \__IRQ_STAT(smp_processor_id(), __softirq_pending)---------------软中断pending 寄存器(不是硬件的寄存器)irq_stat[0].__softirq_pending  代表cpu0的软中断pending bitirq_stat[1].__softirq_pending  代表cpu1的软中断pending bit。。。。irq_stat[n].__softirq_pending  代表cpun的软中断pending bit__softirq_pending 的bit 定义如下,当对应bit为1代表有软中断pending,0代表没有,低位优先级较高enum
{HI_SOFTIRQ=0,TIMER_SOFTIRQ,NET_TX_SOFTIRQ,NET_RX_SOFTIRQ,BLOCK_SOFTIRQ,BLOCK_IOPOLL_SOFTIRQ,TASKLET_SOFTIRQ, //6SCHED_SOFTIRQ,HRTIMER_SOFTIRQ,RCU_SOFTIRQ,    /* Preferable RCU should always be the last softirq */NR_SOFTIRQS
};

ksoftirqd内核线程-处理软中断相关推荐

  1. ksoftirqd内核线程

    每个处理器都有一组辅助处理器软中断(和tasklet)的内核线程.当内核中出现大量软中断的时候,这些内核进程就会辅助处理它们. 引入ksoftirq内核线程的原因: 对于软中断,内核会选择在几个特殊时 ...

  2. 【Linux内核】Linux软中断处理机制-ksoftirqd

    1.前言 软中断(softirq)是中断处理程序在开启中断的情况下执行的部分,可以被硬中断抢占.把延迟函数叫做软中断并不是因为它是一个真正的中断,而是因为延迟函数主要在中断上下文环境中运行.Linux ...

  3. 内核线程ksoftirqd

    软中断和微线程的处理都依赖于一组每-处理器内核线程,这些内核线程在当系统中软中断或微线程处理过于频繁时协助软中断和微线程的处理. 一个软中断或微线程可以重新激活自己,从来导致其又重新运行,这样会导致用 ...

  4. Linux内核中断系统结构——软中断

    在 Linux异常(中断)处理体系结构 这篇文章,我们详细描写了内核如何进行中断(异常)向量表的初始化.如何初始化硬件中断(IRQ)的操作. 在这篇文章中,我们将重心放在软件中断上.也就是 CPU 本 ...

  5. Linux内核中的软中断、tasklet和工作队列详解

    本文基于Linux2.6.32内核版本. 引言 软中断.tasklet和工作队列并不是Linux内核中一直存在的机制,而是由更早版本的内核中的"下半部"(bottom half)演 ...

  6. Linux内核中的软中断、tasklet和工作队列具体解释

    [TOC] 本文基于Linux2.6.32内核版本号. 引言 软中断.tasklet和工作队列并非Linux内核中一直存在的机制,而是由更早版本号的内核中的"下半部"(bottom ...

  7. 【linux性能优化】内核线程CPU利用率高分析

    在排查网络问题时经常碰到的一个问题,就是内核线程的CPU使用率很高 比如,在高并发的场景中内核线程ksoftirqd的CPU使用率通常就会比较高,根据CPU和网络模块知识可以得知,这是网络收发的软中断 ...

  8. 【Linux 内核】进程管理 ( 进程特殊形式 | 内核线程 | 用户线程 | C 标准库与 Linux 内核中进程相关概念 | Linux 查看进程命令及输出字段解析 )

    文章目录 一.进程特殊形式 ( 内核线程 | 用户线程 ) 二.C 标准库与 Linux 内核中进程相关概念 三.Linux 查看进程命令及输出字段解析 一.进程特殊形式 ( 内核线程 | 用户线程 ...

  9. 深入理解Linux内核之内核线程(上)

    1.开场白 环境: 处理器架构:arm64 内核源码:linux-5.11 ubuntu版本:20.04.1 代码阅读工具:vim+ctags+cscope 在linux系统中, 我们接触最多的莫过于 ...

最新文章

  1. poj1182 and 携程预赛2第一题 带权并查集
  2. java int比较用==,整数-在Java中使用==运算符比较包装对象
  3. android 个推打开页面,个推android客户端点击跳到指定activity
  4. 挖掘建模-分类与预测-回归分析-逻辑回归
  5. 《C和指针》——指针运算
  6. java 带参数转发_Nginx 根据URL带的参数转发的实现
  7. Eclipse无法查看Servlet源代码的解决方案
  8. JSP与Servlet传值及对比
  9. LA3027(并查集)
  10. Arduino--DS3231时钟模块
  11. 呼叫中心语音外呼营销系统软件成企业首选
  12. android备份手机号码,Android QQ同步助手3.2 保证号码备份“不丢人”
  13. pwm脉宽调制c语言程序,MCS-51系列单片机C语言编程PWM脉宽调制器程序模板
  14. java short 写法_Java Short类shortValue()方法及示例
  15. poi操作word替换文本框里的内容
  16. aspcms友情链接调用
  17. 【三级等保】三级等保服务费用一年大概要多少?一年需要测评一次嘛?
  18. 大数据BI可视化基础
  19. android ftdi,从 Android FTDI串行通信开始_ftdi_开发99编程知识库
  20. LeetCode:387.字符串中的第一个唯一字符

热门文章

  1. 离散数学复习--集合的势证明
  2. 钢铁侠材质制作——3、基础光照模型实现
  3. 中秋测试大礼包来了,送一个测试流量app~
  4. 怎么把手机文件导入华为云服务器,华为手机如何上传数据到云服务器
  5. 佳能(Canon)打印机初始化备忘录
  6. win11壁纸怎么可以动 Windows11秒变动态壁纸的设置方法
  7. 大佬H5网页手机端怎么应用微信快捷登陆?
  8. 张宏 :移动机器人全局定位技术与方法是啥?道翰天琼认知智能机器人平台API接口大脑为您揭秘-1。
  9. UVA12304直线,圆,点的综合应用
  10. 数字加千分位分隔符,加货币符号,数字转百分数