linux内核学习:中断中推后执行的部分

软中断-softirq

特点

  • 相同和不同的软中断都可以在不同处理器上同时执行
  • 一个软中断不会抢占另一个软中断

何时执行

  • 从中断程序返回时
  • ksoftirqd线程中
  • 显示调用

软中断最多有32个,一个32位的整型数据可以被用来标记刮起的软中断

使用策略

软中断应用于确实需要的场合,目前只有网络驱动和SCSI驱动中使用。另外,内核定时器和tasklet建立在软中断之上。

使用方法

注册软中断

linux内核学习:中断中推后执行的部分
void open_softirq(int nr, void (*action)(struct softirq_action *))
linux内核学习:中断中推后执行的部分

nr 静态指定于 linux/interrupt.h ,例如:

linux内核学习:中断中推后执行的部分
enum
{
 HI_SOFTIRQ=0,
 TIMER_SOFTIRQ,
 NET_TX_SOFTIRQ,
 NET_RX_SOFTIRQ,
 BLOCK_SOFTIRQ,
 BLOCK_IOPOLL_SOFTIRQ,
 TASKLET_SOFTIRQ,
 SCHED_SOFTIRQ,
 HRTIMER_SOFTIRQ,
 RCU_SOFTIRQ,    /* Preferable RCU should always be the last softirq */
 NR_SOFTIRQS
 };
linux内核学习:中断中推后执行的部分
action为响应函数。

触发软中断

linux内核学习:中断中推后执行的部分
void raise_softirq(unsigned int nr);
linux内核学习:中断中推后执行的部分

会标记某个软中断为挂起状态,以便在何时的时机执行响应函数。

tasklet

关键数据

linux内核学习:中断中推后执行的部分
struct tasklet_struct
 {
 struct tasklet_struct *next;
 unsigned long state;
 atomic_t count;
 void (*func)(unsigned long);
 unsigned long data;
 };
linux内核学习:中断中推后执行的部分

执行原理

连个软中断 HI_SOFTIRQ和 TASKLED_SOFTIRQ,每个下面挂这一个tasklet链表,执行相应软中断的时候,会遍历这两个链表,执行可以执行的tasklet。

所以说tasklet其实是softirq的复用。

使用

linux内核学习:中断中推后执行的部分
DECLARE_TASKLET(name, func, data)
DECLARE_TASKLET_DISABLED(name, func, data)
linux内核学习:中断中推后执行的部分
linux内核学习:中断中推后执行的部分
void tasklet_schedule(struct tasklet_struct *t)
linux内核学习:中断中推后执行的部分
linux内核学习:中断中推后执行的部分
void tasklet_disable(struct tasklet_struct *t)
void tasklet_enable(struct tasklet_struct *t)
linux内核学习:中断中推后执行的部分

ksoftirqd

软中断辅助处理线程,每个CPU核心有一个,nice值为19,优先级最低。

 工作队列

 特点

每个处理器核心对应一个内核线程。

关键数据

linux内核学习:中断中推后执行的部分
struct workqueue_struct {
 struct list_head        pwqs;           /* WR: all pwqs of this wq */
 struct list_head        list;           /* PL: list of all workqueues */
 
 struct mutex            mutex;          /* protects this wq */
 int                     work_color;     /* WQ: current work color */
 int                     flush_color;    /* WQ: current flush color */
 atomic_t                nr_pwqs_to_flush; /* flush in progress */
 struct wq_flusher       *first_flusher; /* WQ: first flusher */
 struct list_head        flusher_queue;  /* WQ: flush waiters */
 struct list_head        flusher_overflow; /* WQ: flush overflow list */
 
 struct list_head        maydays;        /* MD: pwqs requesting rescue */
 struct worker           *rescuer;       /* I: rescue worker */
 
 int                     nr_drainers;    /* WQ: drain in progress */
 int                     saved_max_active; /* WQ: saved pwq max_active */
 
 struct workqueue_attrs  *unbound_attrs; /* WQ: only for unbound wqs */
 struct pool_workqueue   *dfl_pwq;       /* WQ: only for unbound wqs */
 
 #ifdef CONFIG_SYSFS
 struct wq_device        *wq_dev;        /* I: for sysfs interface */
 #endif
 #ifdef CONFIG_LOCKDEP
 struct lockdep_map      lockdep_map;
 #endif
 char                    name[WQ_NAME_LEN]; /* I: workqueue name */
 
 /* hot fields used during command issue, aligned to cacheline */
 unsigned int            flags ____cacheline_aligned; /* WQ: WQ_* flags */
 struct pool_workqueue __percpu *cpu_pwqs; /* I: per-cpu pwqs */
 struct pool_workqueue __rcu *numa_pwq_tbl[]; /* FR: unbound pwqs indexed by node */
 };
linux内核学习:中断中推后执行的部分
linux内核学习:中断中推后执行的部分
struct work_struct {
 atomic_long_t data;
 struct list_head entry;
 work_func_t func;
 #ifdef CONFIG_LOCKDEP
 struct lockdep_map lockdep_map;
 #endif
 };
linux内核学习:中断中推后执行的部分

使用

创建

linux内核学习:中断中推后执行的部分
DECLARE_WORK(n, f)
INIT_WORK
linux内核学习:中断中推后执行的部分

处理函数

linux内核学习:中断中推后执行的部分
void work_handler(void *)
linux内核学习:中断中推后执行的部分

触发

linux内核学习:中断中推后执行的部分
schedule_work(&work)
schedule_delayed_work(&work, delay)
linux内核学习:中断中推后执行的部分

 

比较

 

  软中断 tasklet 工作队列
并发性 同一软中断可同时运行于不同处理器 不同处理器同时只能运行不同的tasklet  
是否可阻塞 N N Y

linux内核学习:中断中推后执行的部分,布布扣,bubuko.com

linux内核学习:中断中推后执行的部分

上一篇:Linux中的文件特殊权限


下一篇:将主机变为服务器,ssh连接出现access denied