内核线程、软中断和定时器有何区别

本文讨论了内核线程、软中断和定时器的区别,重点解释了软中断的概念及其与慢速中断的关系。通过分析Linux内核源代码,明确了软中断的工作原理和应用场景。
内核线程、软中断和定时器有何区别?

在慢速中断的过程中,允许别的中断发生

 

 
 Re: 内核线程、软中断和定时器有何区别?

2.4中还有慢速中断吗? 

 

 
 Re: 内核线程、软中断和定时器有何区别?

有,其实就是软中断. 

 

 
 Re: 内核线程、软中断和定时器有何区别?

你好快,就成newbie了,我努力了好几个月才成newbie 

慢速中断不应该是软中断吧?如果说慢速中断是可以中断的中断,那应该是那种没有XX_INTERRUPT标志的中断,系统响应时会打开中断。 

软中断应该就是tasklet 


 

 
 Re: 内核线程、软中断和定时器有何区别?

我觉得首先讲一下LINUX的内核机制: 
传统的UNIX把内核分成两部分:TOP HALF和BOTTOMHALF.BOTTOM呢是由异步事件来调用的,其实在LINUX中不严格的说就是中断.TOP是由系统调用来调用的.注意这里的 BOTTOM HALF和LINUX2.2中的并在LINUX2.4也支持的BH机制不是一回事情. 
好了,现在讲你问的问题: 
软中断其实就是把一个异步事件的响应分成两个部分的一个部分.另一个叫硬中断.硬中断必须实时响应,软中断可以等有时间再做,LINUX怎么调度软中断,有三个途径,从系统掉用,异常和中断中返回的时候有检查要不要执行软终端. 
对于一个时钟,很显然时钟中断的服务程序也被分成两个部分,一个就是硬中断,一个就是软中断了.你说的定时器我估计就是指时钟中断的软中断. 
对与内核线程,LINUX从2.4的一些高端版本好象也开始采用了对某些软中断使用这中方法,即把软中断作为一个线程来执行. 


 

 
 Re: 内核线程、软中断和定时器有何区别?

从他的意思来看就是软中断. 
我原来比NEWBIE的级别还高一点呢,现在我换名字了. 
你说的TASKLET只是软中断的一种类型. 
对于中断的服务程序的设计,要具体对待,对于服务程序不大,没有必要采用软中断机制.直接关中断就可以了.你说的对XXX_INTERUPT如果象你那么设计,就不是采用软中断的机制了,在早期的UNIX是这么实现的,即一个中断服务不分成两个部分,只是在服务程序中开哪些中断.譬如 XENIX2.3.4就是这么设计的.至于LINUX可以不可以也这么直接写服务程序,我不知道.不过通常都是软硬中断分开的. 

 

 
 Re: 内核线程、软中断和定时器有何区别?

我想你没有理解他的意思。他说的慢速中断是指没有SA_INTERRUPT标志的中断。 

以下是相关代码: 
 

int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * action)

{

	int status;

	int cpu = smp_processor_id();



	irq_enter(cpu, irq);



	status = 1;	/* Force the "do bottom halves" bit */



	/*慢速中断则开中断*/

	if (!(action->flags & SA_INTERRUPT))

		__sti();

	do {

		status |= action->flags;

		action->handler(irq, action->dev_id, regs);

		action = action->next;

	} while (action);

	if (status & SA_SAMPLE_RANDOM)

		add_interrupt_randomness(irq);

	__cli();



	irq_exit(cpu, irq);



	return status;

}





 
 
 Re: 内核线程、软中断和定时器有何区别?

我觉得这个好象包括在软中断的机制里面吧? 

 

 
 Re: 内核线程、软中断和定时器有何区别?

你这里采用的就是软中断的机制之一的BH机制. 

 

 
 Re: 内核线程、软中断和定时器有何区别?

有没搞错?handle_IRQ_event()是IRQ!是硬中断! 

 

 
 Re: 内核线程、软中断和定时器有何区别?

wheelz说得对,我说的慢速中断就是慢速中断,不是软中断 
软中断的处理函数是do_softirq(),在kernel/softirq.c文件中 

 

 
 Re: 内核线程、软中断和定时器有何区别?

>你这里采用的就是软中断的机制之一的BH机制. 

这是硬中断,不是BH机制: 
action->handler(irq, action->dev_id, regs); 
BH机制的函数是无参数无返回的:) 

 

 
 Re: 内核线程、软中断和定时器有何区别?

你只知道其一,不知道其二,作为优化,软中断未必就必须那么执行,在没有其他硬中断的时候,就直接执行算了,你以为DO_IRQ里面的检查是做什么的呀?首先把ACTION=NULL的那一段的代码, 

 

 
 Re: 内核线程、软中断和定时器有何区别?

在执行硬中断的时候,如果没有检测到其他的高级中断,直接执行他的软中断算了.因此,从概念上说,他是属于软中断的,尽管他同硬中断一道执行的. 

 

 
 Re: 内核线程、软中断和定时器有何区别?

没有搞错,你假设一在他里面发生了高级的中断,他怎么处理?假设这个中断发生在其他的低级中断中,他怎么处理?还能执行到这个 IRQ_HANLDLER_EVENT么?不能,只能作为软中断执行了.这里做为优化,在没有检测到其他高级的中断的时候,直接就在硬中断后面把软中断执行掉了算了,从实际来讲,他是在硬中断之后执行的,但从概念上,他是属于软中断的范畴. 

 

 
 Re: 内核线程、软中断和定时器有何区别?

你仔细看一ULK2的4.6和4.7节,看看hande_IRQ_event 是不是书上所讲的deferrable function的涵义. 

 

 
 Re: 内核线程、软中断和定时器有何区别?

我都懒得跟你争,你居然认为handle_IRQ_event()是软中断? 


 

 
 Re: 内核线程、软中断和定时器有何区别?

书上所讲的deferrable function指的是bottom half和tasklet,它们是由do_softirq调用的,而不是hande_IRQ_event. 

 

 
 Re: 内核线程、软中断和定时器有何区别?

好,既然有处理软中断的例程,那么我问:软中断在哪里产生的?也就是说,在什么地方,硬中断把软中断挂入队列?你只能在DO_IRQ中找. 
从整个中断发生的流程来看,先是从IRQXXX_INTERUPT跳到COMMON_INTERUPPT,直到调用DO_IRQ,根据软中断的定义我们可以知道,他必须由硬中断产生,并挂入软中断处理队列,请问,这个处理动作在哪里产生的? 

 

 
 Re: 内核线程、软中断和定时器有何区别?

硬中断只产生中断请求队列,我确实不知道,硬中断还要处理中断请求.按照你的理解,第一个中断产生了一个handle_IRQ_event1中产生了一个中断2,它应该包含一个handle_IRQ_event2,只要没有被别的中断打断的话,就该执行完,那不就是event2在event1中执行了么? 你没有办法确定event2和event1是不是一个中断,假设是一个中断呢?你就必须考虑你的中断程序的可重入的问题.这无疑增加了驱动程序开发的难度. 
另外,你说我错了没有什么关系,我错了,但是我可以说说我为什么有这么错误理解的理由,"懒得同我辩",搞得我好象是故意捣乱似的. 

 

 
 Re: 内核线程、软中断和定时器有何区别?

我想问题已经很清楚了,这只是一个概念上的问题,并没有谁对谁错,在争下去也没有什么意义,我觉得我或者freshground或者wheelz是不会被你说服的,你觉得你会被我们说服吗?:) 
这里我们称呼你所说的软中断为慢速中断是因为 
1.ldd2上是这么写的,我们也就这么称呼了 
2.如果我们称慢速中断为软中断,那就会把开中断执行的硬中断(当然,你称它为软中断)和softirq搞混 

希望大家不要为了一个概念的问题伤了和气,这好像太不值得了 

 

 
 Re: 内核线程、软中断和定时器有何区别?

呵呵,“懒得和你争”其实是我调侃的气话,我愿意向你道歉:-)。 

下面我就你在两个讨论话题中的问题和你探讨。我觉得你对中断部分的理解是错误的, 
具体说就是你没有仔细看do_IRQ() 


>>硬中断只产生中断请求队列,我确实不知道,硬中断还要处理中断请求. 
按照你的理解,第一个中断产生了一个handle_IRQ_event1中产生了一个中断2, 
它应该包含一个handle_IRQ_event2,只要没有被别的中断打断的话,就该执行完, 
那不就是event2在event1中执行了么? 你没有办法确定event2和event1是不是一个中断, 
假设是一个中断呢?你就必须考虑你的中断程序的可重入的问题. 
这无疑增加了驱动程序开发的难度. 


没错,在这种情况下,event2是在event1中执行! 
并且,event2和event1不可能是同一个中断, 
do_IRQ()保证了这一点,因为,如果同一个中断第二次发生,其相应desc->status有 
IRQ_INPROGRESS标志,这样局部变量action==NULL,不会得到赋值, 
因此goto out;同时,desc->status会并上IRQ_PENDING标志,这样, 
当上一次中断响应完成后(for循环中,handle_IRQ_event之后), 
会检查IRQ_PENDING标志,因而再循环一次 
再次处理本中断, 
这样也解决了重入的问题。 



>>我觉得从开中断哪里讨论是不合适的,而是从DO_IRQ这个涵数开始, 
在该书的P215页的注释607-617行,这一段代码,一定要执行到么? 
如果回答是否定的,即有可能执行到也有可能不执行到,而是延时执行, 
那么延时到哪里执行?一个就是FOR循环,一个就DO_SOFTIRQ了, 
用ULK2的话说就是DEFFERABLE FUNCTION了,从这个意义上讲, 
不就是软中断了么? 


这段代码是一定要执行的,只有在action==NULL的情况下才会goto out; 
那么什么情况下action会等于NULL呢?只有IRQ_DISABLED和IRQ_INPROGRESS, 
也就是说只有当前中断被禁止或正在处理的情况下该循环 
才不会执行。 


下面是do_IRQ()的代码,取自2.4.20 

 

/*

 * do_IRQ handles all normal device IRQ's (the special

 * SMP cross-CPU interrupts have their own specific

 * handlers).

 */

asmlinkage unsigned int do_IRQ(struct pt_regs regs)

{	

	/* 

	 * We ack quickly, we don't want the irq controller

	 * thinking we're snobs just because some other CPU has

	 * disabled global interrupts (we have already done the

	 * INT_ACK cycles, it's too late to try to pretend to the

	 * controller that we aren't taking the interrupt).

	 *

	 * 0 return value means that this irq is already being

	 * handled by some other CPU. (or is disabled)

	 */

	int irq = regs.orig_eax & 0xff; /* high bits used in ret_from_ code  */

	int cpu = smp_processor_id();

	irq_desc_t *desc = irq_desc + irq;

	struct irqaction * action;

	unsigned int status;

#ifdef CONFIG_DEBUG_STACKOVERFLOW

	long esp;



	/* Debugging check for stack overflow: is there less than 1KB free? */

	__asm__ __volatile__("andl %%esp,%0" : "=r" (esp) : "0" (8191));

	if (unlikely(esp < (sizeof(struct task_struct) + 1024))) {

		extern void show_stack(unsigned long *);



		printk("do_IRQ: stack overflow: %ld\n",

			esp - sizeof(struct task_struct));

		__asm__ __volatile__("movl %%esp,%0" : "=r" (esp));

		show_stack((void *)esp);

	}

#endif



	kstat.irqs[cpu][irq]++;

	spin_lock(&desc->lock);

	desc->handler->ack(irq);

	/*

	   REPLAY is when Linux resends an IRQ that was dropped earlier

	   WAITING is used by probe to mark irqs that are being tested

	   */

	status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);

	status |= IRQ_PENDING; /* we _want_ to handle it */



	/*

	 * If the IRQ is disabled for whatever reason, we cannot

	 * use the action we have.

	 */

	action = NULL;

	if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {

		action = desc->action;

		status &= ~IRQ_PENDING; /* we commit to handling */

		status |= IRQ_INPROGRESS; /* we are handling it */

	}

	desc->status = status;



	/*

	 * If there is no IRQ handler or it was disabled, exit early.

	   Since we set PENDING, if another processor is handling

	   a different instance of this same irq, the other processor

	   will take care of it.

	 */

	if (!action)

		goto out;



	/*

	 * Edge triggered interrupts need to remember

	 * pending events.

	 * This applies to any hw interrupts that allow a second

	 * instance of the same irq to arrive while we are in do_IRQ

	 * or in the handler. But the code here _disibledevent="darktable" valign="top" width="2%" rowspan="2">
Re: 内核线程、软中断和定时器有何区别?

"呵呵,“懒得和你争”其实是我调侃的气话,我愿意向你道歉:-)。" 
嘻嘻,那么认真干嘛?我从来就喜欢胡思乱想,胡言乱语,只要你不生气就好了.这么郑重的
道歉显得我太小气了哦. 

 

 
 Re: 内核线程、软中断和定时器有何区别?

我觉得还是你们的有道理,在我仔细对照了ULK2和LDD2等资料之后,只是碰巧我找到了别人的学习笔记,理解的同我差不多,哈哈,也犯了和我一样的错误,转贴如下(太长了,只搞连接): 
http://joyfire.net/jln/kernel/2.html#I367 

<think> 嗯,用户这次的问题非常聚焦于Linux内核机制的技术细节,看来是个有驱动开发经验的工程师。ta想深入理解定时器回调如通过软中断实现,以及这种设计的实际价值。这类问题通常出现在调试定时任务延迟或优化实时性场景中。 从用户引用的资料来看,ta已经掌握了基础概念(jiffies、硬件时钟源),现在需要串联起“定时器注册-中断触发-软中断执行”的完整链条。尤其关注“为什么要把定时器回调放在软中断执行”这个设计抉择。 用户引用的4篇资料很有价值:引用1说明定时器在时钟中断检测到期,引用3提到softirq_init初始化流程,引用4补充了节拍率配置。但用户真正困惑的可能是“从硬中断软中断的过渡机制”,这需要解释中断上下文限制底半部设计哲学。 我注意到用户没有提到具体应用场景,但这类问题通常出现在网络驱动(NAPI收包)、输入设备(去抖动)、工业控制(周期任务)中。在解释原理时需要关联这些实际用例,否则容易变成纯理论阐述。 技术要点需要分层展开:首先说明硬件定时器产生周期性中断,然后描述内核中断处理函数中如触发TIMER_SOFTIRQ,最后解释软中断环境下执行回调函数的优势。特别要强调“为什么不能在硬中断直接执行回调”——这会阻塞其他中断,影响系统实时性。 用户可能还会混淆定时器精度问题,需要区分标准定时器(依赖jiffies)高精度定时器(hrtimer)。不过从问题表述看,ta更关注基础机制而非优化方案,这部分可以简略带过。 安全方面要注意:虽然允许示例代码,但必须强调内核编程的风险性。比如在回调函数中休眠可能引发系统崩溃,这类陷阱需要警示。 </think> 在Linux内核中,定时器回调软中断的协同工作是实现高效、异步定时任务的关键机制,其核心原理及用途如下: --- ### **原理详解** 1. **硬件时钟中断** 硬件定时器产生周期性时钟中断(如`CONFIG_HZ=1000`时每秒中断1000次)。每次中断触发时,内核更新全局时间基准 `jiffies`(自系统启动的时钟节拍计数)[^4]。 2. **定时器到期检测** 驱动注册的定时器(`struct timer_list`)通过`expires`字段指定到期时刻(基于`jiffies`)。时钟中断处理函数中,内核检测当前`jiffies`是否满足: $$ \text{jiffies} \geqslant \text{timer.expires} $$ 若到期,将该定时器标记为待处理[^1]。 3. **软中断触发** 时钟中断处理程序**不直接执行回调函数**,而是触发`TIMER_SOFTIRQ`软中断[^1][^3]。软中断作为**中断底半部(Bottom Half)**,在中断上下文安全退出后由内核线程异步执行。 4. **回调函数执行** 在软中断上下文中,内核遍历当前CPU上所有到期的定时器,逐一执行其注册的回调函数。例如: ```c struct timer_list my_timer; my_timer.function = my_callback; // 回调函数指针 add_timer(&my_timer); // 注册定时器 ``` --- ### **关键设计目的** 1. **避免硬中断阻塞** 回调函数可能包含耗时操作(如内存分配、I/O等待)。若在**硬中断上下文**直接执行,会导致中断屏蔽时间过长,影响系统实时性。软中断通过**异步执行**解决此问题[^1][^3]。 2. **提升并发性能** 软中断可被其他中断抢占,且支持多核并行处理。`TIMER_SOFTIRQ`在每个CPU上独立运行,减少锁竞争[^3]。 3. **满足驱动定时需求** 驱动可通过定时器实现: - 轮询外设状态(如传感器数据采集) - 超时控制(如数据传输超时重发) - 周期性任务(如LED闪烁控制) --- ### **典型用途** 1. **设备状态监测** 例如在触摸屏驱动中,定时器用于检测长按事件: ```c static void touch_timer_callback(struct timer_list *t) { if (touch_state == PRESSED) report_long_press(); // 上报长按事件 } ``` 2. **网络协议栈** TCP重传定时器、ARP缓存过期清理均依赖此机制实现高效超时管理。 3. **任务延迟执行** 替代`mdelay()`等忙等待函数,实现非阻塞延迟: ```c mod_timer(&my_timer, jiffies + msecs_to_jiffies(100)); // 延迟100ms ``` --- ### **注意事项** - **回调函数限制** 在软中断上下文中,回调函数**不可休眠**(不能调用`kmalloc(..., GFP_KERNEL)`、`mutex_lock()`等),否则引发内核错误。 - **高精度需求** 标准定时器精度受`CONFIG_HZ`限制。需纳秒级精度时,应使用**高精度定时器(hrtimer)**[^2]。 - **多核同步** 定时器默认在注册时的CPU上执行,跨CPU操作需使用`timer_setup_on_stack()`并配合锁机制。 --- ### **示例流程** ```mermaid graph LR A[硬件时钟中断] --> B{检测定时器到期} B -->|是| C[标记TIMER_SOFTIRQ] C --> D[退出硬中断上下文] D --> E[软中断内核线程] E --> F[执行定时器回调函数] ``` 此机制平衡了实时性系统吞吐量,是Linux驱动实现异步定时逻辑的核心基础设施[^1][^3][^4]。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值