linux驱动下半部之tasklet

        linux将中断分为两部分:上部分和下半部(顶半部和底半部);上半部完成紧急但能很快完成的事情,下半部完成不紧急但比较耗时的操作;        

1. struct tasklet_struct结构体 

struct tasklet_struct
{
	struct tasklet_struct *next; //构成链表的指针
	unsigned long state;    //该tasklet被调度的状态(被调度还是已经执行)
	atomic_t count;         //用于禁止tasklet执行(非0时)
	void (*func)(unsigned long);//下半部函数
	unsigned long data;         //传递给下半部函数的参数
};

         要实现tasklet中断下半部,就要构造一个struct tasklet_struct结构对象,并初始化里面的成员;然后放入对应的cpu的tasklet链表;最后设置软中断号TASKLET_SOFTIRQ所对应的比特位;

2. 初始化

#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 }

 上面DECLARE_TASKLET宏定义一个struct tasklet_struct对象,名字为name,下半部函数为func,传递的参数是data; 该tasklet可以被执行(因为count值被设置为0)

DECLARE_TASKLET_DISABLED宏与DECLARE_TASKLET仅仅是count被设置为1,故不能被执行; 需要调用tasklet_enable函数使能;

除了上面的宏,tasklet_init也可以实现对struct tasklet_struct结构体对象的初始化;

void tasklet_init(struct tasklet_struct *t,void (*func)(unsigned long), unsigned long data) 

 源码:

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;
}

3. tasklet_schedule函数

将tasklet_struct对象加入到内核的tasklet链表中; 

void tasklet_schedule(struct tasklet_struct *t);

源码:

static inline void tasklet_schedule(struct tasklet_struct *t)
{
    //测试该tasklet_struct对象是否被调度状态,没有则设置并加入调度队列;
	if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
		__tasklet_schedule(t);
}

4. 简单示例:

#if 1
static void jit_tasklet_fn(unsigned long arg); //前向声明
DECLARE_TASKLET(tlet,jit_tasklet_fn,(unsigned long)&xxx);
#else
static struct tasklet_struct tlet;
#endif

static void jit_tasklet_fn(unsigned long arg)
{
	printk("in jit_tasklet_fn  jiffies=%ld\n",jiffies);
}

//中断函数
static irqreturn_t my_handler(int irq, void *dev_id)
{
    tasklet_schedule(&tlet);

    return IRQ_HANDLED;
}

{
    #if 0
    tasklet_init(&tlet, jit_tasklet_fn, (unsigned long)&xxx);
    #endif

    ...
}

上面两种不同的初始化方式: 

static void jit_tasklet_fn(unsigned long arg); //前向声明
DECLARE_TASKLET(tlet,jit_tasklet_fn,(unsigned long)&xxx); 参数3为指针,大多指定某个结构体对象地址或NULL;

 static struct tasklet_struct tlet;

 tasklet_init(&tlet, jit_tasklet_fn, (unsigned long)&xxx);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天未及海宽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值