老版本的 Linux 内核尽了很大努力来区分"快速"和"慢速"中断. 快速中断是那些能够很 快处理的, 而处理慢速中断要特别地长一些. 慢速中断可能十分苛求处理器, 并且它值得 在处理的时候重新使能中断. 否则, 需要快速注意的任务可能被延时太长.

在现代内核中, 快速和慢速中断的大部分不同已经消失. 剩下的仅仅是一个: 快速中断 (那些使用 SA_INTERRUPT 被请求的)执行时禁止所有在当前处理器上的其他中断. 注意其 他的处理器仍然能够处理中断, 尽管你从不会看到 2 个处理器同时处理同一个 IRQ.

这样, 你的驱动应当使用哪个类型的中断? 在现代系统上, SA_INTERRUPT 只是打算用在 几个, 特殊的情况例如时钟中断. 除非你有一个充足的理由来运行你的中断处理在禁止其 他中断情况下, 你不应当使用 SA_INTERRUPT.

这个描述应当满足大部分读者, 尽管有人喜好硬件并且对她的计算机有经验可能有兴趣深 入一些. 如果你不关心内部的细节, 你可跳到下一节.

这个描述是从
arch/i386/kernel/irq.c, arch/i386/kernel/ apic.c, arch/i386/kernel/entry.S,
arch/i386/kernel/i8259.c, 和 include/asm- i386/hw_irq.h 它们出现于 2.6 内核而推知的; 尽管一般的概念保持一致,
硬件细节在 其他平台上不同.

中断处理的最低级是在 entry.S, 一个汇编语言文件处理很多机器级别的工作. 通过一点 汇编器的技巧和一些宏定义, 一点代码被安排到每个可能的中断. 在每个情况下, 这个代 码将中断号压栈并且跳转到一个通用段, 称为 do_IRQ, 在 irq.c 中定义.

do_IRQ 做的第一件事是确认中断以便中断控制器能够继续其他事情.
它接着获取给定 IRQ 号的一个自旋锁, 因此阻止任何其他 CPU 处理这个 IRQ. 它清除几个状态位(包括称 为 IRQ_WAITING 的一个, 我们很快会看到它)并且接着查看这个特殊 IRQ 的处理者. 如

果没有处理者, 什么不作; 自旋锁释放, 任何挂起的软件中断被处理, 最后 do_IRQ
返回.

常常, 但是, 如果一个设备在中断, 至少也有一个处理者注册给它的 IRQ. 函数 handle_IRQ_event 被调用来实际调用处理者. 如果处理者是慢速的( SA_INTERRUPT 没有 设置 ), 中断在硬件中被重新使能, 并且调用处理者. 接着仅仅是清理, 运行软件中断, 以及回到正常的工作. "常规工作"很可能已经由于中断而改变了(处理者可能唤醒一个进 程, 例如), 因此从中断中返回的最后的事情是一个处理器的可能的重新调度.

探测 IRQ 通过设置 IRQ_WAITING 状态位给每个当前缺乏处理者的 IRQ 来完成. 当中断 发生,
do_IRQ 清除这个位并且接着返回, 因为没有注册处理者. probe_irq_off, 当被一 个函数调用, 需要只搜索不再有 IRQ_WAITING 设置的
IRQ.

实现一个处理

 

至今, 我们已学习了注册一个中断处理, 但是没有编写一个. 实际上, 对于一个处理者, 没什么不寻常的 -- 它是普通的 C
代码.

唯一的特别之处是一个处理者在中断时运行, 因此, 它能做的事情遭受一些限制. 这些限 制与我们在内核定时器上看到的相同. 一个处理者不能传递数据到或者从用户空间, 因为 它不在进程上下文执行. 处理者也不能做任何可能睡眠的事情, 例如调用 wait_event, 使用除 GFP_ATOMIC 之外任何东西来分配内存, 或者加锁一个旗标. 最后, 处理者不能调
用调度.

一个中断处理的角色是给它的设备关于中断接收的回应并且读或写数据, 根据被服务的中 断的含义. 第一步常常包括清除接口板上的一位; 大部分硬件设备不产生别的中断直到它 们的"中断挂起"位被清除. 根据你的硬件如何工作的, 这一步可能需要在最后做而不是开 始; 这里没有通吃的规则. 一些设备不需要这步, 因为它们没有一个"中断挂起"位; 这样
的设备是一少数, 尽管并口是其中之一. 由于这个理由, short 不必清除这样一个位.

一个中断处理的典型任务是唤醒睡眠在设备上的进程, 如果中断指示它们在等待的事件, 例如新数据的到达.

为坚持帧抓取者的例子, 一个进程可能请求一个图像序列通过连续读设备; 读调用阻塞在 读取每个帧之前, 而中断处理唤醒进程一旦每个新帧到达. 这个假定抓取器中断处理器来 指示每个新帧的成功到达.

程序员应当小心编写一个函数在最小量的时间内执行, 不管是一个快速或慢速处理者. 如 果需要进行长时间计算, 最好的方法是使用一个 tasklet 或者 workqueue 来调度计算在 一个更安全的时间(我们将在"上和下半部"一节中见到工作如何被延迟.).

我们在 short 中的例子代码响应中断通过调用 do_gettimeofday 和 打印当前时间到一 个页大小的环形缓存. 它接着唤醒任何读进程, 因为现在有数据可用来读取.

irqreturn_t
short_interrupt(int irq, void *dev_id, struct pt_regs *regs)

{

struct
timeval tv; int written; do_gettimeofday(&tv);

/*
Write a 16 byte record. Assume PAGE_SIZE is a multiple of 16 */ written =
sprintf((char *)short_head,"%08u.%06u\n",

(int)(tv.tv_sec % 100000000), (int)(tv.tv_usec));
BUG_ON(written != 16);

short_incr_bp(&short_head,
written);

wake_up_interruptible(&short_queue);
/* awake any reading process */ return IRQ_HANDLED;

}

这个代码, 尽管简单, 代表了一个中断处理的典型工作. 依次地, 它称为 short_incr_bp, 定义如下:

static
inline void short_incr_bp(volatile unsigned long *index, int delta)

{

unsigned
long new = *index + delta;

barrier();  /*
Don't optimize these two together */

*index
= (new >= (short_buffer + PAGE_SIZE)) ? short_buffer : new;

}

这个函数已经仔细编写来回卷指向环形缓存的指针, 没有暴露一个不正确的值. 这里的 barrier 调用来阻止编译器在这个函数的其他 2 行之间优化. 如果没有
barrier, 编译 器可能决定优化掉 new 变量并且直接赋值给 *index. 这个优化可能暴露一个 index 的 不正确值一段时间, 在它回卷的地方. 通过小心阻止对其他线程可见的不一致的值, 我们 能够安全操作环形缓存指针而不用锁.

用来读取中断时填充的缓存的设备文件是 /dev/shortint. 这个设备特殊文件, 同

/dev/shortprint 一起, 不在第 9 章介绍, 因为它的使用对中断处理是特殊的.

/dev/shortint 内部特别地为中断产生和报告剪裁过. 写到设备会每隔一个字节产生一个
中断; 读取设备给出了每个中断被报告的时间.

如果你连接并口连接器的管脚 9 和 10, 你可产生中断通过拉高并口数据字节的高位. 这 可通过写二进制数据到 /dev/short0 或者通过写任何东西到 /dev/shortint 来完成.

[38]下列代码为 /dev/shortint 实现读和写:

ssize_t
short_i_read (struct file *filp, char  
user *buf, size_t count,

loff_t
*f_pos)

{

int count0; DEFINE_WAIT(wait);

while
(short_head == short_tail)

{

prepare_to_wait(&short_queue,
&wait, TASK_INTERRUPTIBLE); if (short_head == short_tail)

schedule(); finish_wait(&short_queue,
&wait);

if
(signal_pending (current)) /* a signal arrived */

return
-ERESTARTSYS; /* tell the fs layer to handle it */

} /* count0 is the number of readable data bytes */
count0 = short_head - short_tail;

if
(count0 < 0) /* wrapped */

count0 = short_buffer + PAGE_SIZE - short_tail; if
(count0 < count)

count
= count0;

if (copy_to_user(buf, (char *)short_tail, count))
return -EFAULT;

short_incr_bp
(&short_tail, count); return count;

}

ssize_t
short_i_write (struct file *filp, const char  
user *buf, size_t count, loff_t *f_pos)

{

int
written = 0, odd = *f_pos & 1;

unsigned
long port = short_base; /* output to the parallel data latch */ void *address =
(void *) short_base;

if
(use_mem)

{

}

else

{

}

while
(written < count)

iowrite8(0xff
* ((++written + odd) & 1), address);

while
(written < count)

outb(0xff
* ((++written + odd) & 1), port);

*f_pos
+= count; return written;

}

其他设备特殊文件, /dev/shortprint, 使用并口来驱动一个打印机; 你可用使用它, 如 果你想避免连接一个 D-25 连接器管脚 9 和 10. shortprint 的写实现使用一个环形缓 存来存储要打印的数据, 而写实现是刚刚展示的那个(因此你能够读取你的打印机吃进每 个字符用的时间).

为了支持打印机操作, 中断处理从刚刚展示的那个已经稍微修改, 增加了发送下一个数据 字节到打印机的能力, 如果没有更多数据传送.

linux 快速和慢速处理的更多相关文章

  1. Linux下 网卡测速

    参考: How do I verify the speed of my NIC? Linux下 网卡测速 命令: $ sudo ethtool eth0 Settings for eth0: Supp ...

  2. linux快速复制大量小文件方法 nc+tar【转】

    1,在需要对大量小文件进行移动或复制时,用cp.mv都会显得很没有效率,可以用tar先压缩再解压缩的方式.  2,在网络环境中传输时,可以再结合nc命令,通过管道和tcp端口进行传输.  nc和tar ...

  3. Linux 快速删除大量小文件方法

    进行以下两步操作即可: 1.第一步:创建空的文件夹: mkdir  /tmp/blank 2.第二步:执行以下命令:rsync --delete-before -d /tmp/blank/ /home ...

  4. Linux快速入门教程-进程管理ipcs命令学习

    使用Linux系统必备的技能之一就是Linux进程管理,系统运行的过程正是无数进程在运行的过程.这些进程的运行需要占用系统的内存等资源,做好系统进程的管理,对于我们合理分配.使用系统资源有非常大的意义 ...

  5. Linux快速入门打开你的学习之道

    Linux快速入门打开你的学习之道 相信看到这篇文章的你一定是想要学习Linux,或者已经在学习Linux的人了,那我们就可以一起探讨一下,学习Linux如何快速入门呢? 首先,希望大家弄清楚自己为什 ...

  6. 【Git】2、Linux快速安装Git环境 & oh-my-zsh

    Linux快速安装Git环境 文章目录 Linux快速安装Git环境 1.Linux安装Git 2.安装zsh 3.安装oh-my-zsh 3.1.安装oh-my-zsh 3.2. 测试验证 4.小结 ...

  7. Linux之:Ubuntu速学笔记(1)

    撰写日期:2016-7-2 17:11:28 Saturday 课程资源:  web程序员角度ubuntu自修速学课程 链接来源:程序员在囧途, VMware: VMware Workstation1 ...

  8. Linux快速上手

    1.Linux系统架构 内核(kernel) 内存管理(mm) Linux内存特性无论物理内存有多大,Linux 都将其充份利用,将一些程序调用过的硬盘数据读入内存,利用内存读写的高速特性来提高Lin ...

  9. Linux快速配置集群ssh互信

    之前在<记录一则Linux SSH的互信配置过程>.<Vertica 7.1安装最佳实践(RHEL6.4)>中,都分别提到了配置ssh互信的方法,本文在此基础上进一步整理配置s ...

随机推荐

  1. 纯CSS3个性化圆形按钮登录表单

    在线演示 本地下载

  2. No PostCSS Config found解决办法

    npm install报错 Module build failed: Error: No PostCSS Config found 解决办法是同级package.json文件新建postcss.con ...

  3. 提取网址的python练习

    import urllib, urllib2, cookielib from HTMLParser import HTMLParser import sys reload(sys) sys.setde ...

  4. LeetCode153 Find Minimum in Rotated Sorted Array. LeetCode162 Find Peak Element

    二分法相关 153. Find Minimum in Rotated Sorted Array Suppose a sorted array is rotated at some pivot unkn ...

  5. 两张图说明http协议,tcp协议,ip协议,dns服务之间的关系和区别

    一.理解一个传输流再去扩展 用http举例来说,首先作为发送端的客户端在应用层(http协议)发出一个想看某个web页面的http请求. 接着,为了传输方便,在传输层(tcp协议)把从应用层处收到的数 ...

  6. QT开发ROS遇到问题:execute_process(/usr/bin/python"/home/fu/catkin_ws/build/catkin_genetated/generate_cached_setup.py)..........

    具体如上图显示,网上给的方法是重装ros和重新创建ROS工作空间.经过这样做以后发现问题依然存在. 最后考虑可能是没有加载ROS的环境变量.(我的qtcreator中已经有了创建ros工程的项目,但是 ...

  7. 64位Linux编译C代码,crt1.o文件格式不对的问题

    今天在某台64位LInux下编译一个简单的hello world的C程序,报错: /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../crt1.o: cou ...

  8. Lambda plus: 云上大数据解决方案

    本文会简述大数据分析场景需要解决的技术挑战,讨论目前主流大数据架构模式及其发展.最后我们将介绍如何结合云上存储.计算组件,实现更优的通用大数据架构模式,以及该模式可以涵盖的典型数据处理场景. 大数据处 ...

  9. hdu 1839 Delay Constrained Maximum Capacity Path(spfa+二分)

    Delay Constrained Maximum Capacity Path Time Limit: 10000/10000 MS (Java/Others)    Memory Limit: 65 ...

  10. HDU - 6534 Chika and Friendly Pairs

    这个题其实也是很简单的莫队,题目要求是给一个序列,询问l-r区间内部,找到有多少对答案满足 i < j 并且 | a[ i ] -a[ j ] | <=k 也就是有多少对,满足差值小于k的 ...