7.5Tasklets机制

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/shenwanjiang111/article/details/81711290

7.5 Tasklet


关于时间,内核另外一个有力工具就是tasklet机制。它主要用于中断管理。

Tasklet在某些方面与内核定时器类似。它们总是在中断时运行,总是运行在调度它们的CPU上,且能够接受unsigned long类型的参数。又不像内核定时器,不能要求在特定时间执行该功能。通过调度tasklet,你可以让内核选择在稍后的时间执行它。这种行为对于中断处理程序非常有用,硬件中断必须尽可能快的处理,但是数据处理可以延迟后安全地进行。事实上,tasklet,就像内核定时器一样,在“软中断”的上下文中被执行(原子模式),这是内核在使能硬件中断的情况下执行异步任务的一种机制。

tasklet的数据结构如下所示,在使用之前必须被初始化。声明可以使用下面的函数或宏。

#include <linux/interrupt.h>
struct tasklet_struct {
    /* ... */
    void (*func)(unsigned long);
    unsigned long data;
};

void tasklet_init(struct tasklet_struct *t, void (*func)(unsigned long), unsigned long data);
DECLARE_TASKLET(name, func, data);
DECLARE_TASKLET_DISABLED(name, func, data);

Tasklet提供了许多有趣的功能:

  • tasklet可以禁用和使能;
  • 就像计时器一样,tasklet可以重新注册自己;
  • tasklet可以以正常优先级或高优先级调度运行。后来的组总是先执行。
  • 如果系统负荷不是很重,tasklet可以立即执行,但是不迟于下一个定时器嘀嗒;
  • tasklet可以并发执行,但是同一个tasklet只能在一个处理器上运行且运行在调度它的CPU之上。

jit模块包含2个文件,/proc/jitasklet/proc/jitasklethi,其返回与/proc/jitimer相同的数据。数据内容如下:

phon% cat /proc/jitasklet
 time delta inirq pid cpu command
 6076139 0 0 4370 0 cat
 6076140 1 1 4368 0 cc1
 6076141 1 1 4368 0 cc1
 6076141 0 1 2 0 ksoftirqd/0
 6076141 0 1 2 0 ksoftirqd/0
 6076141 0 1 2 0 ksoftirqd/0

第1行数据描述了调用进程的内容,其它行描述了运行tasklet程序的内容。

上面的数据证实,当CPU正在运行一个进程的时候,tasklet会在下一个定时器嘀嗒运行;否则,当CPU处于空闲时,它会立即运行。内核提供了一组ksoftirqd内核线程,每个CPU一个,只是为了运行“软中断”处理程序,例如tasklet_action函数。因此,上面最后三个tasklet发生在ksoftirqd内核线程里,其运行在CPU 0上。jitasklethi的实现,使用了高优先级的tasklet。下面的函数列表会有介绍。

jit模块里, /proc/jitasklet/proc/jitasklethi的实现与/proc/jitimer几乎一样。前两个使用的是tasklet调用,后一个使用的timer相关调用。下面的列表就是tasklet相关接口:

  • void tasklet_disable(struct tasklet_struct *t);

    禁止给定的tasklet。仍可以使用tasklet_schedule调度tasklet,但是会延迟执行,直到再次使能tasklet为止。如果tasklet当前正在运行,则此函数将等待,直到tasklet退出; 因此,在调用tasklet_disable之后,您可以确保tasklet没有在系统中的任何位置运行。

  • void tasklet_disable_nosync(struct tasklet_struct *t);

    禁用tasklet,但不等待任何当前正在运行的函数退出。当它返回时,tasklet被禁用,并且在重新使能之前不会被调度,但是,它可以在另一个CPU上运行。

  • void tasklet_enable(struct tasklet_struct *t);

    启用先前禁止的tasklet。与tasklet_disable函数成对使用。

  • void tasklet_schedule(struct tasklet_struct *t);

    调度tasklet执行。如果tasklet运行之前被调度,只运行一次;如果在运行中被调度,则运行完成后再执行一次。这可确保在处理其它事件时,刚发生的时间能够得到应有的处理。这种行为还允许tasklet重新调度自己。

  • void tasklet_hi_schedule(struct tasklet_struct *t);

    安排tasklet以更高的优先级执行。 当软中断处理程序运行时,它会在其它软中断任务(包括“普通”tasklet)之前处理高优先级的tasklet。 理想情况下,只有具有低延迟要求的任务(例如填充音频缓冲区)才应使用此功能,以避免其它软中断处理程序引入的额外延迟。 实际上,/proc/jitasklethi/proc/jitasklet之间表现的差异我们是很难看出来的。

  • void tasklet_kill(struct tasklet_struct *t);

    “杀死”tasklet,保证不会再次运行;通常会在设备被关闭或模块被移除时调用。如果已经运行,则该函数等待直到tasklet完成执行。在调用该函数之前不能再重新调度自己。

tasklet相关的实现位于kernel/softirq.c中。两个tasklet列表(普通和高优先级)在每个CPU上都会声明, 这点与内核定时器相同。在tasklet中使用的数据结构是一个单链表,因为它没有内核定时器所需要的排序要求。

猜你喜欢

转载自blog.csdn.net/shenwanjiang111/article/details/81711290
7.5