博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux 内核 tasklet 机制和工作队列zz
阅读量:6094 次
发布时间:2019-06-20

本文共 9490 字,大约阅读时间需要 31 分钟。

http://blog.jobbole.com/107110/

1. Tasklet机制分析

上面我们介绍了,linux内核为什么还要引入tasklet机制呢?主要原因是软中断的pending标志位也就32位,一般情况是不随意增加软中断处理的。而且内核也没有提供通用的增加软中断的接口。其次内,软中断处理函数要求可重入,需要考虑到竞争条件比较多,要求比较高的编程技巧。所以内核提供了tasklet这样的一种通用的机制。

其实每次写总结的文章,总是想把细节的东西说明白,所以越写越多。这样做的好处是能真正理解其中的机制。但是,内容太多的一个坏处就是难道记忆,所以,在讲清楚讲详细的同时,我还要把精髓总结出来。Tasklet的特点,也是tasklet的精髓就是:tasklet不能休眠,同一个tasklet不能在两个CPU上同时运行,但是不同tasklet可能在不同CPU上同时运行,则需要注意共享数据的保护。

主要的数据结构

static DEFINE_PER_CPU(struct tasklet_head, tasklet_vec);

static DEFINE_PER_CPU(struct tasklet_head, tasklet_hi_vec);

如何使用tasklet

使用tasklet比较简单,只需要初始化一个tasklet_struct结构体,然后调用tasklet_schedule,就能利用tasklet机制执行初始化的func函数。

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

  tasklet_schedule处理过程也比较简单,就是把tasklet_struct结构体挂到tasklet_vec链表或者挂接到tasklet_hi_vec链表上,并调度软中断TASKLET_SOFTIRQ或者HI_SOFTIRQ

void __tasklet_schedule(struct tasklet_struct *t){    unsigned long flags;local_irq_save(flags);    t->next = NULL;    *__get_cpu_var(tasklet_vec).tail = t;    __get_cpu_var(tasklet_vec).tail = &(t->next);    raise_softirq_irqoff(TASKLET_SOFTIRQ);    local_irq_restore(flags);}EXPORT_SYMBOL(__tasklet_schedule);void __tasklet_hi_schedule(struct tasklet_struct *t){    unsigned long flags;        local_irq_save(flags);    t->next = NULL;    *__get_cpu_var(tasklet_hi_vec).tail = t;    __get_cpu_var(tasklet_hi_vec).tail = &(t->next);    raise_softirq_irqoff(HI_SOFTIRQ);    local_irq_restore(flags);}EXPORT_SYMBOL(__tasklet_hi_schedule);

  

Tasklet执行过程

Tasklet_action在软中断TASKLET_SOFTIRQ被调度到后会被执行,它从tasklet_vec链表中把tasklet_struct结构体都取下来,然后逐个执行。如果t->count的值等于0,说明这个tasklet在调度之后,被disable掉了,所以会将tasklet结构体重新放回到tasklet_vec链表,并重新调度TASKLET_SOFTIRQ软中断,在之后enable这个tasklet之后重新再执行它。

static void tasklet_action(struct softirq_action *a){    struct tasklet_struct *list;local_irq_disable();    list = __get_cpu_var(tasklet_vec).head;    __get_cpu_var(tasklet_vec).head = NULL;    __get_cpu_var(tasklet_vec).tail = &__get_cpu_var(tasklet_vec).head;    local_irq_enable();        while (list)    {        struct tasklet_struct *t = list;                list = list->next;                if (tasklet_trylock(t))        {            if (!atomic_read(&t->count))            {                if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))                    BUG();                t->func(t->data);                tasklet_unlock(t);                continue;            }            tasklet_unlock(t);        }                local_irq_disable();        t->next = NULL;        *__get_cpu_var(tasklet_vec).tail = t;        __get_cpu_var(tasklet_vec).tail = &(t->next);        __raise_softirq_irqoff(TASKLET_SOFTIRQ);        local_irq_enable();    }}

  

2. Linux工作队列

前面已经介绍了tasklet机制,有了tasklet机制为什么还要增加工作队列机制呢?我的理解是由于tasklet机制的限制,变形tasklet中的回调函数有很多的限制,比如不能有休眠的操作等等。而是用工作队列机制,需要处理的函数在进程上下文中调用,休眠操作都是允许的。但是工作队列的实时性不如tasklet,采用工作队列的例程可能不能在短时间内被调用执行。

数据结构说明

首先需要说明的是workqueue_struct和cpu_workqueue_struct这两个数据结构,创建一个工作队列首先需要创建workqueue_struct,然后可以在每个CPU上创建一个cpu_workqueue_struct管理结构体。

转载地址:http://nmwza.baihongyu.com/

你可能感兴趣的文章
java1234 shiro 第0 .1课 缓存
查看>>
CSS字体样式
查看>>
传输层TCP与UDP
查看>>
LAMP的搭建
查看>>
history 详解
查看>>
单节点网络改造实例:宝视通网络改造方案
查看>>
简单线性回归和多项式回归
查看>>
动态图表制作之:定义名称法
查看>>
设计模式之禅-第一篇
查看>>
事件代理
查看>>
绑定live bind click
查看>>
用户价值判断
查看>>
CentOS 7中Samba服务安装和配置
查看>>
我的友情链接
查看>>
【Objective-C】OC中KVO的基本概念和使用方法
查看>>
java.lang.NoSuchMethodError: com.google.common.collect.FluentIterable.append
查看>>
配置IP路由实验汇总
查看>>
从OA到“大OA” 前进的路还有多远?
查看>>
巧用渐变色打造精致移动端APP
查看>>
聊聊原型设计中的团队管理功能
查看>>