前言

在上一篇 LINUX软中断-softirq的描述中,提到过ksoftirqd,这篇文章就介绍ksoftirqd

ksoftirqd 是什么?

ksoftirqd 是个内核线程,在创建的时候是绑定cpu的,每一个core对应生成一个ksoftirqd 线程
比如当前系统有4个core

~# ps aux | grep ksoftirqd
root        3  0.0  0.0      0     0 ?        S    14:20   0:00 [ksoftirqd/0] //core 0
root        9  0.0  0.0      0     0 ?        S    14:20   0:00 [ksoftirqd/1] //core 1
root       12  0.0  0.0      0     0 ?        S    14:20   0:00 [ksoftirqd/2] //core 2
root       15  0.0  0.0      0     0 ?        S    14:20   0:00 [ksoftirqd/3] //core 3
ksoftirqd 的作用

ksoftirqd 的作用就是处理softirq用,它的本质就是调用 __do_softirq

ksoftirqd 的触发条件
  • 通过中断
    上一篇文章已经解释过了 softirq的处理是通过中断服务程序的第二个阶段,即中断来了执行ISR后,调用do_softirq遍历数组softirq_vec执行数组项的action(比如tasklet类型的softirq),但是有个问题,比如softirq_vec的第6个数组项(任务tasklet)执行完,恰好又来了个ISR提交tasklet,使得softirq_vec[6]又被需要处理,这可如何是好呢?
    总不能老是卡在中断流程里吧,这时就要唤醒本core上的ksoftirqd来处理softirq_vec数组,看下代码
static int run_ksoftirqd(void * __bind_cpu)
{set_current_state(TASK_INTERRUPTIBLE);while (!kthread_should_stop()) {preempt_disable();if (!local_softirq_pending()) {schedule_preempt_disabled();}__set_current_state(TASK_RUNNING);while (local_softirq_pending()) {if (local_softirq_pending())//do_softirq会再次通过本core的__softirq_pending 变量来遍历softirq_vec数组__do_softirq();}}return 0;
}
  • tasklet_schedule
    上篇文章讲过 tasklet是通过调用 tasklet_schedule来提交 ,tasklet_schedule除了可以再ISR中被调用之外,其实也可以在普通的线程中调用。
void __tasklet_schedule(struct tasklet_struct *t)
{unsigned long flags;local_irq_save(flags);t->next = NULL;*__this_cpu_read(tasklet_vec.tail) = t;__this_cpu_write(tasklet_vec.tail, &(t->next));raise_softirq_irqoff(TASKLET_SOFTIRQ);local_irq_restore(flags);
}
//raise_softirq_irqoff
inline void raise_softirq_irqoff(unsigned int nr)
{__raise_softirq_irqoff(nr);/** If we're in an interrupt or softirq, we're done* (this also catches softirq-disabled code). We will* actually run the softirq once we return from* the irq or softirq.** Otherwise we wake up ksoftirqd to make sure we* schedule the softirq soon.*/if (!in_interrupt())wakeup_softirqd();
}static void wakeup_softirqd(void)
{/* Interrupts are disabled: no need to stop preemption */struct task_struct *tsk = __this_cpu_read(ksoftirqd);if (tsk && tsk->state != TASK_RUNNING)wake_up_process(tsk);
}

由上面的代码得知,tasklet_schedule如果在中断上下文被调用的话(ISR中调用),则不唤醒ksoftirqd,会交给中断的下半段处理tasklet,如果在普通线程被调用的话,则唤醒ksoftirqd。注意,唤醒的是本core上的ksoftirqd

tasklet的缺点

tasklet感觉很少被用到,特点是执行权限比较高,执行时不能被打断,实时性比较好,缺点也明显,因为tasklet在执行过程中本core不能运行其他程序,如果tasklet运行时间长的话,会导致其他程序久久不被运行或者其他程序会抢别的core运行,导致系统性能下降。

实际项目中遇到的问题

要求display的显示是 60fps, insmod sd卡驱动后,显示会掉帧,导致降到 50fps左右
原因是sd卡驱动在检测sd卡是否插入用的是loop的方式检测gpio的值,而loop是利用mod_timer这种精度定时器来做的(300ms一次检测)
mod_timer实现机制是用tasklet来做的(TIMER_SOFTIRQ),即mod_timer所注册的回调函数会在softirq_vec[TIMER_SOFTIRQ]->action中被调用(run_timer_softirq)
每次tick产生后,就会判断一下timer时间到没到,如果到了,就会raise_softirq触发软中断来处理回调函数。

tick_handle_periodic()
->tick_periodic()->update_process_times()->run_local_timers()->hrtimer_run_queues()->__run_hrtimer(timer, &base->softirq_time);->raise_softirq(TIMER_SOFTIRQ)->run_timer_softirq->处理 mod_timer所注册timer的回调函数

而在本地问题中,timer的回调函数的处理中用到了如下的做法:

for (i=0; i<5; i++) {gpio_val += (smc_host->cd_mode == CARD_DETECT_BY_GPIO_IRQ_UP)\? (!__gpio_get_value(cd->gpio))\:( __gpio_get_value(cd->gpio));\mdelay(1);}

即循环5次检测gpio,并且还用mdelay来进行延迟,(此函数意味着本core不能被切走必须死等, 这也是没办法的,因为回调函数是在softirq上下文运行的,不能使用睡眠类的函数,这里mdelay不会睡眠)
这就造成了一次timer回调的执行至少需要5-6ms,因为系统有两个sd卡卡槽,一个卡槽对应一个timer进行检测,相当于执行一次需要10-12ms
而且softirq上下文导致其他线程不能被执行,从而大大影响系统性能。

tasklet处理中能否调用sleep函数

注意,在linux中,只要是中断上下文,是不允许调用schedule这种函数切走的,因为中断上下文即原子上下文,所以tasklet中不能用睡眠函数(本身你用了tasklet,就说明要处理的东西优先级高),但我偏偏要主动schedule切走呢?其实实验中发现也没什么问题,但是schedule会报错(scheduling while atomic)

static noinline void __schedule_bug(struct task_struct *prev)
{if (oops_in_progress)return;printk(KERN_ERR "BUG: scheduling while atomic: %s/%d/0x%08x\n",prev->comm, prev->pid, preempt_count());debug_show_held_locks(prev);print_modules();if (irqs_disabled())print_irqtrace_events(prev);dump_stack();
}

因为上篇文章讲过,内核调度的原则是preempt_count为0,你偏偏非要preempt_count不为0的时候主动调用sleep等切走的话,内核__schedule函数会给你一个bug,但是为了尽可能的维持系统的运行,还坚持在跑,并且试图修正整个preempt_count (不在本次的讨论范围之内)

ISR处理中能否调用sleep函数

注意: 中断服务程序 = ISR + softirq
softirq执行的时候毕竟是开中断的,即便softirq执行中主动切走当前进程A,因为tick中断还是开的,还是会被切回来的。
我们模拟下流程:

  1. 进程A运行
  2. 来中断,进程A被打断,执行softirq(A)
  3. 在softirq中调用__schedule函数主动切走
  4. 切走时当前进程的thread info 变量栈中保存的上下文是:A进程的上下文 + softirqA)的上下文
  5. 切到B中运行
  6. 来了个tick中断,中断退出后,在切回进程A,先把softirqA)的上下文从thread info中出栈
  7. 继续执行 softirq(A), softirq(A)执行完后,把A进程的上下文从thread info中出栈
  8. 运行进程A

所以整个流程都没什么太大问题,但是在ISR中调用__schedule时问题就大了。
因为在执行ISR时,中断是关的,即本core上不会再有中断了,相当于调度器也关了,所以主动且走后,就没办法在切回来了,其实这种理解是错的!哈哈哈!
答案是,__schedule要切的时候,会把本core中断再次打开

raw_local_irq_disable() //关闭本地中断
schedule() //调用schedule()函数来切换进程
raw_local_irq_enable() //打开本地中断

假设进程A在关闭本地中断的情况下切换到进程B来运行,进程B切换执行时会打开本地中断,以防止系统瘫痪。我们看下代码:

__schedule (A) //A在cpu0上context_switchswitch_to (B) //多核的情况下,Bthread可能在thread1上被唤醒finish_task_switchfinish_lock_switch(rq, prev);raw_spin_rq_unlock_irqlocal_irq_enable //开中断

但是有个问题,单核的情况下没什么问题,B跟A都是同一个cpu,B被唤醒时,把中断打开,但是多核呢?其实那也没关系,等B在切换回A时,或者说,有一个thread从cpu0唤醒时,都会先打开中断!
也就是说,在中断中是可以切走的。经过实测,在ISR中与softirq中都可以调用schedule切走,但是会报BUG(因为在中断上下文中调用schedule,schedule设计原则是不允许切换的,但是你非要这么做,它只能就范,但是又为什么不让系统瘫痪,故报一个bug提醒你)。

BUG: scheduling while atomic: swapper/0/0/0x00010002

但是不管怎么说,设计初衷就是不允许被抢占,而且在中断走切走基本上就是bug,比如你在A thread用了spinlock,然后来了个中断,中断主动schedule后切到B thread了,B thread要spinlock,就死锁了(A在中断时被切走)

LINUX软中断-ksoftirqd相关推荐

  1. Linux内核网络中的软中断ksoftirqd

    1. 前言 之前分享过Linux内核网络数据包的接收过程,当执行到网卡通过硬件中断(IRQ)通知CPU,告诉它有数据来了,CPU会根据中断表,调用已经注册的中断函数,这个中断函数会调到驱动程序(NIC ...

  2. 【Linux 性能优化系列】Linux 性能优化 -- CPU 性能篇(三) Linux 软中断

    [Linux 性能优化系列]Linux 性能优化 -- CPU 性能篇(三) Linux 软中断 [1]相关概念 [1.1]中断 中断其实是一种异步的事件处理机制,可以提高系统的并发处理能力:为了减少 ...

  3. linux软中断是什么机制,Linux软中断原理浅析

    Linux软中断原理浅析 Linux软中断原理浅析 Linux中的软中断机制用于中对时间要求最严格以及最重要的中断下半部进行使用.在系统设计过 程中,大家都清楚中断上下文不能处理太多的事情,需要快速的 ...

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

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

  5. 09 | 基础篇:怎么理解Linux软中断?

    上一期,我用一个不可中断进程的案例,带你学习了 iowait(也就是等待 I/O 的 CPU 使用率)升高时的分析方法.这里你要记住,进程的不可中断状态是系统的一种保护机制,可以保证硬件的交互过程不被 ...

  6. Linux软中断、tasklet和工作队列

    Linux内核中的软中断.tasklet和工作队列详解 引言 软中断.tasklet和工作队列并不是Linux内核中一直存在的机制,而是由更早版本的内核中的"下半部"(bottom ...

  7. LINUX软中断-softirq

    前言 关于linux的软中断的文章,在网上可以找到很多,但总觉着讲的都不够深入,打算自己写一下 软中断的由来 在linux下,有两种中断: 硬中断 GIC产生一个中断后通知cpu,cpu硬件会跳到特定 ...

  8. 保护linux系统调用,Linux软中断与系统调用

    1. SWI软中断 以ARMV7 A/R架构为例, SWI软中断和中断一样,内核空间处理始于异常向量表.Linux向量表默认地址0XFFFF0000,SWI向量偏移8字节为0xFFFF0008: 具体 ...

  9. linux软中断的实现

    中断服务程序往往都是在CPU关中断的条件下执行的,以避免中断嵌套而使控制复杂化.但是CPU关中断的时间不能太长,否则容易丢失中断信号.为此, Linux将中断服务程序一分为二,各称作"Top ...

最新文章

  1. json下linux64位版本,linux下正确安装jsoncpp(示例代码)
  2. 【操作系统】考研の页面置换算法例子(看不懂你来打我~!)
  3. Android 常用的性能分析工具详解:GPU呈现模式, TraceView, Systrace, HirearchyViewer(转)...
  4. 树莓派外设开发之控制继电器(组)
  5. 图解选择排序与插入排序
  6. Linux 系统应用编程——网络编程(服务器模型)
  7. log4j 禁止类输出日志_SpringBoot统一日志处理原理
  8. python学习之老男孩python全栈第九期_数据库day004 -- 作业
  9. python自学行吗-上万程序员总结:自学Python,掌握到什么程度就可以找工作了?...
  10. double operator[](int i)_请谨慎使用float和double
  11. SAP VA01 消息 没有用于售达方 XXXXXX 的客户主记录存在
  12. 腾讯微博开放平台开发者服务协议 2.1、3.6 解读
  13. RFID定位技术下的智能养老系统具有哪些优势呢?--新导智能
  14. 进阶的阿牛哥之pandas透视表pivot_table的使用
  15. 个人简历网页搭建(快速搭建GitHub Pages和Apache)
  16. echarts 3D地图点击事件
  17. 小叙酷狗和酷我音乐盒
  18. 收割10W大奖+大厂面试+成果发表 | 2022『猛犸杯』国际组学数据创新大赛开放报名
  19. ASEMI肖特基二极管MBR40200PT参数,MBR40200PT规格
  20. 国内首个隐私计算盛会闭幕,区块链与隐私碰撞,数据流动价值未来可期

热门文章

  1. python 实现学生信息管理系统+MySql 数据库,包含源码及相关实现说明~
  2. 可变形的四旋翼飞行器——无人机
  3. 搜狗输入法,好用不?原理是什么?
  4. 惠普JAVA工程师给想从事JAVA开发的朋友一点工作心得
  5. 机器视觉技术原理解析及解决方案
  6. PPTV去广告(XP测试通过)
  7. 2018迅雷校园招聘---整数求和
  8. 调试器(debugger)是如何工作的
  9. python html5 便利店收银系统_基于Python的Django框架实现的中式快餐厅管理信息系统网站...
  10. 利用Open 3D建立三维模型