三种 bottom half的实现方式 softirqs, tasklets, work queue 及之间的比较 ,驱动程序使用tasklet机制

本文详细介绍了Linux内核中的Tasklet机制,包括Tasklet的工作原理、调度机制及其在驱动程序中的应用。并给出了一个简单的Tasklet使用示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

The following mechanisms are available in the kernel to defer work to a bottom half: softirqs, tasklets, and work queues .

 

Softirqs are the basic bottom half mechanism and have strong locking requirements. They are used only by a few performance-sensitive subsystems such as the networking layer, SCSI layer, and kernel timers.

 

Tasklets are built on top of softirqs and are easier to use. It's recommended to use tasklets unless you have crucial scalability or speed requirements.

 

          A primary difference between a softirq and a tasklet is that the former is reentrant whereas the latter isn't. Different instances of a softirq can run simultaneously on different processors, but that is not the case with tasklets.

 

Work queues are a third way to defer work from interrupt handlers. They execute in process context and are allowed to sleep , so they can use drowsy functions such as mutexes.

 

 

 

驱动程序使用tasklet机制

 

      驱动程序在初始化时,通过函数task_init建立一个tasklet,然后调用函数tasklet_schedule将这个tasklet 放在 tasklet_vec链表的头部,并唤醒后台线程ksoftirqd。当后台线程ksoftirqd运行调用__do_softirq时,会执行在中断向量表softirq_vec里中断号TASKLET_SOFTIRQ对应的tasklet_action函数,然后tasklet_action遍历 tasklet_vec链表,调用每个tasklet的函数完成软中断操作。
 
下面对函数tasklet_init和tasklet_schedule分析:
   函数tasklet_init初始化一个tasklet,其参数t是tasklet_struct结构描述的tasklet,参数(*func)是软中断响应函数。
void tasklet_init(struct tasklet_struct *t,
    void (*func)(unsigned long), unsigned long data)
{
 t->next = NULL;
 t->state = 0;
 atomic_set(&t->count, 0);
 t->func = func;
 t->data = data;
}
驱动程序调用函数tasklet_schedule来运行tasklet。
static inline void tasklet_schedule(struct tasklet_struct *t)
{
 if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
  __tasklet_schedule(t);
}
函数__tasklet_schedule得到当前CPU的tasklet_vec链表,并执行TASKLET_SOFTIRQ软中断。
void fastcall __tasklet_schedule(struct tasklet_struct *t)
{
 unsigned long flags;
 local_irq_save(flags);
 t->next = __get_cpu_var(tasklet_vec).list;
 __get_cpu_var(tasklet_vec).list = t;
 raise_softirq_irqoff(TASKLET_SOFTIRQ);
 local_irq_restore(flags);
}
函数raise_softirq_irqoff设置软中断nr为挂起状态,并在没有中断时唤醒线程ksoftirqd。函数raise_softirq_irqoff必须在关中断情况下运行。
inline fastcall void raise_softirq_irqoff(unsigned int nr)
{
 __raise_softirq_irqoff(nr);
 /*
  * If we're in an interrupt or softirq, we're done
  * (this also catches softirq-disabled code). We will
  * actually run the softirq once we return from
  * the irq or softirq.
  *
  * Otherwise we wake up ksoftirqd to make sure we
  * schedule the softirq soon.
  */
 if (!in_interrupt())
  wakeup_softirqd();
}
 
下面是tasklet_struct和softirq_action的定义。
struct tasklet_struct
{
 struct tasklet_struct *next;
 unsigned long state;
 atomic_t count;
 void (*func)(unsigned long);
 unsigned long data;
};
 
struct softirq_action
{
 void (*action)(struct softirq_action *);
 void *data;
};
 
摘录于《Linux内核分析及编程>


http://hi.baidu.com/ryderlee/blog/item/ceeec316e8d1f318962b431a.html
 1.Tasklet 可被hi-schedule和一般schedule,hi-schedule一定比一般shedule早运行;
   2.同一个Tasklet可同时被hi-schedule和一般schedule;
   3.同一个Tasklet若被同时hi-schedule多次,等同于只hi-shedule一次,因为,在tasklet未 运行时,hi-shedule同一tasklet无意义,会冲掉前一个tasklet;
   4.对于一般shedule, 同上。
   5.不同的tasklet不按先后shedule顺序运行,而是并行运行。
 6.Tasklet的运行时间:
         a.若在中断中schedule tasklet, 中断结束后立即运行;
         b.若CPU忙,在不在此次中断后立即运行;
         c.不在中断中shedule tasklet;
         d.有软或硬中断在运行;
         e.从系统调用中返回;(仅当process闲时)
         f.从异常中返回;
         g.调试程序调度。(ksoftirqd运行时,此时CPU闲)
 7.Taskelet的hi-schedule 使用softirq 0, 一般schedule用softirq 30;
 8.Tasklet的运行时间最完在下一次time tick 时。(因为最外层中断一定会运行使能的softirq, 面不在中断中便能或shedule的softirq在下一定中断后一定会被调用。)

  综上: Tasklet 能保证的运行时间是(1000/HZ)ms,一般是10ms。Tasklet在CPU闲或中断后被调用

 

 

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 (&my_ tasklet );
        printk ( KERN_ALERT "test_exit running./n" );
}
MODULE_LICENSE ( "GPL" );   

module_init( test_init );
module_exit ( test_exit );

 

本文来自优快云博客,转载请标明出处:http://blog.youkuaiyun.com/RichardYSteven/archive/2009/08/24/4479236.aspx

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值