国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
使用工作隊列 - qinzhonghello的專欄

使用工作隊列

 

      我們先來看一下默認的events任務隊列,然后再看看創(chuàng)建新的工作者線程。

     1.創(chuàng)建推后的工作

      首先要做的是實際創(chuàng)建一些需要推后完成的工作??梢酝ㄟ^DECLARE_WORK在編譯時靜態(tài)地創(chuàng)建該結構體:

  1. 在<workqueue.h>中
  2. #define DECLARE_WORK(n, f)                  
  3.     struct work_struct n = __WORK_INITIALIZER(n, f)
  4. #define __WORK_INITIALIZER(n, f) {              
  5.     .data = WORK_DATA_INIT(0),              \
  6.         .entry  = { &(n).entry, &(n).entry },           \
  7.     .func = (f),                        \
  8.     }

也可以在運行時通過指針創(chuàng)建一個工作:

  1. #define INIT_WORK(_work, _func)                 
  2.     do {                            \
  3.         (_work)->data = (atomic_long_t) WORK_DATA_INIT(0);  \
  4.         INIT_LIST_HEAD(&(_work)->entry);        \
  5.         PREPARE_WORK((_work), (_func));         \
  6.     } while (0)
  7. /*
  8.  * initialize a work item's function pointer
  9.  */
  10. #define PREPARE_WORK(_work, _func)              
  11.     do {                            \
  12.         (_work)->func = (_func);            \
  13.     } while (0)

2.工作隊列處理函數(shù)

 

       工作隊列對立函數(shù)的原型是:

         void work_handler(void *data)

       這個函數(shù)會由一個工作者線程執(zhí)行,因此,函數(shù)會運行在進程上下文中。默認情況下,運行響應中斷,并且不持有任何鎖。如果需要,函數(shù)可以睡眠。需要注意的是,盡管操作處理函數(shù)運行在進程上下文中,但它不能訪問用戶空間,因為內(nèi)核線程在用戶空間沒有相關的內(nèi)存映射。通常在系統(tǒng)調用發(fā)生時,內(nèi)核會代表用戶空間的進程運行,此時它才能訪問用戶空間,也只有在此時它才會映射用戶空間的內(nèi)存。

 

3.對工作進行調度

 

    要把給定工作的處理函數(shù)提交給默認的events工作線程,只須調用

    schedule_work(&work);

  1. /**
  2.  * schedule_work - put work task in global workqueue
  3.  * @work: job to be done
  4.  *
  5.  * This puts a job in the kernel-global workqueue.
  6.  */
  7. int fastcall schedule_work(struct work_struct *work)
  8. {
  9.     return queue_work(keventd_wq, work);
  10. }
  11. /**
  12.  * queue_work - queue work on a workqueue
  13.  * @wq: workqueue to use
  14.  * @work: work to queue
  15.  *
  16.  * Returns 0 if @work was already on a queue, non-zero otherwise.
  17.  *
  18.  * We queue the work to the CPU it was submitted, but there is no
  19.  * guarantee that it will be processed by that CPU.
  20.  */
  21. int fastcall queue_work(struct workqueue_struct *wq, struct work_struct *work)
  22. {
  23.     int ret = 0, cpu = get_cpu();
  24.     if (!test_and_set_bit(WORK_STRUCT_PENDING, work_data_bits(work))) {
  25.         if (unlikely(is_single_threaded(wq)))
  26.             cpu = singlethread_cpu;
  27.         BUG_ON(!list_empty(&work->entry));
  28.         __queue_work(per_cpu_ptr(wq->cpu_wq, cpu), work);
  29.         ret = 1;
  30.     }
  31.     put_cpu();
  32.     return ret;
  33. }

   

  1. /* Preempt must be disabled. */
  2. static void __queue_work(struct cpu_workqueue_struct *cwq,
  3.              struct work_struct *work)
  4. {
  5.     unsigned long flags;
  6.     spin_lock_irqsave(&cwq->lock, flags);
  7.     set_wq_data(work, cwq);
  8.     list_add_tail(&work->entry, &cwq->worklist);
  9.     cwq->insert_sequence++;
  10.     wake_up(&cwq->more_work);
  11.     spin_unlock_irqrestore(&cwq->lock, flags);
  12. }

    work馬上就會被調度,一旦其所在的處理器上的工作者線程被喚醒,它就會被執(zhí)行。如不希望工作馬上被執(zhí)行,延遲一段時間之后再執(zhí)行,可以調度它在指定的時間執(zhí)行:

    schedule_delayed_work(&work,delay);

  1. /**
  2.  * schedule_delayed_work - put work task in global workqueue after delay
  3.  * @dwork: job to be done
  4.  * @delay: number of jiffies to wait or 0 for immediate execution
  5.  *
  6.  * After waiting for a given time this puts a job in the kernel-global
  7.  * workqueue.
  8.  */
  9. int fastcall schedule_delayed_work(struct delayed_work *dwork,
  10.                     unsigned long delay)
  11. {
  12.     timer_stats_timer_set_start_info(&dwork->timer);
  13.     return queue_delayed_work(keventd_wq, dwork, delay);
  14. }
  15. /**
  16.  * queue_delayed_work - queue work on a workqueue after delay
  17.  * @wq: workqueue to use
  18.  * @dwork: delayable work to queue
  19.  * @delay: number of jiffies to wait before queueing
  20.  *
  21.  * Returns 0 if @work was already on a queue, non-zero otherwise.
  22.  */
  23. int fastcall queue_delayed_work(struct workqueue_struct *wq,
  24.             struct delayed_work *dwork, unsigned long delay)
  25. {
  26.     int ret = 0;
  27.     struct timer_list *timer = &dwork->timer;
  28.     struct work_struct *work = &dwork->work;
  29.     timer_stats_timer_set_start_info(timer);
  30.     if (delay == 0)
  31.         return queue_work(wq, work);
  32.     if (!test_and_set_bit(WORK_STRUCT_PENDING, work_data_bits(work))) {
  33.         BUG_ON(timer_pending(timer));
  34.         BUG_ON(!list_empty(&work->entry));
  35.         /* This stores wq for the moment, for the timer_fn */
  36.         set_wq_data(work, wq);
  37.         timer->expires = jiffies + delay;
  38.         timer->data = (unsigned long)dwork;
  39.         timer->function = delayed_work_timer_fn;
  40.         add_timer(timer);
  41.         ret = 1;
  42.     }
  43.     return ret;
  44. }
  45. struct delayed_work {
  46.     struct work_struct work;
  47.     struct timer_list timer;
  48. };

 

4.刷新操作

 

   排入隊列的工作會在工作者線程下一次被喚醒的時候執(zhí)行。有時,在繼續(xù)下一步工作之前,你必須保證一些操作已經(jīng)執(zhí)行完畢了。這一點對模塊來說很重要,在卸載之前,它就有可能需要調用下面的函數(shù);而在內(nèi)核的其他部分,為了防止競爭條件的出現(xiàn),也可能需要確保不在有待處理的工作。

   出于以上目的,內(nèi)核準備了一個用于刷新指定工作隊列的函數(shù):

    void flush_scheduled_work(void);

  1. void flush_scheduled_work(void)
  2. {
  3.     flush_workqueue(keventd_wq);
  4. }
  5. /**
  6.  * flush_workqueue - ensure that any scheduled work has run to completion.
  7.  * @wq: workqueue to flush
  8.  *
  9.  * Forces execution of the workqueue and blocks until its completion.
  10.  * This is typically used in driver shutdown handlers.
  11.  *
  12.  * This function will sample each workqueue's current insert_sequence number and
  13.  * will sleep until the head sequence is greater than or equal to that.  This
  14.  * means that we sleep until all works which were queued on entry have been
  15.  * handled, but we are not livelocked by new incoming ones.
  16.  *
  17.  * This function used to run the workqueues itself.  Now we just wait for the
  18.  * helper threads to do it.
  19.  */
  20. void fastcall flush_workqueue(struct workqueue_struct *wq)
  21. {
  22.     might_sleep();
  23.     if (is_single_threaded(wq)) {
  24.         /* Always use first cpu's area. */
  25.         flush_cpu_workqueue(per_cpu_ptr(wq->cpu_wq, singlethread_cpu));
  26.     } else {
  27.         int cpu;
  28.         mutex_lock(&workqueue_mutex);
  29.         for_each_online_cpu(cpu)
  30.             flush_cpu_workqueue(per_cpu_ptr(wq->cpu_wq, cpu));
  31.         mutex_unlock(&workqueue_mutex);
  32.     }
  33. }

    函數(shù)會一直等待,直到隊列中所有對象都被執(zhí)行以后才返回。在等待所有待處理的工作執(zhí)行的時候,該函數(shù)會進入休眠狀態(tài),所以只能在進程上下文中使用它。

    注意,該函數(shù)并不取消任何延遲執(zhí)行的工作。就是說,任何通過schedule_delayed_work()調度的工作,如果其延遲時間未結束,它并不會因為調用flush_scheduled_work()而被刷新掉。

      取消延遲執(zhí)行的工作應該調用:

 int cancle_delayed_work(sruct work_struc work);

       這個函數(shù)可以取消任何與work_struct相關的掛起工作。

  1. 在<workqueue.h>中
  2. /*
  3.  * Kill off a pending schedule_delayed_work().  Note that the work callback
  4.  * function may still be running on return from cancel_delayed_work().  Run
  5.  * flush_scheduled_work() to wait on it.
  6.  */
  7. static inline int cancel_delayed_work(struct delayed_work *work)
  8. {
  9.     int ret;
  10.     ret = del_timer_sync(&work->timer);
  11.     if (ret)
  12.         work_release(&work->work);
  13.     return ret;
  14. }
  15. /**
  16.  * work_release - Release a work item under execution
  17.  * @work: The work item to release
  18.  *
  19.  * This is used to release a work item that has been initialised with automatic
  20.  * release mode disabled (WORK_STRUCT_NOAUTOREL is set).  This gives the work
  21.  * function the opportunity to grab auxiliary data from the container of the
  22.  * work_struct before clearing the pending bit as the work_struct may be
  23.  * subject to deallocation the moment the pending bit is cleared.
  24.  *
  25.  * In such a case, this should be called in the work function after it has
  26.  * fetched any data it may require from the containter of the work_struct.
  27.  * After this function has been called, the work_struct may be scheduled for
  28.  * further execution or it may be deallocated unless other precautions are
  29.  * taken.
  30.  *
  31.  * This should also be used to release a delayed work item.
  32.  */
  33. #define work_release(work) 
  34.     clear_bit(WORK_STRUCT_PENDING, work_data_bits(work))

5.創(chuàng)建新的工作隊列

 

         如果默認的隊列不能滿足需要,可以創(chuàng)建一個新的工作對列和與之相應的工作者線程。

         創(chuàng)建一個新的任務隊列和與之相關的工作者線程,只須調用一個簡單的函數(shù):

         struct workqueue_struct *create_workqueue(const char *name);

  1. 在<workqueue.h>中
  2. #define create_workqueue(name) __create_workqueue((name), 0, 0)
  3. 在<workqueue.c>中
  4. struct workqueue_struct *__create_workqueue(const char *name,
  5.                         int singlethread, int freezeable)
  6. {
  7.     int cpu, destroy = 0;
  8.     struct workqueue_struct *wq;
  9.     struct task_struct *p;
  10.     wq = kzalloc(sizeof(*wq), GFP_KERNEL);
  11.     if (!wq)
  12.         return NULL;
  13.     wq->cpu_wq = alloc_percpu(struct cpu_workqueue_struct);
  14.     if (!wq->cpu_wq) {
  15.         kfree(wq);
  16.         return NULL;
  17.     }
  18.     wq->name = name;
  19.     mutex_lock(&workqueue_mutex);
  20.     if (singlethread) {
  21.         INIT_LIST_HEAD(&wq->list);
  22.         p = create_workqueue_thread(wq, singlethread_cpu, freezeable);
  23.         if (!p)
  24.             destroy = 1;
  25.         else
  26.             wake_up_process(p);
  27.     } else {
  28.         list_add(&wq->list, &workqueues);
  29.         for_each_online_cpu(cpu) {
  30.             p = create_workqueue_thread(wq, cpu, freezeable);
  31.             if (p) {
  32.                 kthread_bind(p, cpu);
  33.                 wake_up_process(p);
  34.             } else
  35.                 destroy = 1;
  36.         }
  37.     }
  38.     mutex_unlock(&workqueue_mutex);
  39.     /*
  40.      * Was there any error during startup? If yes then clean up:
  41.      */
  42.     if (destroy) {
  43.         destroy_workqueue(wq);
  44.         wq = NULL;
  45.     }
  46.     return wq;
  47. }

     這個函數(shù)會創(chuàng)建所有的工作者線程(系統(tǒng)中的每個處理器都有一個),并且做好所有開始處理工作之前的準備工作。

     創(chuàng)建一個工作的時候無須考慮工作隊列的類型??梢允褂孟铝泻瘮?shù)對給定工作而不是默認的event隊列進行操作。

int queue_work(struct workqueue_struct *wq, struct work_struct*work);

int queue_delayed_work(struct workqueue_struct *wq, structwork_struct *work, unsigned long delay);

flush_workqueue(struct workqueue_struct *wq);

  1. /**
  2.  * queue_work - queue work on a workqueue
  3.  * @wq: workqueue to use
  4.  * @work: work to queue
  5.  *
  6.  * Returns 0 if @work was already on a queue, non-zero otherwise.
  7.  *
  8.  * We queue the work to the CPU it was submitted, but there is no
  9.  * guarantee that it will be processed by that CPU.
  10.  */
  11. int fastcall queue_work(struct workqueue_struct *wq, struct work_struct *work)
  12. {
  13.     int ret = 0, cpu = get_cpu();
  14.     if (!test_and_set_bit(WORK_STRUCT_PENDING, work_data_bits(work))) {
  15.         if (unlikely(is_single_threaded(wq)))
  16.             cpu = singlethread_cpu;
  17.         BUG_ON(!list_empty(&work->entry));
  18.         __queue_work(per_cpu_ptr(wq->cpu_wq, cpu), work);
  19.         ret = 1;
  20.     }
  21.     put_cpu();
  22.     return ret;
  23. }
  24. /**
  25.  * queue_delayed_work - queue work on a workqueue after delay
  26.  * @wq: workqueue to use
  27.  * @dwork: delayable work to queue
  28.  * @delay: number of jiffies to wait before queueing
  29.  *
  30.  * Returns 0 if @work was already on a queue, non-zero otherwise.
  31.  */
  32. int fastcall queue_delayed_work(struct workqueue_struct *wq,
  33.             struct delayed_work *dwork, unsigned long delay)
  34. {
  35.     int ret = 0;
  36.     struct timer_list *timer = &dwork->timer;
  37.     struct work_struct *work = &dwork->work;
  38.     timer_stats_timer_set_start_info(timer);
  39.     if (delay == 0)
  40.         return queue_work(wq, work);
  41.     if (!test_and_set_bit(WORK_STRUCT_PENDING, work_data_bits(work))) {
  42.         BUG_ON(timer_pending(timer));
  43.         BUG_ON(!list_empty(&work->entry));
  44.         /* This stores wq for the moment, for the timer_fn */
  45.         set_wq_data(work, wq);
  46.         timer->expires = jiffies + delay;
  47.         timer->data = (unsigned long)dwork;
  48.         timer->function = delayed_work_timer_fn;
  49.         add_timer(timer);
  50.         ret = 1;
  51.     }
  52.     return ret;
  53. }
  54. /**
  55.  * flush_workqueue - ensure that any scheduled work has run to completion.
  56.  * @wq: workqueue to flush
  57.  *
  58.  * Forces execution of the workqueue and blocks until its completion.
  59.  * This is typically used in driver shutdown handlers.
  60.  *
  61.  * This function will sample each workqueue's current insert_sequence number and
  62.  * will sleep until the head sequence is greater than or equal to that.  This
  63.  * means that we sleep until all works which were queued on entry have been
  64.  * handled, but we are not livelocked by new incoming ones.
  65.  *
  66.  * This function used to run the workqueues itself.  Now we just wait for the
  67.  * helper threads to do it.
  68.  */
  69. void fastcall flush_workqueue(struct workqueue_struct *wq)
  70. {
  71.     might_sleep();
  72.     if (is_single_threaded(wq)) {
  73.         /* Always use first cpu's area. */
  74.         flush_cpu_workqueue(per_cpu_ptr(wq->cpu_wq, singlethread_cpu));
  75.     } else {
  76.         int cpu;
  77.         mutex_lock(&workqueue_mutex);
  78.         for_each_online_cpu(cpu)
  79.             flush_cpu_workqueue(per_cpu_ptr(wq->cpu_wq, cpu));
  80.         mutex_unlock(&workqueue_mutex);
  81.     }
  82. }
  1. static void flush_cpu_workqueue(struct cpu_workqueue_struct *cwq)
  2. {
  3.     if (cwq->thread == current) {
  4.         /*
  5.          * Probably keventd trying to flush its own queue. So simply run
  6.          * it by hand rather than deadlocking.
  7.          */
  8.         run_workqueue(cwq);
  9.     } else {
  10.         DEFINE_WAIT(wait);
  11.         long sequence_needed;
  12.         spin_lock_irq(&cwq->lock);
  13.         sequence_needed = cwq->insert_sequence;
  14.         while (sequence_needed - cwq->remove_sequence > 0) {
  15.             prepare_to_wait(&cwq->work_done, &wait,
  16.                     TASK_UNINTERRUPTIBLE);
  17.             spin_unlock_irq(&cwq->lock);
  18.             schedule();
  19.             spin_lock_irq(&cwq->lock);
  20.         }
  21.         finish_wait(&cwq->work_done, &wait);
  22.         spin_unlock_irq(&cwq->lock);
  23.     }
  24. }
  1. static void run_workqueue(struct cpu_workqueue_struct *cwq)
  2. {
  3.     unsigned long flags;
  4.     /*
  5.      * Keep taking off work from the queue until
  6.      * done.
  7.      */
  8.     spin_lock_irqsave(&cwq->lock, flags);
  9.     cwq->run_depth++;
  10.     if (cwq->run_depth > 3) {
  11.         /* morton gets to eat his hat */
  12.         printk("%s: recursion depth exceeded: %d\n",
  13.             __FUNCTION__, cwq->run_depth);
  14.         dump_stack();
  15.     }
  16.     while (!list_empty(&cwq->worklist)) {
  17.         struct work_struct *work = list_entry(cwq->worklist.next,
  18.                         struct work_struct, entry);
  19.         work_func_t f = work->func;
  20.         list_del_init(cwq->worklist.next);
  21.         spin_unlock_irqrestore(&cwq->lock, flags);
  22.         BUG_ON(get_wq_data(work) != cwq);
  23.         if (!test_bit(WORK_STRUCT_NOAUTOREL, work_data_bits(work)))
  24.             work_release(work);
  25.         f(work);
  26.         if (unlikely(in_atomic() || lockdep_depth(current) > 0)) {
  27.             printk(KERN_ERR "BUG: workqueue leaked lock or atomic: "
  28.                     "%s/0x%08x/%d\n",
  29.                     current->comm, preempt_count(),
  30.                         current->pid);
  31.             printk(KERN_ERR "    last function: ");
  32.             print_symbol("%s\n", (unsigned long)f);
  33.             debug_show_held_locks(current);
  34.             dump_stack();
  35.         }
  36.         spin_lock_irqsave(&cwq->lock, flags);
  37.         cwq->remove_sequence++;
  38.         wake_up(&cwq->work_done);
  39.     }
  40.     cwq->run_depth--;
  41.     spin_unlock_irqrestore(&cwq->lock, flags);
  42. }
本站僅提供存儲服務,所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Linux工作隊列實現(xiàn)機制
Linux kernel 中的work queue原理
工作隊列(workqueue)
linux內(nèi)核分析筆記------上半部與下半部(下)
workqueue
linux 內(nèi)核work工作隊列實現(xiàn)
更多類似文章 >>
生活服務
分享 收藏 導長圖 關注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服