• linux驱动下半部之tasklet


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

    1. struct tasklet_struct结构体 

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

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

    2. 初始化

    1. #define DECLARE_TASKLET(name, func, data) \
    2. struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data }
    3. #define DECLARE_TASKLET_DISABLED(name, func, data) \
    4. 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) 

     源码:

    1. void tasklet_init(struct tasklet_struct *t,
    2. void (*func)(unsigned long), unsigned long data)
    3. {
    4. t->next = NULL;
    5. t->state = 0;
    6. atomic_set(&t->count, 0);
    7. t->func = func;
    8. t->data = data;
    9. }

    3. tasklet_schedule函数

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

    void tasklet_schedule(struct tasklet_struct *t);

    源码:

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

    4. 简单示例:

    1. #if 1
    2. static void jit_tasklet_fn(unsigned long arg); //前向声明
    3. DECLARE_TASKLET(tlet,jit_tasklet_fn,(unsigned long)&xxx);
    4. #else
    5. static struct tasklet_struct tlet;
    6. #endif
    7. static void jit_tasklet_fn(unsigned long arg)
    8. {
    9. printk("in jit_tasklet_fn jiffies=%ld\n",jiffies);
    10. }
    11. //中断函数
    12. static irqreturn_t my_handler(int irq, void *dev_id)
    13. {
    14. tasklet_schedule(&tlet);
    15. return IRQ_HANDLED;
    16. }
    17. {
    18. #if 0
    19. tasklet_init(&tlet, jit_tasklet_fn, (unsigned long)&xxx);
    20. #endif
    21. ...
    22. }

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

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

  • 相关阅读:
    【三维目标检测】CenterPoint(一)
    Dynamic Head: Unifying Object Detection Heads with Attentions
    视频实现输入密码才能观看的应用效果
    Fitness diary Privacy Policy
    SpringBoot+Vue2项目解决前后端跨域方案
    bp神经网络的主要功能,一文搞定bp神经网络
    Android退出应用后是否需要关闭数据库?
    HTML5+CSS3+JS小实例:使用L2Dwidget实现二次元卡通看板娘
    关于mybatisplus报错:Property ‘sqlSessionFactory‘ or ‘sqlSessionTemplat的问题
    树和二叉树
  • 原文地址:https://blog.csdn.net/qq_39048131/article/details/126187218