歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> 關於Linux >> poll&&epoll實現分析(一)—poll實現

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

日期:2017/3/2 9:54:31   编辑:關於Linux

在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