阻塞型字元裝置驅動

來源:互聯網
上載者:User
阻塞型字元裝置驅動

[概述]

首先明確一點,不管你是睡眠、休眠還是阻塞,還是掛起,本質上都是把進程放到等待隊列上。

 

[休眠的實現]

休眠通過等待隊列進行處理。等待隊列是由等待某些事件發生的進程組成的簡單鏈表。核心中用wake_queue_head_t來代表等待隊列。等待隊列可以通過DECLARE_WAITQUEUE()靜態建立,也可以由Init_waitqueue_head()動態建立。進程把自己放入等待隊列中並設定成不可執行狀態。當與等待隊列相關的事件發生的時候,隊列上的進程會被喚醒。為了避免產生競爭條件,休眠和喚醒的實現不能有紕漏。

針對休眠,核心提供了一些簡單的介面。但那些介面會帶來競爭條件:有可能導致在判斷條件為真後,進程卻開始了休眠,那樣就會使進程無限期地休眠下去,所以,在核心中進行休眠的推薦操作就想複雜了一些:

DEFINE_WAIT(wait); Add_wait_queue(q, &wait);While (!condition) {         Prepare_to_wait(&q,&wait, TASK_INTERRUPTIBLE);         If(signal_pending(current))                   /*處理訊號 */         Schedule();}Finish_wait(&q, &wait);

1)      調用宏DEFINE_WAIT()建立一個等待隊列的項;

2)      調用add_wait_queue()把自己加入到隊列中,該隊列會在進程等待的條件滿足時喚醒它,當然我們必須在其他地方編寫相關代碼,在事件發生時,對等待隊列執行wake_up()操作;

3)      調用prepare_to_wait()方法將進程的狀態變更為TASK_INTERRUPTIBLE或TASK_UNINTERRUPTIBLE。而且該函數如果有必要的話會將進程家回到等待隊列,這是在接下來的迴圈遍曆中所需要的;

4)      如果狀態被設定為TASK_INTERRUPTIBLE,則訊號喚醒進程。這就是所謂的偽喚醒,因此檢查並處理訊號;

5)      當進程被喚醒的時候,它會再次檢查條件是否為真。如果是,它就退出迴圈;如果不是,它再次調用schedule()並一直重複這步操作;

6)      當條件滿足後,進程將自己設定為TASK_RUNNING並調用finish_wait()方法把自己移出等待隊列;

如果需要瞭解這些函數的實現,可以參考http://edsionte.com/techblog/archives/1854

 

[一個阻塞型FIFO執行個體]

對上面休眠實現理論有了一個瞭解,看下面的代碼應該不難了。

[fifo結構體]

struct simple_chrdev_fifo {         structcdev cdev;         charfifo[MAX_SIZE];         intfifo_size;         intcurrent_pos;       /* read and writeposition in fifo */         structsemaphore sem;   /* semaphore */         wait_queue_head_treadq, writeq;         /* read queue andwrite queue */};

[阻塞型read方法]

static ssize_t simple_read(struct file*filp, char __user *buf, size_t count,                                                                 loff_t*f_pos){         structsimple_chrdev_fifo *dev = filp->private_data;         intret = 0;          DEFINE_WAIT(wait);          if(down_interruptible(&dev->sem))                   return-ERESTARTSYS;          add_wait_queue(&dev->readq,&wait);         while(dev->current_pos == 0) {                   up(&dev->sem);                   if(filp->f_flags & O_NONBLOCK)                            return- EAGAIN;                    prepare_to_wait(&dev->readq,&wait, TASK_INTERRUPTIBLE);                    if(signal_pending(current)) {                            ret  = - ERESTARTSYS;                            gotoout2;                   }                    schedule();                    if(down_interruptible(&dev->sem)) {                            ret= -ERESTARTSYS;                            gotoout2;                   }         }          if(count > dev->current_pos)                   count= dev->current_pos;                 if(copy_to_user(buf, (void *)(dev->fifo), count)) {                   ret= -EFAULT;                   gotoout;         }         dev->current_pos-= count;         ret= count;          wake_up_interruptible(&dev->writeq);out:         up(&dev->sem);out2:         finish_wait(&dev->readq,&wait);         returnret;}

[模組初始化函數]

static int __initsimple_chrdev_fifo_init(void){         ……         /*          * initialze wait queue         */         init_waitqueue_head(&dev->readq);         init_waitqueue_head(&dev->writeq);          init_MUTEX(&dev->sem);         ……}

使用init_waitqueue_head宏對等待讀隊列頭和等待寫隊列頭進行初始化;

這裡只貼出了重要的代碼,如果需要完整的代碼,請發email給我。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.