linux驱动中的工作队列

来源:互联网 发布:北京一七网络 编辑:程序博客网 时间:2024/05/29 11:58

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?
  1.    typedef void (*work_func_t)(struct work_struct *work);  
  2.      
  3.    定义中初始化处理函数  
  4.    DECLARE_WORK(n, f);  
  5.     
  6.    #define DECLARE_WORK(n, f)   struct work_struct n = __WORK_INITIALIZER(n, f)  
  7.    #define __WORK_INITIALIZER(n, f) {       \  
  8. .data = WORK_DATA_INIT(0),    \  
  9. .entry  = { &(n).entry, &(n).entry }, \  
  10. .func = (f)                        \  
  11.     }  
  12.   
  13.    先定义中后初始化处理函数  
  14.    struct work_struct   
  15.    INIT_WORK(struct work_struct *work, func_t);  
  16.    #define INIT_WORK(_work, _func)              \  
  17. do {                                                    \  
  18.     __INIT_WORK((_work), (_func), 0);       \  
  19. while (  
       在使用带delay的函数或宏时使用DECLARE_DELAYED_WORK定义和INIT_DELAYED_WORK初始化。

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

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

测试例子         

[cpp] view plain copy
 print?
  1. void myfunc(struct work_struct*ws);  
  2. DECLARE_WORK(mywork,myfunc);                  //定义  
  3.   
  4.   
  5. void myfunc(struct work_struct*ws)  
  6. {  
  7.    printk(KERN_ALERT "myfunc current->pid %d\n",current->pid);  
  8.    ssleep(1);  
  9.    printk(KERN_ALERT "myfunc current->pid %d\n",current->pid);  
  10.    ssleep(1);  
  11.    printk(KERN_ALERT "myfunc current->pid %d\n",current->pid);  
  12.    ssleep(1);  
  13. }  
  14.   
  15. 在加载模块时调用  
  16. schedule_work(&mywork);  
  17. printk(KERN_ALERT "main current->pid  %d\n" ,current->pid);  
测试结果

[plain] view plain copy
 print?
  1. 输出的pid  
  2. main current->pid  2883                                                           
  3. myfunc current->pid 4                                                             
  4. myfunc current->pid 4                                     
  5. myfunc current->pid 4   
  6.   
  7. [root@fontlose module]# ps                                                        
  8.   PID USER       VSZ STAT COMMAND                                                 
  9.     1 root      2108 S    init                                                    
  10.     2 root         0 SW   [ksoftirqd/0]                                           
  11.     3 root         0 SW   [watchdog/0]                                            
  12.     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?
  1. if (!cwq->freezeable)  
  2.      current->flags |= PF_NOFREEZE;  
  3.  set_user_nice(current, -5);  

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


主要函数

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

主要测试代码

[cpp] view plain copy
 print?
  1. void myfunc(struct work_struct*ws);  
  2.   
  3. struct workqueue_struct *wqueue;  
  4. DECLARE_WORK(mywork,myfunc);    
  5.   
  6. void myfunc(struct work_struct*ws)  
  7. {  
  8.    printk(KERN_ALERT "myfunc 1 current->pid %d\n",current->pid);  
  9.    ssleep(1);  
  10.    printk(KERN_ALERT "myfunc 2 current->pid %d\n",current->pid);  
  11.    ssleep(1);  
  12.    printk(KERN_ALERT "myfunc 3 current->pid %d\n",current->pid);  
  13.    ssleep(1);  
  14. }  
  15.   
  16. 在模块加载是执行  
  17.  wqueue=create_workqueue("myqueue");  
  18.  queue_work(wqueue,&mywork);    
  19.  printk(KERN_ALERT "main current->pid  %d\n" ,current->pid);  

测试结果

[cpp] view plain copy
 print?
  1. main current->pid  1010              
  2.                                              
  3. myfunc 1 current->pid 1016                                                        
  4. myfunc 2 current->pid 1016                                
  5. myfunc 3 current->pid 1016     
  6.   
  7. ps  
  8. ....  
  9. 1016 root         0 SW<  [myqueue/0]   
可见函数运行在pid为1016的进程中,ps查看进程名为myqueue/0.
原创粉丝点击