软中断-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 |