歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> 關於Linux

poll&&epoll實現分析(一)—poll實現

在Linux內核中等待隊列有很多用途,可用於中斷處理、進程同步及定時。我們在這裡只說,進程經常必須等待某些事件的發生。等待隊列實現了在事件上的條件等待: 希望等待特定事件的進程把自己放進合適的等待隊列,並放棄控制全。因此,等待隊列表示一組睡眠的進程,當某一條件為真時,由內核喚醒它們。

等待隊列由循環鏈表實現,由等待隊列頭(wait_queue_head_t)和等待隊列項(wait_queue)組成,其元素(等待隊列項)包含指向進程描述符的指針。每個等待隊列都有一個等待隊列頭(wait queue head),等待隊列頭是一個類型為wait_queue_head_t的數據結構

定義等待隊列頭(相關內容可以在linux/include/wait.h中找到)

等待隊列頭結構體的定義:

struct wait_queue_head {

  spinlock_t  lock;          //自旋鎖變量,用於在對等待隊列頭          

  struct list_head task_list;  // 指向等待隊列的list_head

}; 

typedef struct __wait_queue_head  wait_queue_head_t;

使用等待隊列時首先需要定義一個wait_queue_head,這可以通過DECLARE_WAIT_QUEUE_HEAD宏來完成,這是靜態定義的方法。該宏會定義一個wait_queue_head,並且初始化結構中的鎖以及等待隊列。

 

     Linux中等待隊列的實現思想如下圖所示,當一個任務需要在某個wait_queue_head上睡眠時,將自己的進程控制塊信息封裝到wait_queue中,然後掛載到wait_queue的鏈表中,執行調度睡眠。當某些事件發生後,另一個任務(進程)會喚醒wait_queue_head上的某個或者所有任務,喚醒工作也就是將等待隊列中的任務設置為可調度的狀態,並且從隊列中刪除。

 


 

(2)等待隊列中存放的是在執行設備操作時不能獲得資源而掛起的進程

定義等待對列:

struct wait_queue {

  unsigned int flags;  //prepare_to_wait()裡有對flags的操作,查看以得出其含義

      #define WQ_FLAG_EXCLUSIVE        0x01 //一個常數,在prepare_to_wait()用於修改flags的值

          void * private          //通常指向當前任務控制塊

          wait_queue_func_t func;    //喚醒阻塞任務的函數 ,決定了喚醒的方式

  struct list_head task_list;    // 阻塞任務鏈表

};

typedef struct __wait_queue          wait_queue_t;

 

 

poll實現分析

1.select/poll缺點

 select/poll的缺點在於:
     1.每次調用時要重復地從用戶態讀入參數。
     2.每次調用時要重復地掃描文件描述符。
     3.每次在調用開始時,要把當前進程放入各個文件描述符的等待隊列。在調用結束後,又把進程從各個等待隊列中刪除。

2. 內核實現

2.1 主要數據結構:

(1) struct poll_table_entry {

        struct file  filp;

        wait_queue_t wait;//內部有一個指針指向一個進程

        wait_queue_head_t   wait_address;//等待隊列頭部(等待隊列有多個wait_queue_t組成,通過雙鏈表連接)

};

(2) struct poll_table_page {

        struct poll_table_page   next;

        struct poll_table_entry   entry;

        struct poll_table_entry entries[0];

};

(3) struct poll_wqueues {

       poll_table pt;//一個函數指針,通常指向__pollwait或null

       struct poll_table_page * table;

       int error;

};

(4) struct poll_list {

        struct poll_list *next;//按內存頁連接,因為kmalloc有申請數據限制

        int len;//用戶空間傳入fd的數量

        struct pollfd entries[0];//存放用戶空間存入的數據

};

typedef void (*poll_queue_proc)(struct file *, wait_queue_head_t *, struct poll_table_struct *);
 typedef struct poll_table  struct {
     poll_queue_proc qproc;
 } poll_table;


 

2.2 poll系統調用函數關系總圖

 int poll(struct pollfd *fds, nfds_t nfds, int timeout);

 

Copyright © Linux教程網 All Rights Reserved