使用非阻塞IO的應用程序常常使用select,poll,epoll系統調用;它們的功能本質上是同樣的:都容許進程決定是否能夠對一個或者多個打開的文件作非阻塞的讀取或者寫入;這些電泳也會阻塞進程,直到給定的文件描述符中的任何一個可讀取或者寫入;所以,它們經常用於那些須要使用多個輸入或者輸出流而又不會阻塞於其中任何一個流的應用程序中;同一功能之因此要由多個獨立的函數提供,是由於其中兩個幾乎是由兩個不一樣的Unix團體分別實現的:select在BSD中引入,而poll由SystemV引入;epoll系統調用則用於將poll函數擴展到可以處理數千個文件描述符;函數
poll在file_operations結構中的定義以下:spa
1 unsigned int (*poll) (struct file *, struct poll_table_struct *);
1
|
unsigned int (*poll) (struct file *, struct poll_table_struct *);
|
當用戶空間程序在驅動程序關聯的文件描述符上執行select,poll,epoll系統調用時,該驅動程序的方法將被調用;該poll函數的功能分爲兩步:code
1. 在一個或者多個可指示poll狀態變化的等待隊列上調用poll_wait;若是當前沒有文件描述符可用來執行IO,則內核將進程在傳遞到該系統調用的全部文件描述符對應的等待隊列上等待;blog
1 static inline void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p)
2. 返回一個用來描述操做是否能夠當即無阻塞執行的位掩碼;隊列
POLLIN-若是設備能夠無阻塞的讀取,就設置該位;進程
POLLRDNORM-若是一般的數據已經就緒,就能夠讀取,就應該設置該位;一個可讀設備返回POLLIN|POLLRDNORM;it
POLLRDBAND-指示能夠從設備讀取out-of-band帶外數據;io
POLLPRI-能夠無阻塞的讀取高優先級(即out-of-band)的數據;設置該位會致使select報告文件發生一個異常,這是因爲select把out-of-band數據做爲異常對待;table
POLLHUP-當讀取設備的進程到達文件尾時,驅動程序必須設置POLLHUP位,調用select的進程會被告知設備是可讀的;class
POLLERR-設備發生了錯誤;若是調用poll,就會報告設備既能夠讀也能夠寫,由於讀寫都會無阻塞的返回一個錯誤碼;
POLLOUT-若是設備能夠無阻塞的寫入,就在返回值中設置該位;
POLLWRNORM-該位和POLLOUT的意義同樣,有時其實就是同一個數字;一個可寫的設備將返回POLLOUT|POLLWRNORM;
POLLWRBAND-與POLLRDBAND相似,這一位標識具備非零優先級的數據能夠被寫入設備;只有數據報的poll實現中使用了這一位,由於數據報能夠傳輸out-of-band數據;
POLLRDBAND和POLLWRBAND只在於套接字相關的文件描述符中才有意義,設備驅動程序一般用不到這兩個標記;
隨意從內核摘取了一段代碼,對上面描述的兩個步驟體現的很明確;
1 static unsigned int evdev_poll(struct file *file, poll_table *wait) 2 { 3 struct evdev_client *client = file->private_data; 4 struct evdev *evdev = client->evdev; 5 unsigned int mask; 6 7 poll_wait(file, &evdev->wait, wait); 8 9 if (evdev->exist && !client->revoked) 10 mask = POLLOUT | POLLWRNORM; 11 else 12 mask = POLLHUP | POLLERR; 13 14 if (client->packet_head != client->tail) 15 mask |= POLLIN | POLLRDNORM; 16 17 return mask; 18 }