tasklet、wait_queue、completion、work_queue用法總結

來源:互聯網
上載者:User

標籤:kernel   tasklet   work_queue   wait_queue   completion   

對於核心中常用的中斷處理機製做一些總結,方便在合適的時候採用合適的機制。

 

tasklet 和 work_queue 是延期執行工作的機制,實現基於非強制中斷;completion的實現基於wait_queue。

——————————————————————————————————————————————————————————————————————————————————————————————————————————————
tasklet

小進程,主要用於執行一些小任務,對這些任務使用全功能進程比較浪費。也稱為中斷下半部,在處理非強制中斷時執行。

definition:

struct tasklet_struct{        struct tasklet_struct *next;        unsigned long state;        atomic_t count;        void (*func)(unsigned long);        unsigned long data;};


相關定義:

 

#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 }enum{        TASKLET_STATE_SCHED,    /* Tasklet is scheduled for execution */        TASKLET_STATE_RUN       /* Tasklet is running (SMP only) */};


初始化及銷毀tasklet的方法:

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;}void tasklet_kill(struct tasklet_struct *t){        if (in_interrupt())                printk("Attempt to kill tasklet from interrupt\n");        while (test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) {                do {                        yield();                } while (test_bit(TASKLET_STATE_SCHED, &t->state));        }        tasklet_unlock_wait(t);        clear_bit(TASKLET_STATE_SCHED, &t->state);}


調度tasklet的方法:

 

static inline void tasklet_schedule(struct tasklet_struct *t){        if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))                __tasklet_schedule(t);}void __tasklet_schedule(struct tasklet_struct *t){        unsigned long flags;        local_irq_save(flags);        t->next = NULL;        *__this_cpu_read(tasklet_vec.tail) = t;        __this_cpu_write(tasklet_vec.tail, &(t->next));        raise_softirq_irqoff(TASKLET_SOFTIRQ);        local_irq_restore(flags);}


 

使用方法:
tasklet_init->tasklet_schedule

——————————————————————————————————————————————————————————————————————————————————————————————————————————————
wait_queue


用於使進程等待某一事件的發生,無須頻繁輪訊,進程在等待期間睡眠,在事件發生時由核心自動喚醒。

用法1(add_wait_queue 和 wake_up組合):
當nand控制器被一個進程使用時,其餘進程被放入等待隊列;待第一個進程使用結束後,調用wake_up喚醒等待隊列,下一個進程獲得nand控制器的使用權。

 

#define DECLARE_WAITQUEUE(name, tsk)                                            wait_queue_t name = __WAITQUEUE_INITIALIZER(name, tsk)#define __WAITQUEUE_INITIALIZER(name, tsk) {                                    .private        = tsk,                                                  .func           = default_wake_function,                                .task_list      = { NULL, NULL } }        void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait){        unsigned long flags;        wait->flags &= ~WQ_FLAG_EXCLUSIVE;        spin_lock_irqsave(&q->lock, flags);        __add_wait_queue(q, wait);        spin_unlock_irqrestore(&q->lock, flags);}<nand_base.c>static int nand_test_get_device(struct mtd_info *mtd, int new_state){        struct nand_chip *chip = mtd->priv;        spinlock_t *lock = &chip->controller->lock;        wait_queue_head_t *wq = &chip->controller->wq;        DECLARE_WAITQUEUE(wait, current);retry:        spin_lock(lock);        /* Hardware controller shared among independent devices */        if (!chip->controller->active)                chip->controller->active = chip;        if (chip->controller->active == chip && chip->state == FL_READY) {                chip->state = new_state;                spin_unlock(lock);                return 0;        }            if (new_state == FL_PM_SUSPENDED) {                if (chip->controller->active->state == FL_PM_SUSPENDED) {                        chip->state = FL_PM_SUSPENDED;                        spin_unlock(lock);                        return 0;                }            }            set_current_state(TASK_UNINTERRUPTIBLE);        add_wait_queue(wq, &wait);        spin_unlock(lock);        schedule();        remove_wait_queue(wq, &wait);        goto retry;}static void nand_test_release_device(struct mtd_info *mtd){        struct nand_chip *chip = mtd->priv;        /* Release the controller and the chip */        spin_lock(&chip->controller->lock);        chip->controller->active = NULL;        chip->state = FL_READY;        wake_up(&chip->controller->wq);        spin_unlock(&chip->controller->lock);}


 

 

方法2(prepare_to_wait 和 wake_up組合),可作為實現阻塞的方式:

 

#define DEFINE_WAIT_FUNC(name, function)                                        wait_queue_t name = {                                                           .private        = current,                                              .func           = function,                                             .task_list      = LIST_HEAD_INIT((name).task_list),             }#define DEFINE_WAIT(name) DEFINE_WAIT_FUNC(name, autoremove_wake_function)


 

autoremove_wake_function會調用default_wake_function,然後將所屬等待隊列成員從等待隊列中刪除。

 

voidprepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state){        unsigned long flags;        wait->flags &= ~WQ_FLAG_EXCLUSIVE;        spin_lock_irqsave(&q->lock, flags);        if (list_empty(&wait->task_list))                __add_wait_queue(q, wait);        set_current_state(state);        spin_unlock_irqrestore(&q->lock, flags);}static long do_CustomEvent_wait(long eventNum)                                                {        struct CustomEvent *tmp = NULL;                                                               struct CustomEvent *prev = NULL;                                                              pr_info("Enten into %s, the eventNum is %d\n", __func__, eventNum);                           if((tmp = FindEventNum(eventNum, &prev)) != NULL) {                                                   DEFINE_WAIT(wait);                                                                            prepare_to_wait(tmp->p, &wait, TASK_INTERRUPTIBLE);                                           schedule();                                                                                   finish_wait(tmp->p, &wait);                                                                   return eventNum;        }        return -1;}static long do_CustomEvent_signal(long eventNum){        struct CustomEvent *tmp = NULL;        struct CustomEvent *prev = NULL;        pr_info("Enten into %s, the eventNum is %d\n", __func__, eventNum);        if(!(tmp = FindEventNum(eventNum, &prev)))                return 0;        wake_up(tmp->p);        return 1;}


 

第三種方法(wait_event 和 wake_up組合):
該方法首先將進程的狀態設為 TASK_UNINTERRUPTIBLE, 之後判斷條件是否滿足;條件不滿足時,通過schedule()將該進程從runqueue隊列中移除,該進程進入睡眠狀態;只有當某進程調用wake_up才能再次喚醒該進程;進程被喚醒後,再次將該進程的狀態置為TASK_UNINTERRUPTIBLE,然後判斷條件是否滿足。條件滿足時結束迴圈,由finish_wait將進程的狀態設定為TASK_RUNNING,並從等待隊列的鏈表中移除相應項。


 

#define __wait_event(wq, condition)                                     do {                                                                            DEFINE_WAIT(__wait);                                                                                                                            for (;;) {                                                                      prepare_to_wait(&wq, &__wait, TASK_UNINTERRUPTIBLE);                    if (condition)                                                                  break;                                                          schedule();                                                     }                                                                       finish_wait(&wq, &__wait);                                      } while (0)#define wait_event(wq, condition)                                       do {                                                                            if (condition)                                                                  break;                                                          __wait_event(wq, condition);                                    } while (0)

 

——————————————————————————————————————————————————————————————————————————————————————————————————————————————
completion:
基於等待隊列,核心利用該機制等待某一操作結束。由於和wait_queue用法類似,不再詳細描述。
completion的操作介面:
init_completion()封裝了init_waitqueue_head()介面;
wait_for_completion()封裝了wait_for_common()介面;
complete()封裝了__wake_up_common()介面。

——————————————————————————————————————————————————————————————————————————————————————————————————————————————
work_queue:

由於在中斷中不能進行阻塞型操作,而有時候需要在中斷時讀取某些記憶體單元或寄存器的值,此時可以考慮利用工作隊列來實現。

工作隊列的定義:

工作隊列是將操作延期的一種手段。因為他們是通過守護進程在使用者上下文執行,函數可以睡眠任意長的時間,這與核心無關。替換了之前的kevented機制。

 
工作隊列的使用:

使用工作隊列,主要有以下三個步驟:

1 實現工作任務處理函數

2 建立並初始化工作任務

3 將工作任務添加到某工作隊列中,等待系統調度


<kernel/workqueue.c>

int schedule_work(struct work_struct *work)int schedule_delayed_work(struct work_struct *dwork, unsigned long delay)

 

1 定義工作任務處理函數:

static void func(struct work_struct *work){......} 

 

2 建立並初始化工作任務

可採用兩種方式建立並初始化工作任務:

1) 先建立工作任務,後綁定處理函數:
 

struct work_struct xxx_wq;//建立工作任務

 

在模組初始化的時候:

INIT_WORK(&xxx_wq,func);//初始化工作任務,工作任務需要執行的是函數func

 
2)  建立工作任務的同時初始化:
 

DECLARE_WORK(xxx_wq, func); 


3 在中斷處理函數中將工作任務添加到工作隊列,等待系統調度

static inline bool queue_work(struct workqueue_struct *wq, struct work_struct *work){        return queue_work_on(WORK_CPU_UNBOUND, wq, work);}



用於將某工作任務添加到某工作隊列

核心建立了一個標準的工作隊列events,核心的各個部分若無必要建立獨立的工作隊列,可直接使用該工作隊列。

static inline bool schedule_work(struct work_struct *work)//將工作任務xxx_wq添加到標準工作隊列events中,中斷處理完成之後可以立即執行func{        return queue_work(system_wq, work);}

 

tasklet、wait_queue、completion、work_queue用法總結

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.