linux驱动中的工作队列

xiaoxiao2021-02-28  139

linux 3.18   drivers/rtc

在看linux RTC框架的时候看到初始化的时候 INIT_WOR(&rtc->irqwork , rtc_timer_do_work)

在rtc_set_time   rtc_update_irq  rtc_timer_enqueue中都会schedule_work(&rtc->irqwork)

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

工作队列是一种将工作推后执行的形式,交由一个内核线程去执行在进程上下文执行,其不能访问用户空间。最重要特点的就是工作队列允许重新调度甚至是睡眠。工作队列子系统提供了一个默认的工作者线程来处理这些工作。默认的工作者线程叫做events/n,这里n是处理器的编号,每个处理器对应一个线程,也可以自己创建工作者线程。

       1.工作的定义

[cpp]  view plain  copy  print ?    typedef void (*work_func_t)(struct work_struct *work);            定义中初始化处理函数      DECLARE_WORK(n, f);           #define DECLARE_WORK(n, f)   struct work_struct n = __WORK_INITIALIZER(n, f)      #define __WORK_INITIALIZER(n, f) {       \   .data = WORK_DATA_INIT(0),    \   .entry  = { &(n).entry, &(n).entry }, \   .func = (f)                        \       }         先定义中后初始化处理函数      struct work_struct       INIT_WORK(struct work_struct *work, func_t);      #define INIT_WORK(_work, _func)              \   do {                                                    \       __INIT_WORK((_work), (_func), 0);       \   while (          在使用带delay的函数或宏时使用DECLARE_DELAYED_WORK定义和INIT_DELAYED_WORK初始化。

      2.使用内核提供的共享列队

[cpp]  view plain  copy  print ?      对工作进行调度,即把给定工作的处理函数提交给缺省的工作队列和工作者线程。        int schedule_work(struct work_struct *work);           确保没有工作队列入口在系统中任何地方运行。        void flush_scheduled_work(void);           延时执行一个任务        int schedule_delayed_work(struct delayed_struct *work, unsigned long delay);           从一个工作队列中去除入口;        int cancel_delayed_work(struct delayed_struct *work);    

测试例子         

[cpp]  view plain  copy  print ? void myfunc(struct work_struct*ws);   DECLARE_WORK(mywork,myfunc);                  //定义         void myfunc(struct work_struct*ws)   {      printk(KERN_ALERT "myfunc current->pid %d\n",current->pid);      ssleep(1);      printk(KERN_ALERT "myfunc current->pid %d\n",current->pid);      ssleep(1);      printk(KERN_ALERT "myfunc current->pid %d\n",current->pid);      ssleep(1);   }      在加载模块时调用   schedule_work(&mywork);   printk(KERN_ALERT "main current->pid  %d\n" ,current->pid);   测试结果

[plain]  view plain  copy  print ? 输出的pid   main current->pid  2883                                                            myfunc current->pid 4                                                              myfunc current->pid 4                                      myfunc current->pid 4       [root@fontlose module]# ps                                                           PID USER       VSZ STAT COMMAND                                                      1 root      2108 S    init                                                         2 root         0 SW   [ksoftirqd/0]                                                3 root         0 SW   [watchdog/0]                                                 4 root         0 SW<  [events/0]      myfunc运行在pid为4的进程中,查看pid为4的进程为events/0,使用内核提供的共享列队,列队是保持顺序执行的,做完一个工作才做下一个,如果一个工作内有耗时大的处理如阻塞等待信号或锁,那么后面的工作都不会执行。如果你不喜欢排队或不好意思让别人等太久,那么可以创建自己的工作者线程,所有工作可以加入自己创建的工作列队,列队中的工作运行在创建的工作者线程中。

       3.使用自定义列队 

         创建工作列队使用3个宏 成功后返回workqueue_struct *指针,并创建了工作者线程。三个宏主要区别在后面两个参数singlethread和freezeable,singlethread为0时会为每个cpu上创建一个工作者线程,为1时只在当前运行的cpu上创建一个工作者线程。freezeable会影响内核线程结构体thread_info的PF_NOFREEZE标记  

[cpp]  view plain  copy  print ? if (!cwq->freezeable)        current->flags |= PF_NOFREEZE;    set_user_nice(current, -5);   在线程函数内设置了测试点如下 [cpp]  view plain  copy  print ? if (cwq->freezeable)       try_to_freeze();   如果设置了PF_NOFREEZE这个flag,那么系统挂起时候这个进程不会被挂起。

主要函数

[html]  view plain  copy  print ? #define create_workqueue(name) __create_workqueue((name), 0, 0)                          //多处理器时会为每个cpu创建一个工作者线程                 #define create_freezeable_workqueue(name) __create_workqueue((name), 1, 1)       //只创建一个工作者线程,系统挂起是线程也挂起   #define create_singlethread_workqueue(name) __create_workqueue((name), 1, 0)    //只创建一个工作者线程,系统挂起是线程线程不挂起   以上三个宏调用__create_workqueue函数定义   extern struct workqueue_struct *__create_workqueue(const char *name,int singlethread, int freezeable);      释放创建的工作列队资源   void destroy_workqueue(struct workqueue_struct *wq)      延时调用指定工作列队的工作   queue_delayed_work(struct workqueue_struct *wq,struct delay_struct *work, unsigned long delay)      取消指定工作列队的延时工作   cancel_delayed_work(struct delay_struct *work)      将工作加入工作列队进行调度   queue_work(struct workqueue_struct *wq, struct work_struct *work)      等待列队中的任务全部执行完毕。   void flush_workqueue(struct workqueue_struct *wq);   主要测试代码

[cpp]  view plain  copy  print ? void myfunc(struct work_struct*ws);      struct workqueue_struct *wqueue;   DECLARE_WORK(mywork,myfunc);        void myfunc(struct work_struct*ws)   {      printk(KERN_ALERT "myfunc 1 current->pid %d\n",current->pid);      ssleep(1);      printk(KERN_ALERT "myfunc 2 current->pid %d\n",current->pid);      ssleep(1);      printk(KERN_ALERT "myfunc 3 current->pid %d\n",current->pid);      ssleep(1);   }      在模块加载是执行    wqueue=create_workqueue("myqueue");    queue_work(wqueue,&mywork);      printk(KERN_ALERT "main current->pid  %d\n" ,current->pid);   测试结果

[cpp]  view plain  copy  print ? main current->pid  1010                                                             myfunc 1 current->pid 1016                                                         myfunc 2 current->pid 1016                                 myfunc 3 current->pid 1016         ps   ....   1016 root         0 SW<  [myqueue/0]    可见函数运行在pid为1016的进程中,ps查看进程名为myqueue/0.
转载请注明原文地址: https://www.6miu.com/read-69142.html

最新回复(0)