(笔记)Linux内核学习(五)之中断推后处理机制
一 中断
硬件通过中断与操作系统进行通信,通过对硬件驱动程序处注册中断处理程序,快速响应硬件的中断。
硬件中断优先级很高,打断当前正在执行的程序。有两种情况:
硬件中断在中断处理程序中处理
硬件中断延后再进行处理
这个具体硬件相关,在中断处理程序中处理,打断了当前正在执行的程序;所有中断都将被屏蔽;如果占用时间太长不合适,
造成系统交互性,反应能力都会受到影响。 需要在其中判断平衡:
如果一个任务对时间非常敏感,将其放在中断处理程序中执行;
如果一个人和和硬件相关,将其放在中断处理程序中执行;
如果一个任务要保证不被其他中断打断,将其放在中断处理程序中执行;
其余情况考虑延后机制中执行——下半部。
二 中断推后执行机制—— 软中断
软中断是在编译期间静态分配的,在程序执行前将软中断假如到表中。
下面看一下这个过程:
加入软中断类型:
Linux3.5.3代码:

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 };

//软中断表:
static struct softirq_action softirq_vec[NR_SOFTIRQS]
//软中断结构体
struct softirq_action
{
void (*action)(struct softirq_action *);
};
注册软中断处理函数:
void open_softirq(int nr, void (*action)(struct softirq_action *))
{
//关联表中对应类型
softirq_vec[nr].action = action;
}
触发软中断:

void raise_softirq(unsigned int nr)
{
unsigned long flags; //停止但保存中断标志
local_irq_save(flags); //将相应软中断挂起状态
raise_softirq_irqoff(nr); //恢复中断
local_irq_restore(flags);
}

执行软中断:

void irq_exit(void)
{
invoke_softirq(); //do_softirq();
} void __do_softirq(void)
{
struct softirq_action *h;
__u32 pending;
int max_restart = MAX_SOFTIRQ_RESTART;
int cpu; //获取CPU软中断状态标志位 32位代表最多32个软中断
pending = local_softirq_pending(); restart:
/* Reset the pending bitmask before enabling irqs */
set_softirq_pending(0);
local_irq_enable();
h = softirq_vec;
do {
//被触发则执行软中断处理程序
if (pending & 1) {
h->action(h);
} //下一个软中断
h++; //下一个软中断状态标志位
pending >>= 1;
} while (pending); local_irq_disable();
pending = local_softirq_pending();
if (pending && --max_restart)
goto restart; if (pending)
wakeup_softirqd();
lockdep_softirq_exit();
__local_bh_enable(SOFTIRQ_OFFSET);
}

软中断的基本结构如下图表示:

三 中断推后执行机制——tasklet
软中断中表中有一种类型是:TASKLET_SOFTIRQ
Tasklet就是利用软中断实现中断推后处理机制。通常使用较多的是tasklet而不是软中断。
Tasklet数据结构:

struct tasklet_struct
{
//链表中下一个tasklet
struct tasklet_struct *next; //tasklet状态
unsigned long state; //引用计数器
atomic_t count; //tasklet处理函数
void (*func)(unsigned long); //处理函数参数
unsigned long data; };

state:
enum
{
TASKLET_STATE_SCHED, /* Tasklet is scheduled for execution */
TASKLET_STATE_RUN /* Tasklet is running (SMP only) */
};
count:为0允许激活执行
声明tasklet:可以动态或者静态方式
静态:
#define DECLARE_TASKLET(name, func, data) \
struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data } #define DECLARE_TASKLET_DISABLED(name, func, data) \
struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(1), func, data }
动态:

void tasklet_init(struct tasklet_struct *t,void (*func)(unsigned long), unsigned long data)
{
t->next = NULL;
t->state = 0;
atomic_set(&t->count, 0);
t->func = func;
t->data = data;
}

同时需要编写tasklet处理函数。
调度tasklet:

void tasklet_hi_schedule(struct tasklet_struct *t)
{
unsigned long flags;
local_irq_save(flags);
t->next = NULL;
*__this_cpu_read(tasklet_vec.tail) = t;
__this_cpu_write(tasklet_vec.tail, &(t->next));
raise_softirq_irqoff(TASKLET_SOFTIRQ);
local_irq_restore(flags);
}

执行tasklet处理程序:
继续看上面调度tasklet程序执行:

inline void raise_softirq_irqoff(unsigned int nr)
{
__raise_softirq_irqoff(nr);
if (!in_interrupt())
wakeup_softirqd();
} //使用ksoftirqd内核线程来处理
static void wakeup_softirqd(void)
{
/* Interrupts are disabled: no need to stop preemption */
struct task_struct *tsk = __this_cpu_read(ksoftirqd);
if (tsk && tsk->state != TASK_RUNNING)
wake_up_process(tsk);
}

Ksoftirqd内核线程:
软中断才被触发频率很高,在处理过程中还会重新触发软中断;执行会导致用户空间进程无法获得处理时间处于饥饿状态;
对重新触发的软中断立即处理,会导致占据处理时间过长;不进行立即处理不合适;
对此解决方法:
l 只要还有被触发并等待处理和过程中重新触发的软中断的软中断,本次执行就要负责处理;软中断立即处理,用户空间得不到执行时间。
l 不处理过程中触发的软中断,放到下一个中断执行时机时处理。软中断得不到立即处理,系统空闲时造成不合理;保证用户空间得到执行时间。
两种方式有存在问题,只能在这其中采取这种的方式:
内核使用线程处理软中断,线程优先级较低,可以被抢占;能够保证软中断被处理,也能保证用户空间程序得到执行时间。
每个CPU上有存在这样一个线程:ksoftirqd/0或者ksoftirqd/1……

static __init int spawn_ksoftirqd(void)
{
void *cpu = (void *)(long)smp_processor_id();
int err = cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu);
……
return 0;
} early_initcall(spawn_ksoftirqd);
static int __cpuinit cpu_callback(struct notifier_block *nfb,
unsigned long action,
void *hcpu)
{
int hotcpu = (unsigned long)hcpu;
struct task_struct *p; switch (action) {
case CPU_UP_PREPARE:
case CPU_UP_PREPARE_FROZEN:
p = kthread_create_on_node(run_ksoftirqd,
hcpu,
cpu_to_node(hotcpu),
"ksoftirqd/%d", hotcpu);
kthread_bind(p, hotcpu);
per_cpu(ksoftirqd, hotcpu) = p;
break;
……
}

四 中断推后执行机制——工作队列
工作队列(work queue)通过内核线程将中断下半部分程序推后执行到线程中执行,工作队列可以创建线程来处理相应任务。
工作队列创建的线程为工作者线程:worker thread;系统提供默认的线程来处理工作者队列。

工作者线程数据结构:

struct workqueue_struct {
unsigned int flags; /* W: WQ_* flags */
union {
struct cpu_workqueue_struct __percpu *pcpu;
struct cpu_workqueue_struct *single;
unsigned long v;
} cpu_wq; /* I: cwq's */
struct list_head list; /* W: list of all workqueues */
……
}

CPU工作队列数据结构:

struct cpu_workqueue_struct {
//每个CPU工作队列信息
struct global_cwq *gcwq;
//每个CPU工作队列
struct workqueue_struct *wq;
……
};

工作数据结构:
struct work_struct {
atomic_long_t data;
struct list_head entry;
work_func_t func;
};
声明工作队列:
静态:
#define DECLARE_WORK(n, f) \
struct work_struct n = __WORK_INITIALIZER(n, f)
动态:
#define INIT_WORK(_work, _func) \
do { \
__INIT_WORK((_work), (_func), 0); \
} while (0)
需要编写工作队列处理函数:
typedef void (*work_func_t)(struct work_struct *work);
调度工作队列:

int schedule_work(struct work_struct *work)
{
return queue_work(system_wq, work);
}
int queue_work(struct workqueue_struct *wq, struct work_struct *work)
{
ret = queue_work_on(get_cpu(), wq, work);
}

唤醒工作者队列线程处理。
执行工作者队列处理程序:

static int worker_thread(void *__worker)
{
do {
struct work_struct *work =
list_first_entry(&gcwq->worklist,
struct work_struct, entry);
process_one_work(worker, work);
} while (keep_working(gcwq)); }

可以创建新的工作者队列和线程来处理。
平衡是个很关键的问题!
(笔记)Linux内核学习(五)之中断推后处理机制的更多相关文章
- (笔记)Linux内核学习(八)之定时器和时间管理
一 内核中的时间观念 内核在硬件的帮助下计算和管理时间.硬件为内核提供一个系统定时器用以计算流逝的时间.系 统定时器以某种频率自行触发,产生时钟中断,进入内核时钟中断处理程序中进行处理. 墙上时间和系 ...
- (笔记)Linux内核学习(九)之内核内存管理方式
一 页 内核把物理页作为内存管理的基本单位:内存管理单元(MMU)把虚拟地址转换为物理 地址,通常以页为单位进行处理.MMU以页大小为单位来管理系统中的也表. 32位系统:页大小4KB 64位系统:页 ...
- (笔记)Linux内核学习(二)之进程
一 进程与线程 进程就是处于执行期的程序,包含了独立地址空间,多个执行线程等资源. 线程是进程中活动的对象,每个线程都拥有独立的程序计数器.进程栈和一组进程寄存器. 内核调度的对象是线程而不是进程.对 ...
- (笔记)Linux内核学习(四)之系统调用
一 用户空间和内核空间 Linux内核将这4G字节虚拟地址空间的空间分为两部分: l 将最高的1G字节(从虚拟地址0xC0000000到0xFFFFFFFF),供内核使用,称为“内核空间”. l ...
- (笔记)Linux内核学习(一)之内核介绍
内核与操作系统: 内核是操作系统的核心部分,包含了系统运行的核心过程,决定系统的性能,操作系统启动内核被装入到RAM中: 操作系统与底层硬件设备交互和为运行应用程序提供执行环境. Linux内核与微内 ...
- (笔记)Linux内核学习(三)之进程调度
进程调度: 在可运行态进程之间分配有限处理器时间资源的内核子系统. 一 调度策略 1 进程类型 I/O消耗型进程:大部分时间用来提交I/O请求或是等待I/O请求,经常处于可运行状态,但运行时间短,等待 ...
- (笔记)Linux内核学习(十)之虚拟文件系统概念
虚拟文件系统 虚拟文件系统:内核子系统VFS,VFS是内核中文件系统的抽象层,为用户空间提供文件系统相关接口: 通过虚拟文件系统,程序可以利用标准Linux文件系统调用在不同的文件系统中进行交互和操作 ...
- (笔记)Linux内核学习(六)之并发和同步概念
一 临界区和竞争条件 临界区:访问和操作共享数据的代码段. 竞争条件:多个执行线程处于同一个临界区中. 处于竞争条件:造成访问的数据或者资源不一致状态: 对资源i的访问:ProcessA和B访问后得到 ...
- (笔记)Linux内核学习(七)之内核同步机制和实现方式
一 原子操作 指令以原子的方式执行——执行过程不被打断. 1 原子整数操作 原子操作函数接收的操作数类型——atomic_t //定义 atomic_t v;//初始化 atomic_t u = AT ...
随机推荐
- RabbitMQ 连接断开处理-自动恢复
Rabbitmq 官方给的NET consumer示例代码如下,但使用过程,会遇到connection断开的问题,一旦断开,这个代码就会报错,如果你的消费者端是这样的代码的话,就会导致消费者挂掉. u ...
- 用c#开发微信(3)基于Senparc.Weixin框架的接收普通消息处理 (源码下载)
本文讲述使用Senparc.Weixin框架来快速处理各种接收的普通消息.这里的消息指的是传统的微信公众平台消息交互,微信用户向公众号发送消息后,公众号回复消息给微信用户.包括以下7种类型: 1 文本 ...
- Http Status 参考
http://tool.oschina.net/commons?type=5 状态码 含义 100 客户端应当继续发送请求.这个临时响应是用来通知客户端它的部分请求已经被服务器接收,且仍未被拒绝.客户 ...
- Fiddler初探
我们知道监视Http和Https请求的工具有多种,例如:HttpWatch,FireBug等.但是今天接触到一种新的工具Fiddler.Fiddler能记录所有客户端和服务器的http和https请求 ...
- PAAS平台的web应用性能测试与分析
引言 为什么我会写这一篇博客,因为最近很多京东云擎jae的用户反应一个问题就是他们部署在jae上面的应用访问很慢,有极少数应用甚至经常出现504超时现象,当然大家首先想到的是jae性能太差,这也是人之 ...
- C#与数据库访问技术总结(十三)之DataReader对象
DataReader对象与数据获取 DataReader对象以“基于连接”的方式来访问数据库. 也就是说,在访问数据库.执行SQL操作时,DataReader要求一直连在数据库上. 这将会给数据库的连 ...
- Atitit.mvc的趋势与未来attilax总结
Atitit.mvc的趋势与未来attilax总结 1. Mvc的分类 (服务端mvc vs客户端mvc)1 2. Mvc的趋势,从服务端mvc正在转向客户端mvc1 2.1. 更加完善的分离..h ...
- 在主方法中定义一个大小为50的一维整型数组,数组i名为x,数组中存放着{1,3,5,…,99}输出这个数组中的所有元素,每输出十个换一行
package hanqi; import java.util.Scanner; public class Test7 { public static void main(String[] args) ...
- 26数据查询的各种小玩法-select 下(必学)-天轰穿sqlserver视频教程
大纲:简单查询-选择数据列,使用字符串,改变列标题,使用数据运算,使用ALL语DISTINCT关键字,使用TOP关键字,排序 优酷超清地址,为了冲优酷的访问量,所以这里只放优酷的地址了,其实其他网站还 ...
- [推荐]Zookeeper大型分布式系统的可靠协调系统知识介绍
[推荐]Zookeeper大型分布式系统的可靠协调系统知识介绍 基于Zookeeper的锁开发手册 http://wenku.baidu.com/view/acbb8fc6102de2bd960588 ...