[arm驅動]linux等待隊列阻塞中斷IO的應用

《[arm驅動]linux等待隊列阻塞中斷IO的應用》涉及內核驅動函數四個,內核結構體零個,分析了內核驅動函數四個;可參考的相關應用程序模板或內核驅動模板一個,可參考的相關應用程序模板或內核驅動一個

一、概念:
   要休眠進程,必須有一個前提:有人能喚醒進程,而起這個人必須知道在哪兒能喚醒進程,這裏,就引入了“等待隊列”這個概念。
二、應用場景:
   等待隊列用來實現進程的阻塞,等待隊列可看作保存進程的容器,在阻塞進程時,將進程放入等待隊列,當喚醒進程時,從等待等列中取出進程。進程進入休眠後必須有個地方能夠喚醒休眠的進程;喚醒進程的地方最大可能是中斷裏面,應爲硬件資源的獲取的同時往往伴隨着一箇中斷。所以在中斷中常常使用等待隊列來休眠進程,將cpu資源讓給其他進程,中斷髮生時喚醒進程
三、中斷休眠相關函數
   1、生成等待事件的函數

內核函數一)a)函數wait_event_interruptible(queue,condition)函數

wait_event_interruptible(queue,condition) //當condition(一個布爾表達式)爲真時,立即返回;
//否則讓進程進入TASK_INTERRUPTIBLE的睡眠,並掛在名爲queue所指定的等待隊列上。

內核代碼一)b)內核代碼

#define wait_event_interruptible(wq, condition)            
  ({                                
      int __ret = 0;                        
      if (!(condition))                    
          __wait_event_interruptible(wq, condition, __ret);
      __ret;                            
  })

內核函數二)2、wake_up_interruptible(queue);//喚醒隊列中的名爲queue的隊列
   內核代碼二)a)內核源碼


#define wake_up_interruptible(x)    __wake_up(x, TASK_INTERRUPTIBLE, 1, NULL)
    void fastcall __wake_up(wait_queue_head_t *q, unsigned int mode,
            int nr_exclusive, void *key)
    {
        unsigned long flags;
        spin_lock_irqsave(&q->lock, flags);
        __wake_up_common(q, mode, nr_exclusive, 0, key);
        spin_unlock_irqrestore(&q->lock, flags);
    }

   3、定義隊列名爲queue的兩種方法
內核函數三)a)靜態定義方法: DECLARE_QUEUE_HEAD(name)(常用)
內核代碼三)內核代碼

#define DECLARE_WAIT_QUEUE_HEAD(name) wait_queue_head_t name = __WAIT_QUEUE_HEAD_INITIALIZER(name)
           #define __WAIT_QUEUE_HEAD_INITIALIZER(name) {            
               .lock        = __SPIN_LOCK_UNLOCKED(name.lock),    
               .task_list    = { &(name).task_list, &(name).task_list } }

內核函數四)b)動態定義方法:

wait_queue_head_t  my_queue;
                  init_waitqueue_head(&my_queue);

內代碼四)內核代碼

init_waitqueue_head(&my_queue)的內核代碼
void init_waitqueue_head(wait_queue_head_t *q)
{
spin_lock_init(&q->lock);
INIT_LIST_HEAD(&q->task_list);
}

三、等待隊列代碼使用參考模板

模板一)

staticDECLARE_WAIT_QUEUE_HEAD(queue);
staticintflag =0;
staticirqreturn_t irq_handle(intirq, void*dev__id){
//printk("irq = %d\n", irq);
//..........其他代碼.............
flag = 1;
wake_up_interruptible(&queue);
returnIRQ_RETVAL(IRQ_HANDLED);//warn:榪斿洖IRQ_HANDLED
}
ssize_t XXXXX_read(structfile *filp,char__user *buf,size_tcount,loff_t *pos)
{
//pirntk(KERN_DEBUG "process %i (%s) going to sleep\n",current->pid,current->comm);
wait_event_interruptible(queue,flag);//此時進程被加入等待隊列,等待中斷髮生
flag=0;
//printk(KERN_DEBUG "awoken %i (%s) \n",current->pid,current->comm);
returncount;//這個count變量看自己需要更改
}


實例見[arm驅動]Linux內核開發之阻塞非阻塞IO----輪詢操作 中的實例








發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章