当前位置: 首页 > news >正文

自己买个服务器做网站杭州企业云网站建设

自己买个服务器做网站,杭州企业云网站建设,下载asp网站,泉州网站建设 推广返回目录#xff1a;《ARM-Linux中断系统》。 总结#xff1a; 二介绍了tasklet存在的意义。 三介绍了通过tasklet_struct来抽想一个tasklet#xff0c;每个CPU维护一个tasklet链表tasklet_vec/tasklet_hi_vec#xff0c;然后介绍了如何定一个一个tasklet(静态/动态)#…返回目录《ARM-Linux中断系统》。 总结 二介绍了tasklet存在的意义。 三介绍了通过tasklet_struct来抽想一个tasklet每个CPU维护一个tasklet链表tasklet_vec/tasklet_hi_vec然后介绍了如何定一个一个tasklet(静态/动态)以及如何调度一个tasklet什么时候tasklet回调函数会被执行。 原文地址《linux kernel的中断子系统之九tasklet》   一、前言 对于中断处理而言linux将其分成了两个部分一个叫做中断handlertop half属于不那么紧急需要处理的事情被推迟执行我们称之deferable task或者叫做bottom half。具体如何推迟执行分成下面几种情况 1、推迟到top half执行完毕 2、推迟到某个指定的时间片例如40ms之后执行 3、推迟到某个内核线程被调度的时候执行 对于第一种情况内核中的机制包括softirq机制和tasklet机制。第二种情况是属于softirq机制的一种应用场景timer类型的softirq在本站的时间子系统的系列文档中会描述。第三种情况主要包括threaded irq handler以及通用的workqueue机制当然也包括自己创建该驱动专属kernel thread不推荐使用。本文主要描述tasklet这种机制第二章描述一些背景知识和和tasklet的思考第三章结合代码描述tasklet的原理。 注本文中的linux kernel的版本是4.0 二、为什么需要tasklet 1、基本的思考 我们的驱动程序或者内核模块真的需要tasklet吗每个人都有自己的看法。我们先抛开linux kernel中的机制首先进行一番逻辑思考。 将中断处理分成top halfcpu和外设之间的交互获取状态ack状态收发数据等和bottom half后段的数据处理已经深入人心对于任何的OS都一样将不那么紧急的事情推迟到bottom half中执行是OK的具体如何推迟执行分成两种类型有具体时间要求的对应linux kernel中的低精度timer和高精度timer和没有具体时间要求的。对于没有具体时间要求的又可以分成两种 1越快越好型这种实际上是有性能要求的除了中断top half可以抢占其执行其他的进程上下文无论该进程的优先级多么的高是不会影响其执行的一言以蔽之在不影响中断延迟的情况下OS会尽快处理。 2随遇而安型。这种属于那种没有性能需求的其调度执行依赖系统的调度器。 本质上讲越快越好型的bottom half不应该太多而且tasklet的callback函数不能执行时间过长否则会产生进程调度延迟过大的现象甚至是非常长而且不确定的延迟对real time的系统会产生很坏的影响。 2、对linux中的bottom half机制的思考 在linux kernel中“越快越好型”有两种softirq和tasklet“随遇而安型”也有两种workqueue和threaded irq handler。“越快越好型”能否只留下一个softirq呢对于崇尚简单就是美的程序员当然希望如此。为了回答这个问题我们先看看tasklet对于softirq而言有哪些好处 1tasklet可以动态分配也可以静态分配数量不限。 2同一种tasklet在多个cpu上也不会并行执行这使得程序员在撰写tasklet function的时候比较方便减少了对并发的考虑当然损失了性能。 对于第一种好处其实也就是为乱用tasklet打开了方便之门很多撰写驱动的软件工程师不会仔细考量其driver是否有性能需求就直接使用了tasklet机制。对于第二种好处本身考虑并发就是软件工程师的职责。因此看起来tasklet并没有引入特别的好处而且和softirq一样都不能sleep限制了handler撰写的方便性看起来其实并没有存在的必要。在4.0 kernel的代码中grep一下tasklet的使用实际上是一个很长的列表只要对这些使用进行简单的归类就可以删除对tasklet的使用。对于那些有性能需求的可以考虑并入softirq其他的可以考虑使用workqueue来取代。Steven Rostedt试图进行这方面的尝试http://lwn.net/Articles/239484/不过这个patch始终未能进入main line。 三、tasklet的基本原理 1、如何抽象一个tasklet 内核中用下面的数据结构来表示tasklet struct tasklet_struct{    struct tasklet_struct *next;    unsigned long state;    atomic_t count;    void (*func)(unsigned long);    unsigned long data;}; 每个cpu都会维护一个链表将本cpu需要处理的tasklet管理起来next这个成员指向了该链表中的下一个tasklet。func和data成员描述了该tasklet的callback函数func是调用函数data是传递给func的参数。state成员表示该tasklet的状态TASKLET_STATE_SCHED表示该tasklet以及被调度到某个CPU上执行TASKLET_STATE_RUN表示该tasklet正在某个cpu上执行。count成员是和enable或者disable该tasklet的状态相关如果count等于0那么该tasklet是处于enable的如果大于0表示该tasklet是disable的。在softirq文档中我们知道local_bh_disable/enable函数就是用来disable/enable bottom half的这里就包括softirq和tasklet。但是有的时候内核同步的场景不需disable所有的softirq和tasklet而仅仅是disable该tasklet这时候tasklet_disable和tasklet_enable就派上用场了。 static inline void tasklet_disable(struct tasklet_struct *t){    tasklet_disable_nosync(t);给tasklet的count加一    tasklet_unlock_wait(t);如果该tasklet处于running状态那么需要等到该tasklet执行完毕    smp_mb();} static inline void tasklet_enable(struct tasklet_struct *t){    smp_mb__before_atomic();    atomic_dec(t-count);给tasklet的count减一} tasklet_disable和tasklet_enable支持嵌套但是需要成对使用。 2、系统如何管理tasklet 系统中的每个cpu都会维护一个tasklet的链表定义如下 static DEFINE_PER_CPU(struct tasklet_head, tasklet_vec);static DEFINE_PER_CPU(struct tasklet_head, tasklet_hi_vec); linux kernel中和tasklet相关的softirq有两项HI_SOFTIRQ用于高优先级的taskletTASKLET_SOFTIRQ用于普通的tasklet。对于softirq而言优先级就是出现在softirq pending register__softirq_pending中的先后顺序位于bit 0拥有最高的优先级也就是说如果有多个不同类型的softirq同时触发那么执行的先后顺序依赖在softirq pending register的位置kernel总是从右向左依次判断是否置位如果置位则执行。HI_SOFTIRQ占据了bit 0其优先级甚至高过timer需要慎用实际上我grep了内核代码似乎没有发现对HI_SOFTIRQ的使用。当然HI_SOFTIRQ和TASKLET_SOFTIRQ的机理是一样的因此本文只讨论TASKLET_SOFTIRQ大家可以举一反三。 3、如何定义一个tasklet 你可以用下面的宏定义来静态定义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 } 这两个宏都可以静态定义一个struct tasklet_struct的变量只不过初始化后的tasklet一个是处于eable状态一个处于disable状态的。当然也可以动态分配tasklet然后调用tasklet_init来初始化该tasklet。 4、如何调度一个tasklet 为了调度一个tasklet执行我们可以使用tasklet_schedule这个接口 static inline void tasklet_schedule(struct tasklet_struct *t){    if (!test_and_set_bit(TASKLET_STATE_SCHED, t-state))        __tasklet_schedule(t);} 程序在多个上下文中可以多次调度同一个tasklet执行也可能来自多个cpu core不过实际上该tasklet只会一次挂入首次调度到的那个cpu的tasklet链表也就是说即便是多次调用tasklet_schedule实际上tasklet只会挂入一个指定CPU的tasklet队列中而且只会挂入一次也就是说只会调度一次执行。这是通过TASKLET_STATE_SCHED这个flag来完成的我们可以用下面的图片来描述 我们假设HW block A的驱动使用的tasklet机制并且在中断handlertop half中将静态定义的tasklet这个tasklet是各个cpu共享的不是per cpu的调度执行也就是调用tasklet_schedule函数。当HW block A检测到硬件的动作例如接收FIFO中数据达到半满就会触发IRQ line上的电平或者边缘信号GIC检测到该信号会将该中断分发给某个CPU执行其top half handler我们假设这次是cpu0因此该driver的tasklet被挂入CPU0对应的tasklet链表tasklet_vec并将state的状态设定为TASKLET_STATE_SCHED。HW block A的驱动中的tasklet虽已调度但是没有执行如果这时候硬件又一次触发中断并在cpu1上执行虽然tasklet_schedule函数被再次调用但是由于TASKLET_STATE_SCHED已经设定因此不会将HW block A的驱动中的这个tasklet挂入cpu1的tasklet链表中。 下面我们再仔细研究一下底层的__tasklet_schedule函数 void __tasklet_schedule(struct tasklet_struct *t){    unsigned long flags;     local_irq_save(flags);1    t-next NULL;2    *__this_cpu_read(tasklet_vec.tail) t;    __this_cpu_write(tasklet_vec.tail, (t-next));    raise_softirq_irqoff(TASKLET_SOFTIRQ);3    local_irq_restore(flags);} 1下面的链表操作是per-cpu的因此这里禁止本地中断就可以拦截所有的并发。 2这里的三行代码就是将一个tasklet挂入链表的尾部 3raise TASKLET_SOFTIRQ类型的softirq。 5、在什么时机会执行tasklet 上面描述了tasklet的调度当然调度tasklet不等于执行tasklet系统会在适合的时间点执行tasklet callback function。由于tasklet是基于softirq的因此我们首先总结一下softirq的执行场景 1在中断返回用户空间进程上下文的时候如果有pending的softirq那么将执行该softirq的处理函数。这里限定了中断返回用户空间也就是意味着限制了下面两个场景的softirq被触发执行     a中断返回hard interrupt context也就是中断嵌套的场景     b中断返回software interrupt context也就是中断抢占软中断上下文的场景 2上面的描述缺少了一种场景中断返回内核态的进程上下文的场景这里我们需要详细说明。进程上下文中调用local_bh_enable的时候如果有pending的softirq那么将执行该softirq的处理函数。由于内核同步的要求进程上下文中有可能会调用local_bh_enable/disable来保护临界区。在临界区代码执行过程中中断随时会到来抢占该进程内核态的执行注意这里只是disable了bottom half没有禁止中断。在这种情况下中断返回的时候是否会执行softirq handler呢当然不会我们disable了bottom half的执行也就是意味着不能执行softirq handler但是本质上bottom half应该比进程上下文有更高的优先级一旦条件允许要立刻抢占进程上下文的执行因此当立刻离开临界区调用local_bh_enable的时候会检查softirq pending如果bottom half处于enable的状态pending的softirq handler会被执行。 3系统太繁忙了不过的产生中断raise softirq由于bottom half的优先级高从而导致进程无法调度执行。这种情况下softirq会推迟到softirqd这个内核线程中去执行。 对于TASKLET_SOFTIRQ类型的softirq其handler是tasklet_action我们来看看各个tasklet是如何执行的 static void tasklet_action(struct softirq_action *a){    struct tasklet_struct *list;     local_irq_disable();1    list __this_cpu_read(tasklet_vec.head);    __this_cpu_write(tasklet_vec.head, NULL);    __this_cpu_write(tasklet_vec.tail, this_cpu_ptr(tasklet_vec.head));    local_irq_enable();     while (list) {遍历tasklet链表        struct tasklet_struct *t list;         list list-next;         if (tasklet_trylock(t)) {2            if (!atomic_read(t-count)) {3                if (!test_and_clear_bit(TASKLET_STATE_SCHED, t-state))                    BUG();                t-func(t-data);                tasklet_unlock(t);                continue;处理下一个tasklet            }            tasklet_unlock(t);清除TASKLET_STATE_RUN标记        }         local_irq_disable();4        t-next NULL;        *__this_cpu_read(tasklet_vec.tail) t;        __this_cpu_write(tasklet_vec.tail, (t-next));        __raise_softirq_irqoff(TASKLET_SOFTIRQ); 再次触发softirq等待下一个执行时机        local_irq_enable();    }} 1从本cpu的tasklet链表中取出全部的tasklet保存在list这个临时变量中同时重新初始化本cpu的tasklet链表使该链表为空。由于bottom half是开中断执行的因此在操作tasklet链表的时候需要使用关中断保护 2tasklet_trylock主要是用来设定该tasklet的state为TASKLET_STATE_RUN同时判断该tasklet是否已经处于执行状态这个状态很重要它决定了后续的代码逻辑。 static inline int tasklet_trylock(struct tasklet_struct *t){    return !test_and_set_bit(TASKLET_STATE_RUN, (t)-state);} 你也许会奇怪为何这里从tasklet的链表中摘下一个本cpu要处理的tasklet list而这个list中的tasklet已经处于running状态了会有这种情况吗会的我们再次回到上面的那个软硬件结构图。同样的HW block A的驱动使用的tasklet机制并且在中断handlertop half中将静态定义的tasklet 调度执行。HW block A的硬件中断首先送达cpu0处理因此该driver的tasklet被挂入CPU0对应的tasklet链表并在适当的时间点上开始执行该tasklet。这时候cpu0的硬件中断又来了该driver的tasklet callback function被抢占虽然tasklet仍然处于running状态。与此同时HW block A硬件又一次触发中断并在cpu1上执行这时候该driver的tasklet处于running状态并且TASKLET_STATE_SCHED已经被清除因此调用tasklet_schedule函数将会使得该driver的tasklet挂入cpu1的tasklet链表中。由于cpu0在处理其他硬件中断因此cpu1的tasklet后发先至进入tasklet_action函数调用这时候当从cpu1的tasklet摘取所有需要处理的tasklet链表中HW block A对应的tasklet实际上已经是在cpu0上处于执行状态了。 我们在设计tasklet的时候就规定同一种类型的tasklet只能在一个cpu上执行因此tasklet_trylock就是起这个作用的。 3检查该tasklet是否处于enable状态如果是说明该tasklet可以真正进入执行状态了。主要的动作就是清除TASKLET_STATE_SCHED状态执行tasklet callback function。 4如果该tasklet已经在别的cpu上执行了那么我们将其挂入该cpu的tasklet链表的尾部这样在下一个tasklet执行时机到来的时候kernel会再次尝试执行该tasklet在这个时间点也许其他cpu上的该tasklet已经执行完毕了。通过这样代码逻辑保证了特定的tasklet只会在一个cpu上执行不会在多个cpu上并发。 原创文章转发请注明出处。蜗窝科技转载于:https://www.cnblogs.com/arnoldlu/p/7599602.html
http://www.zqtcl.cn/news/452325/

相关文章:

  • 网站域名做跳转要收费吗科技信息期刊
  • 登别的网站应怎么做网站推广广告词大全集
  • 漯河城乡建设管理局网站wordpress icon class
  • 买空间哪个网站好广州多少网络科技有限公司
  • 网站的网络推广方案营销型网站建设论文
  • 苏州做网站便宜的公司哪家好门店管理系统app
  • 学校多语言网站建设网络维护网站建设培训
  • Wordpress外贸网站搭建公司建站系统的应用场景
  • 网站推广网络推广方wordpress汉语公益
  • 长沙做网站的公司有哪些宁波奉化建设局网站
  • 温岭专业自适应网站建设承德招聘信息网
  • 做公司网站的模板下载wordpress e
  • 网站建设基本知识wordpress 没有小工具
  • 北京完美建设有限公司网站酒店加盟
  • 山东网络推广网站德州市建设局质监站网站
  • api模式网站开发网站打开后显示建设中
  • 排名好的郑州网站建设免费营销培训
  • 美橙互联网站网站主要应用
  • 淘宝客网站做appuv推广平台
  • 网站公司可以做英文网吗图片加字制作免费
  • 海口个人建站模板精品课程云网站建设
  • 阿里网站空间莱芜新闻视频回放
  • 高清网站建设的好处wordpress 房产模板
  • 在建工程查询网站怎么自己开发网站
  • 旧电脑怎么做网站如何自己弄个免费网站
  • 聊城网站营销WordPress工作发布
  • 建造网站需要什么汽车网站建设
  • 网站建设app郑州发布评论
  • 福州网站制作建设网页设计图片是怎么显示的
  • 天津通用网站建设收费网站建设怎么在png上写文字