In 2.6.x, there are 3 mechanisms for implementing a bottom half: softirqs, tasklets and work queues. Here's the comparison:


Softirqs:

  Softirqs are statically allocated at compile time. It is represented by the softirq_action structure, which is defined in <linux/interrupt.h>:

struct softirq_action {
void (*action)(struct softirq_action *);
}

  A 32-entry array of this structure is declared in kernel/softirq.c:

static struct softirq_action softirq_vec[NR_SOFTIRQS];

  But in the current kernel, only nine exist:(as we will discuss later, tasklets are built off softirqs)

  The prototype of a softirq handler looks like

void softirq_handler(struct softirq_action *)

  A softirq never preempts another softirq. The only event that can preempt a softirq is an interrupt handler.

Executing Softirqs:

  A registered softirq must be marked before it will execute. This is called raising the softirq.

  Softirq execution occurs in __do_softirq(), which is invoked by do_softirq(). If there are pending softirqs, __do_softirq() loops over each one, invoking its handler. Let's look at a simplified variant of the important part of __do_softirq():

u32 pending;

pending = local_softirq_pending();
if (pending) {
struct softirq_action *h; /* reset the pending bitmask */
set_softirq_pending(); h = softirq_vec;
do {
if (pending & )
h->action(h);
h++;
pending >>= ;
} while (pending);
}

Using Softirqs:

  Softirqs are reserved for the most timing-critical and important bottom-half processing on the system.  Currently, only two subsystems - networking and block devices - directly use softirqs.

  Registering Your Handler:

  The softirq handler is registered at run-time via open_softirq():

/* in net/core/dev.c */
/* two parameters: the sfotirq's index and its handler function */
open_softirq(NET_TX_SOFTIRQ, net_tx_action);

  Raising Your Softirq:

  To mark it pending, call raise_softirq():    

raise_softirq(NET_TX_SOFTIRQ);

  Then it is run at the next invocation of do_softirq().

asmlinkage void do_softirq(void)
{
__u32 pending;
unsigned long flags; if (in_interrupt())
return; local_irq_save(flags); pending = local_softirq_pending(); if (pending)
__do_softirq(); local_irq_restore(flags);
}

  I have a look at __do_softirq() and I think it's too long to show here, so I just pass it :)

  In general, pending softirqs are checked for and executed in the following places:

    In the return from hardware interrupt code path;

    In the ksoftirqd kernel thread;

    In any code that explicitly checks for and executes pending softirqs, such as the networking subsystem.


Tasklets:

  Tasklets are built on top of softirqs and it's more popular. The difference is that two of the same type of tasklet cannot run simultaneously on different processors but softirqs can.

  As discussed, tasklets are represented by two softirqs: HI_SOFTIRQ and TASKLET_SOFTIRQ.

  The tasklet sturcture is declared in <linux/interrupt.h>:

struct tasklet_struct {
struct tasklet_struct *next;
unsigned long state;
atomic_t count;
void (*func)(unsigned long); /* tasklet handler function */
unsigned long data; /* argument to the tasklet function */
};

Schedulling Tasklets:

  Tasklets are scheduled via the tasklet_schedule() and tasklet_hi_schedule()(for high-priority tasklets):

static inline vid tasklet_schedule(struct tasklet_struct *t)
{
if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
__tasklet_schedule(t);
}

  Here's the __tasklet_schedule():

void __tasklet_schedule(struct tasklet_struct *t)
{
unsigned long flags; /* save the state of interrupt system, and then disable local interrupts. */
local_irq_save(flags);
t->next = NULL;
/* add the tasklet to be scheduled to the tail of the tasklet_vec linked list */
*__get_cpu_var(tasklet_vec).tail = t;
__get_cpu_var(tasklet-vec).tail = &(t->next);
/* raise the TASKLET_SOFTIRQ, so do_softirq() executes this tasklet in the near future */
local_irq_restore(flags);
}

  Then the do_softirq() will execute the associated handlers tasklet_action() soon.  

 ksoftirqd:

  Softirq (and thus tasklet) processing is aided by a set of per-processor kernel threads. The kernel processes softirqs most commonly on return from handling an interrupt.

  There is one thread per processor. The threads are each named ksoftirqd/n where n is the processor number.


Work Queue:

  Work queues defer work into a kernel thread - this bottom half always runs in process context. Therefore, work queues are schedulable and can therefore sleep.

  In its most basic form, the work queue subsystem is an interface fro creating kernel threads, which are called worker threads, to handle work queued from elsewhere.

  The default worker threads are called events/n where n is the processor number.

LKD: Chapter 8 Bottom Halves and Deferring Work的更多相关文章

  1. LKD: Chapter 7 Interrupts and Interrupt Handlers

    Recently I realized my English is still far from good. So in order to improve my English, I must not ...

  2. LKD: Chapter 9 An Introduction to Kernel Synchronization

    This chapter introduces some conception about kernel synchronization generally. Critical Regions: Co ...

  3. LKD: Chapter 6 Kernel Data Structures

    这一章我们研究四种主要的数据结构: linked lists, queues, maps, binary trees. Linked Lists:(<linux/list.h>) 在lin ...

  4. LKD: Chapter 5 System Call

    在Linux中,处理器所作的事可以归纳为3种情况: 1.In user-space, executing user code in a process; 2.In kernel-space, in p ...

  5. linux内核申请内存函数

    kmap函数:    把某块高端内存映射到页表,然后返回给用户一个填好vitual字段的page结构    建立永久地址映射,不是简单的返回virtual字段的pageioremap:    驱动程序 ...

  6. kernel笔记——中断

    cpu与磁盘.网卡.键盘等外围设备(相对于cpu和内存而言)交互时,cpu下发I/O请求到这些设备后,相对cpu的处理能力而言,磁盘.网卡等设备需要较长时间完成请求处理. 那么在请求发出到处理完成这段 ...

  7. linux工作队列

    工作队列一般用来做滞后的工作,比如在中断里面要做很多事,但是比较耗时,这时就可以把耗时的工作放到工作队列.说白了就是系统延时调度的一个自定义函数. 工作队列是实现延迟的新机制,从 2.5 版本 Lin ...

  8. 软中断与硬中断 & 中断抢占 中断嵌套

    参考了这篇文章:http://blog.csdn.net/zhangskd/article/details/21992933 从本质上来讲,中断是一种电信号,当设备有某种事件发生时,它就会产生中断,通 ...

  9. 专家解读Linux操作系统内核中的GCC特性

    专家解读Linux操作系统内核中的GCC特性   Linux内核使用GNU Compiler Collection (GCC)套件的几个特殊功能.这些功能包括提供快捷方式和简化以及向编译器提供优化提示 ...

随机推荐

  1. 部署LAMP+NFS实现双Web服务器负载均衡

    一.需求分析 1.前端需支持更大的访问量,单台Web服务器已无法满足需求了,则需扩容Web服务器: 2.虽然动态内容可交由后端的PHP服务器执行,但静态页面还需要Web服务器自己解析,那是否意味着多台 ...

  2. C#高级编程第9版 阅读笔记(一)

    一.前言 C# 简洁.类型安全的面向对象的语言. .NET是一种在windows平台上编程的架构——一种API. C#是一种从头开始设计的用于.NET的语言,他可以利用.NET Framework及其 ...

  3. Scrapy架构及其组件之间的交互

    最近在学Python,同时也在学如何使用python抓取数据,于是就被我发现了这个非常受欢迎的Python抓取框架Scrapy,下面一起学习下Scrapy的架构,便于更好的使用这个工具. 一.概述 下 ...

  4. C语言第一次实验报告————PTA实验1.2.3内容

    一.PTA实验作业 题目1.温度转换 本题要求编写程序,计算华氏温度100°F对应的摄氏温度.计算公式:C=5×(F−32)/9,式中:C表示摄氏温度,F表示华氏温度,输出数据要求为整型. 1.实验代 ...

  5. JavaScript之“创意时钟”项目

    “时钟展示项目”说明文档(文档尾部附有相应代码) 一.最终效果展示: 二.项目亮点 1.代码结构清晰明了 2.可以实时动态显示当前时间与当前日期 3.界面简洁.美观.大方 4.提高浏览器兼容性 三.知 ...

  6. (转)java的动态代理机制详解

    原文出自:http://www.cnblogs.com/xiaoluo501395377/p/3383130.html 在学习Spring的时候,我们知道Spring主要有两大思想,一个是IoC,另一 ...

  7. Git相关操作四

    1.克隆远程仓库 git clone remote_location clone_name remote_location为仓库地址,clone_name为要克隆到本地的仓库名称. 2.显示对应克隆地 ...

  8. LeetCode 598. Range Addition II (范围加法之二)

    Given an m * n matrix M initialized with all 0's and several update operations. Operations are repre ...

  9. 【Telerik控件学习】-制作3D效果的柱状图(ChartView)

    首先,定义柱状图,并设置自定义的DataTemplate <telerik:RadCartesianChart > <telerik:RadCartesianChart.Horizo ...

  10. .6-Vue源码之AST(2)

    上一节获取到了DOM树的字符串,准备进入compile阶段: // Line-9326 function compileToFunctions(template,options,vm) { // 获取 ...