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

软中断-softirq

特点

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

何时执行

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

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

使用策略

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

使用方法

注册软中断

void open_softirq(int nr, void (*action)(struct softirq_action *))

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

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

 };
action为响应函数。

触发软中断

void raise_softirq(unsigned int nr);

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

tasklet

关键数据

struct tasklet_struct

 {

 struct tasklet_struct *next;

 unsigned long state;

 atomic_t count;

 void (*func)(unsigned long);

 unsigned long data;

 };

执行原理

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

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

使用

DECLARE_TASKLET(name, func, data)

DECLARE_TASKLET_DISABLED(name, func, data)
void tasklet_schedule(struct tasklet_struct *t)
void tasklet_disable(struct tasklet_struct *t)

void tasklet_enable(struct tasklet_struct *t)

ksoftirqd

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

 工作队列

 特点

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

关键数据

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 */

 };
struct work_struct {

 atomic_long_t data;

 struct list_head entry;

 work_func_t func;

 #ifdef CONFIG_LOCKDEP

 struct lockdep_map lockdep_map;

 #endif

 };

使用

创建

DECLARE_WORK(n, f)

INIT_WORK

处理函数

void work_handler(void *)

触发

schedule_work(&work)

schedule_delayed_work(&work, delay)

 

比较

 

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

你可能感兴趣的:(linux)