硬中断和软中断(转)

来自:http://blog.csdn.net/zhangskd/article/details/21992933

概述

从本质上来讲,中断是一种电信号,当设备有某种事件发生时,它就会产生中断,通过总线把电信号发送给中断控制器。

如果中断的线是激活的,中断控制器就把电信号发送给处理器的某个特定引脚。处理器于是立即停止自己正在做的事,

跳到中断处理程序的入口点,进行中断处理。

(1) 硬中断

由与系统相连的外设(比如网卡、硬盘)自动产生的。主要是用来通知操作系统系统外设状态的变化。比如当网卡收到数据包

的时候,就会发出一个中断。我们通常所说的中断指的是硬中断(hardirq)。

(2) 软中断

为了满足实时系统的要求,中断处理应该是越快越好。linux为了实现这个特点,当中断发生的时候,硬中断处理那些短时间

就可以完成的工作,而将那些处理事件比较长的工作,放到中断之后来完成,也就是软中断(softirq)来完成。

(3) 中断嵌套

Linux下硬中断是可以嵌套的,但是没有优先级的概念,也就是说任何一个新的中断都可以打断正在执行的中断,但同种中断

除外。软中断不能嵌套,但相同类型的软中断可以在不同CPU上并行执行。

(4) 软中断指令

int是软中断指令。

中断向量表是中断号和中断处理函数地址的对应表。

int n - 触发软中断n。相应的中断处理函数的地址为:中断向量表地址 + 4 * n。

(5)硬中断和软中断的区别

软中断是执行中断指令产生的,而硬中断是由外设引发的。

硬中断的中断号是由中断控制器提供的,软中断的中断号由指令直接指出,无需使用中断控制器。

硬中断是可屏蔽的,软中断不可屏蔽。

硬中断处理程序要确保它能快速地完成任务,这样程序执行时才不会等待较长时间,称为上半部。

软中断处理硬中断未完成的工作,是一种推后执行的机制,属于下半部。

开关

(1) 硬中断的开关

简单禁止和激活当前处理器上的本地中断:

local_irq_disable();

local_irq_enable();

保存本地中断系统状态下的禁止和激活:

unsigned long flags;

local_irq_save(flags);

local_irq_restore(flags);

(2) 软中断的开关

禁止下半部,如softirq、tasklet和workqueue等:

local_bh_disable();

local_bh_enable();

需要注意的是,禁止下半部时仍然可以被硬中断抢占。

(3) 判断中断状态

#define in_interrupt() (irq_count()) // 是否处于中断状态(硬中断或软中断)

#define in_irq() (hardirq_count()) // 是否处于硬中断

#define in_softirq() (softirq_count()) // 是否处于软中断

硬中断

(1) 注册中断处理函数

注册中断处理函数:

[java] view plain copy

  1. /**
  2. * irq: 要分配的中断号
  3. * handler: 要注册的中断处理函数
  4. * flags: 标志(一般为0)
  5. * name: 设备名(dev->name)
  6. * dev: 设备(struct net_device *dev),作为中断处理函数的参数
  7. * 成功返回0
  8. */
  9. int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
  10. const char *name, void *dev);

中断处理函数本身:

[java] view plain copy

  1. typedef irqreturn_t (*irq_handler_t) (int, void *);
  2. /**
  3. * enum irqreturn
  4. * @IRQ_NONE: interrupt was not from this device
  5. * @IRQ_HANDLED: interrupt was handled by this device
  6. * @IRQ_WAKE_THREAD: handler requests to wake the handler thread
  7. */
  8. enum irqreturn {
  9. IRQ_NONE,
  10. IRQ_HANDLED,
  11. IRQ_WAKE_THREAD,
  12. };
  13. typedef enum irqreturn irqreturn_t;
  14. #define IRQ_RETVAL(x) ((x) != IRQ_NONE)

(2) 注销中断处理函数

[java] view plain copy

  1. /**
  2. * free_irq - free an interrupt allocated with request_irq
  3. * @irq: Interrupt line to free
  4. * @dev_id: Device identity to free
  5. *
  6. * Remove an interrupt handler. The handler is removed and if the
  7. * interrupt line is no longer in use by any driver it is disabled.
  8. * On a shared IRQ the caller must ensure the interrupt is disabled
  9. * on the card it drives before calling this function. The function does
  10. * not return until any executing interrupts for this IRQ have completed.
  11. * This function must not be called from interrupt context.
  12. */
  13. void free_irq(unsigned int irq, void *dev_id);

软中断

(1) 定义

软中断是一组静态定义的下半部接口,可以在所有处理器上同时执行,即使两个类型相同也可以。

但一个软中断不会抢占另一个软中断,唯一可以抢占软中断的是硬中断。

软中断由softirq_action结构体表示:

[java] view plain copy

  1. struct softirq_action {
  2. void (*action) (struct softirq_action *); /* 软中断的处理函数 */
  3. };

目前已注册的软中断有10种,定义为一个全局数组:

[java] view plain copy

  1. static struct softirq_action softirq_vec[NR_SOFTIRQS];
  2. enum {
  3. HI_SOFTIRQ = 0, /* 优先级高的tasklets */
  4. TIMER_SOFTIRQ, /* 定时器的下半部 */
  5. NET_TX_SOFTIRQ, /* 发送网络数据包 */
  6. NET_RX_SOFTIRQ, /* 接收网络数据包 */
  7. BLOCK_SOFTIRQ, /* BLOCK装置 */
  8. BLOCK_IOPOLL_SOFTIRQ,
  9. TASKLET_SOFTIRQ, /* 正常优先级的tasklets */
  10. SCHED_SOFTIRQ, /* 调度程序 */
  11. HRTIMER_SOFTIRQ, /* 高分辨率定时器 */
  12. RCU_SOFTIRQ, /* RCU锁定 */
  13. NR_SOFTIRQS /* 10 */
  14. };

(2) 注册软中断处理函数

[java] view plain copy

  1. /**
  2. * @nr: 软中断的索引号
  3. * @action: 软中断的处理函数
  4. */
  5. void open_softirq(int nr, void (*action) (struct softirq_action *))
  6. {
  7. softirq_vec[nr].action = action;
  8. }

例如:

open_softirq(NET_TX_SOFTIRQ, net_tx_action);

open_softirq(NET_RX_SOFTIRQ, net_rx_action);

(3) 触发软中断

调用raise_softirq()来触发软中断。

[java] view plain copy

  1. void raise_softirq(unsigned int nr)
  2. {
  3. unsigned long flags;
  4. local_irq_save(flags);
  5. raise_softirq_irqoff(nr);
  6. local_irq_restore(flags);
  7. }
  8. /* This function must run with irqs disabled */
  9. inline void rasie_softirq_irqsoff(unsigned int nr)
  10. {
  11. __raise_softirq_irqoff(nr);
  12. /* If we‘re in an interrupt or softirq, we‘re done
  13. * (this also catches softirq-disabled code). We will
  14. * actually run the softirq once we return from the irq
  15. * or softirq.
  16. * Otherwise we wake up ksoftirqd to make sure we
  17. * schedule the softirq soon.
  18. */
  19. if (! in_interrupt()) /* 如果不处于硬中断或软中断 */
  20. wakeup_softirqd(void); /* 唤醒ksoftirqd/n进程 */
  21. }

Percpu变量irq_cpustat_t中的__softirq_pending是等待处理的软中断的位图,通过设置此变量

即可告诉内核该执行哪些软中断。

[java] view plain copy

  1. static inline void __rasie_softirq_irqoff(unsigned int nr)
  2. {
  3. trace_softirq_raise(nr);
  4. or_softirq_pending(1UL << nr);
  5. }
  6. typedef struct {
  7. unsigned int __softirq_pending;
  8. unsigned int __nmi_count; /* arch dependent */
  9. } irq_cpustat_t;
  10. irq_cpustat_t irq_stat[];
  11. #define __IRQ_STAT(cpu, member) (irq_stat[cpu].member)
  12. #define or_softirq_pending(x) percpu_or(irq_stat.__softirq_pending, (x))
  13. #define local_softirq_pending() percpu_read(irq_stat.__softirq_pending)

唤醒ksoftirqd内核线程处理软中断。

[java] view plain copy

  1. static void wakeup_softirqd(void)
  2. {
  3. /* Interrupts are disabled: no need to stop preemption */
  4. struct task_struct *tsk = __get_cpu_var(ksoftirqd);
  5. if (tsk && tsk->state != TASK_RUNNING)
  6. wake_up_process(tsk);
  7. }

在下列地方,待处理的软中断会被检查和执行:

1. 从一个硬件中断代码处返回时

2. 在ksoftirqd内核线程中

3. 在那些显示检查和执行待处理的软中断的代码中,如网络子系统中

而不管是用什么方法唤起,软中断都要在do_softirq()中执行。如果有待处理的软中断,

do_softirq()会循环遍历每一个,调用它们的相应的处理程序。

在中断处理程序中触发软中断是最常见的形式。中断处理程序执行硬件设备的相关操作,

然后触发相应的软中断,最后退出。内核在执行完中断处理程序以后,马上就会调用

do_softirq(),于是软中断开始执行中断处理程序完成剩余的任务。

下面来看下do_softirq()的具体实现。

[java] view plain copy

  1. asmlinkage void do_softirq(void)
  2. {
  3. __u32 pending;
  4. unsigned long flags;
  5. /* 如果当前已处于硬中断或软中断中,直接返回 */
  6. if (in_interrupt())
  7. return;
  8. local_irq_save(flags);
  9. pending = local_softirq_pending();
  10. if (pending) /* 如果有激活的软中断 */
  11. __do_softirq(); /* 处理函数 */
  12. local_irq_restore(flags);
  13. }

[java] view plain copy

  1. /* We restart softirq processing MAX_SOFTIRQ_RESTART times,
  2. * and we fall back to softirqd after that.
  3. * This number has been established via experimentation.
  4. * The two things to balance is latency against fairness - we want
  5. * to handle softirqs as soon as possible, but they should not be
  6. * able to lock up the box.
  7. */
  8. asmlinkage void __do_softirq(void)
  9. {
  10. struct softirq_action *h;
  11. __u32 pending;
  12. /* 本函数能重复触发执行的次数,防止占用过多的cpu时间 */
  13. int max_restart = MAX_SOFTIRQ_RESTART;
  14. int cpu;
  15. pending = local_softirq_pending(); /* 激活的软中断位图 */
  16. account_system_vtime(current);
  17. /* 本地禁止当前的软中断 */
  18. __local_bh_disable((unsigned long)__builtin_return_address(0), SOFTIRQ_OFFSET);
  19. lockdep_softirq_enter(); /* current->softirq_context++ */
  20. cpu = smp_processor_id(); /* 当前cpu编号 */
  21. restart:
  22. /* Reset the pending bitmask before enabling irqs */
  23. set_softirq_pending(0); /* 重置位图 */
  24. local_irq_enable();
  25. h = softirq_vec;
  26. do {
  27. if (pending & 1) {
  28. unsigned int vec_nr = h - softirq_vec; /* 软中断索引 */
  29. int prev_count = preempt_count();
  30. kstat_incr_softirqs_this_cpu(vec_nr);
  31. trace_softirq_entry(vec_nr);
  32. h->action(h); /* 调用软中断的处理函数 */
  33. trace_softirq_exit(vec_nr);
  34. if (unlikely(prev_count != preempt_count())) {
  35. printk(KERN_ERR "huh, entered softirq %u %s %p" "with preempt_count %08x,"
  36. "exited with %08x?\n", vec_nr, softirq_to_name[vec_nr], h->action, prev_count,
  37. preempt_count());
  38. }
  39. rcu_bh_qs(cpu);
  40. }
  41. h++;
  42. pending >>= 1;
  43. } while(pending);
  44. local_irq_disable();
  45. pending = local_softirq_pending();
  46. if (pending & --max_restart) /* 重复触发 */
  47. goto restart;
  48. /* 如果重复触发了10次了,接下来唤醒ksoftirqd/n内核线程来处理 */
  49. if (pending)
  50. wakeup_softirqd();
  51. lockdep_softirq_exit();
  52. account_system_vtime(current);
  53. __local_bh_enable(SOFTIRQ_OFFSET);
  54. }

(4) ksoftirqd内核线程

内核不会立即处理重新触发的软中断。

当大量软中断出现的时候,内核会唤醒一组内核线程来处理。

这些线程的优先级最低(nice值为19),这能避免它们跟其它重要的任务抢夺资源。

但它们最终肯定会被执行,所以这个折中的方案能够保证在软中断很多时用户程序不会

因为得不到处理时间而处于饥饿状态,同时也保证过量的软中断最终会得到处理。

每个处理器都有一个这样的线程,名字为ksoftirqd/n,n为处理器的编号。

[java] view plain copy

    1. static int run_ksoftirqd(void *__bind_cpu)
    2. {
    3. set_current_state(TASK_INTERRUPTIBLE);
    4. current->flags |= PF_KSOFTIRQD; /* I am ksoftirqd */
    5. while(! kthread_should_stop()) {
    6. preempt_disable();
    7. if (! local_softirq_pending()) { /* 如果没有要处理的软中断 */
    8. preempt_enable_no_resched();
    9. schedule();
    10. preempt_disable():
    11. }
    12. __set_current_state(TASK_RUNNING);
    13. while(local_softirq_pending()) {
    14. /* Preempt disable stops cpu going offline.
    15. * If already offline, we‘ll be on wrong CPU: don‘t process.
    16. */
    17. if (cpu_is_offline(long)__bind_cpu))/* 被要求释放cpu */
    18. goto wait_to_die;
    19. do_softirq(); /* 软中断的统一处理函数 */
    20. preempt_enable_no_resched();
    21. cond_resched();
    22. preempt_disable();
    23. rcu_note_context_switch((long)__bind_cpu);
    24. }
    25. preempt_enable();
    26. set_current_state(TASK_INTERRUPTIBLE);
    27. }
    28. __set_current_state(TASK_RUNNING);
    29. return 0;
    30. wait_to_die:
    31. preempt_enable();
    32. /* Wait for kthread_stop */
    33. set_current_state(TASK_INTERRUPTIBLE);
    34. while(! kthread_should_stop()) {
    35. schedule();
    36. set_current_state(TASK_INTERRUPTIBLE);
    37. }
    38. __set_current_state(TASK_RUNNING);
    39. return 0;
时间: 2024-11-08 14:23:57

硬中断和软中断(转)的相关文章

关于linux硬中断、软中断、软中断指令、信号的简明解释

硬中断: 1.同步中断(内部中断/异常) core内部触发的中断,当中断发生时.会等待流水线完成后,再去执行中断.包含软中断指令.中断的标志由软件或者硬件设置. 2.异步中断(外部中断/中断) core外部触发的中断,当中断发生时.不会等待流水线完成,就会立即执行.此时流水线作废.中断的标志由硬件设置. 软中断: linux中断机制的下半部分(下半部:软中断,普通进程处理方式).软件上模拟硬件中断,达到异步调用下半部服务函数的功能. 软中断指令: 由程序设置中断标志后,硬件接着执行中断的相关操作

硬中断与软中断的区别!!!

硬中断: 1. 硬中断是由硬件产生的,比如,像磁盘,网卡,键盘,时钟等.每个设备或设备集都有它自己的IRQ(中断请求).基于IRQ,CPU可以将相应的请求分发到对应的硬件驱动上(注:硬件驱动通常是内核中的一个子程序,而不是一个独立的进程). 2. 处理中断的驱动是需要运行在CPU上的,因此,当中断产生的时候,CPU会中断当前正在运行的任务,来处理中断.在有多核心的系统上,一个中断通常只能中断一颗CPU(也有一种特殊的情况,就是在大型主机上是有硬件通道的,它可以在没有主CPU的支持下,可以同时处理

Linux性能优化从入门到实战:05 CPU篇:硬中断、软中断

??软中断(softirq)会导致CPU 使用率升高 ??中断是系统用来响应硬件设备请求的一种机制,它会打断进程的正常调度和执行,然后调用内核中的中断处理程序来响应设备的请求.中断其实是一种异步的事件处理机制,可以提高系统的并发处理能力.由于中断处理程序会打断其他进程的运行,所以,为了减少对正常进程运行调度的影响,中断处理程序就需要尽可能快地运行.并且当CPU执行在中断处理函数中时,不会响应同时发生的又一次中断. ??所以为了加快中断处理程序执行和解决中断丢失的问题,Linux将中断分为上半部和

软中断与硬中断 &amp; 中断抢占 中断嵌套

参考了这篇文章:http://blog.csdn.net/zhangskd/article/details/21992933 从本质上来讲,中断是一种电信号,当设备有某种事件发生时,它就会产生中断,通过总线把电信号发送给中断控制器. 如果中断的线是激活的,中断控制器就把电信号发送给处理器的某个特定引脚.处理器于是立即停止自己正在做的事, 跳到中断处理程序的入口点,进行中断处理. (1) 硬中断 由与系统相连的外设(比如网卡.硬盘)自动产生的.主要是用来通知操作系统系统外设状态的变化.比如当网卡收

基于 Linux 2.6的 硬中断 / 软中断的原理以及实现

Author:zhangskd @ csdn blog 概述 从本质上来讲,中断是一种电信号,当设备有某种事件发生时,它就会产生中断,通过总线把电信号发送给中断控制器. 如果中断的线是激活的,中断控制器就把电信号发送给处理器的某个特定引脚.处理器于是立即停止自己正在做的事, 跳到中断处理程序的入口点,进行中断处理. 有关概念 (1) 硬中断 由与系统相连的外设(比如网卡.硬盘)自动产生的.主要是用来通知操作系统系统外设状态的变化.比如当网卡收到数据包的时候,就会发出一个中断.我们通常所说的中断指

软中断和硬中断(转)

1.中断:通常被定义成一个事件,该事件改变处理器执行的指令顺序.这样的事件与cpu芯片外部电路产生 的电信号相对应.2.中断的产生:每个能够发出中断请求的硬件设备控制器都有一条称为IRQ的输出线(中断线).所有的IRQ线都 与一个中断控制器的输入引脚相连,中断控制器与cpu的intr引脚相连.3.中断向量:每个中断由0-255之间的一个8位数来标识.称为中断向量.4.中断描述符表:IDT是一个系统表,它与每一个中断或者异常向量相联系,每一个向量在表中有相应的中断处理程 序的入口地址.cpu的id

软中断和硬中断

http://www.cnblogs.com/huayuan/archive/2012/05/18/2507150.html 1.中断: 通常被定义成一个事件,该事件改变处理器执行的指令顺序.这样的事件与cpu芯片外部电路产生 的电信号相对应.2.中断的产生: 每个能够发出中断请求的硬件设备控制器都有一条称为IRQ的输出线(中断线).所有的IRQ线都 与一个中断控制器的输入引脚相连,中断控制器与cpu的intr引脚相连.3.中断向量: 每个中断由0-255之间的一个8位数来标识.称为中断向量.4

Linux内核源代码情景分析-中断下半部(软中断)

Tasklet机制是一种较为特殊的软中断.Tasklet一词的原意是"小片任务"的意思,这里是指一小段可执行的代码,且通常以函数的形式出现.软中断向量HI_SOFTIRQ和TASKLET_SOFTIRQ均是用tasklet机制来实现的.      从某种程度上讲,tasklet机制是Linux内核对BH机制的一种扩展.在2.4内核引入了softirq机制后,原有的BH机制正是通过tasklet机制这个桥梁来纳入softirq机制的整体框架中的.正是由于这种历史的延伸关系,使得taskl

把握linux内核设计(二):硬中断及中断处理

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 操作系统负责管理硬件设备,为了使系统和硬件设备的协同工作不降低机器性能,系统和硬件的通信使用中断的机制,也就是让硬件在需要的时候向内核发出信号,这样使得内核不用去轮询设备而导致做很多无用功. 中断使得硬件可以发出通知给处理器,硬件设备生成中断的时候并不考虑与处理器的时钟同步,中断可以随时产生.也就是说,内核随时可能因为新到来的中断而被打断.当接收到一个中断后,中断控制器会给处