电商网站开发平台需要多少,百度站长平台网站改版工具,租车网站 模板,网站建设 菜鸟教程中断服务程序一般都是在中断请求关闭的条件下执行的,以避免嵌套而使中断控制复杂化。但是#xff0c;中断是一个随机事件#xff0c;它随时会到来#xff0c;如果关中断的时间太长#xff0c;CPU就不能及时响应其他的中断请求#xff0c;从而造成中断的丢失。因此#xf…中断服务程序一般都是在中断请求关闭的条件下执行的,以避免嵌套而使中断控制复杂化。但是中断是一个随机事件它随时会到来如果关中断的时间太长CPU就不能及时响应其他的中断请求从而造成中断的丢失。因此内核的目标就是尽可能快的处理完中断请求尽其所能把更多的处理向后推迟。例如假设一个数据块已经达到了网线当中断控制器接受到这个中断请求信号时Linux内核只是简单地标志数据到来了然后让处理器恢复到它以前运行的状态其余的处理稍后再进行如把数据移入一个缓冲区接受数据的进程就可以在缓冲区找到数据。因此内核把中断处理分为两部分上半部top half和下半部bottom half上半部就是中断服务程序内核立即执行而下半部就是一些内核函数留着稍后处理。首先一个快速的“上半部”来处理硬件发出的请求它必须在一个新的中断产生之前终止。通常除了在设备和一些内存缓冲区如果你的设备用到了DMA就不止这些之间移动或传送数据确定硬件是否处于健全的状态之外这一部分做的工作很少。下半部运行时是允许中断请求的而上半部运行时是关中断的这是二者之间的主要区别。但是内核到底什时候执行下半部以何种方式组织下半部这就是我们要讨论的下半部实现机制这种机制在内核的演变过程中不断得到改进在以前的内核中这个机制叫做bottom half(简称bh)在2.4以后的版本中有了新的发展和改进改进的目标使下半部可以在多处理机上并行执行并有助于驱动程序的开发者进行驱动程序的开发。下面主要介绍常用的小任务(Tasklet)机制及2.6内核中的工作队列机制。除此之外还简要介绍2.4以前内核中的下半部和任务队列机制。1. 小任务机制 这里的小任务是指对要推迟执行的函数进行组织的一种机制。其数据结构为tasklet_struct每个结构代表一个独立的小任务其定义如下struct tasklet_struct { struct tasklet_struct *next; /*指向链表中的下一个结构*/ unsigned long state; /* 小任务的状态 */ atomic_t count; /* 引用计数器 */ void (*func) (unsigned long); /* 要调用的函数 */ unsigned long data; /* 传递给函数的参数 */ } 结构中的func域就是下半部中要推迟执行的函数 data是它唯一的参数。State域的取值为TASKLET_STATE_SCHED或TASKLET_STATE_RUN。TASKLET_STATE_SCHED表示小任务已被调度正准备投入运行TASKLET_STATE_RUN表示小任务正在运行。TASKLET_STATE_RUN只有在多处理器系统上才使用单处理器系统什么时候都清楚一个小任务是不是正在运行它要么就是当前正在执行的代码要么不是。Count域是小任务的引用计数器。如果它不为0则小任务被禁止不允许执行只有当它为零小任务才被激活并且在被设置为挂起时小任务才能够执行。2. 声明和使用小任务大多数情况下为了控制一个寻常的硬件设备小任务机制是实现下半部的最佳选择。小任务可以动态创建使用方便执行起来也比较快。我们既可以静态地创建小任务也可以动态地创建它。选择那种方式取决于到底是想要对小任务进行直接引用还是一个间接引用。如果准备静态地创建一个小任务也就是对它直接引用使用下面两个宏中的一个DECLARE_TASKLET(name, func, data) DECLARE_TASKLET_DISABLED(name, func, data) 这两个宏都能根据给定的名字静态地创建一个tasklet_struct结构。当该小任务被调度以后给定的函数func会被执行它的参数由data给出。这两个宏之间的区别在于引用计数器的初始值设置不同。第一个宏把创建的小任务的引用计数器设置为0因此该小任务处于激活状态。另一个把引用计数器设置为1所以该小任务处于禁止状态。例如DECLARE_TASKLET(my_tasklet, my_tasklet_handler, dev); 这行代码其实等价于struct tasklet_struct my_tasklet { NULL, 0, ATOMIC_INIT(0),tasklet_handler, dev}; 这样就创建了一个名为my_tasklet的小任务其处理程序为tasklet_handler并且已被激活。当处理程序被调用的时候dev就会被传递给它。3. 编写自己的小任务处理程序小任务处理程序必须符合如下的函数类型void tasklet_handler(unsigned long data) 由于小任务不能睡眠因此不能在小任务中使用信号量或者其它产生阻塞的函数。但是小任务运行时可以响应中断。4. 调度自己的小任务通过调用tasklet_schedule()函数并传递给它相应的tasklt_struct指针该小任务就会被调度以便适当的时候执行tasklet_schedule(my_tasklet); /*把 my_tasklet 标记为挂起 */ 在小任务被调度以后只要有机会它就会尽可能早的运行。在它还没有得到运行机会之前如果一个相同的小任务又被调度了那么它仍然只会运行一次。可以调用tasklet_disable()函数来禁止某个指定的小任务。如果该小任务当前正在执行这个函数会等到它执行完毕再返回。调用tasklet_enable()函数可以激活一个小任务如果希望把以DECLARE_TASKLET_DISABLED创建的小任务激活也得调用这个函数如tasklet_disable(my_tasklet); /* 小任务现在被禁止,这个小任务不能运行 */ tasklet_enable(my_tasklet); /* 小任务现在被激活 */ 也可以调用tasklet_kill()函数从挂起的队列中去掉一个小任务。该函数的参数是一个指向某个小任务的tasklet_struct的长指针。在小任务重新调度它自身的时候从挂起的队列中移去已调度的小任务会很有用。这个函数首先等待该小任务执行完毕然后再将它移去。5. tasklet的简单用法下面是tasklet的一个简单应用, 以模块的形成加载。#include linux/module.h #include linux/init.h #include linux/fs.h #include linux/kdev_t.h #include linux/cdev.h #include linux/kernel.h #include linux/interrupt.h static struct tasklet_struct my_tasklet; static void tasklet_handler (unsigned long data) { printk(KERN_ALERT “tasklet_handler is running.n”); } static int __init test_init(void) { tasklet_init(my_tasklet, tasklet_handler, 0); tasklet_schedule(my_tasklet); return 0; } static void __exit test_exit(void) { tasklet_kill(tasklet); printk(KERN_ALERT “test_exit running.n”); } MODULE_LICENSE(“GPL”); module_init(test_init); module_exit(test_exit); 从这个例子可以看出所谓的小任务机制是为下半部函数的执行提供了一种执行机制也就是说推迟处理的事情是由tasklet_handler实现何时执行经由小任务机制封装后交给内核去处理。