InputManagerService入門之Epoll&INotify機制

第一章         文章簡介... 3

第二章         Epoll機制... 3

1、Epoll簡介... 3

2、Epoll創建... 3

3、Epoll控制... 3

4、Epoll讀取... 5

第三章 Inotify機制... 5

1、Inotify簡介... 5

2、Inotify創建... 5

 

 

 

本章主要介紹了在InputManagerService中藥用到的兩個很重要的linux中的機制。只有瞭解了該機制我們才能更好的理解InputManagerService。因爲InputManagerService中全靠這兩個機制來讀取事件和在適當的時機喚醒讀取線程。

1、Epoll簡介

epoll是一種IO多路複用技術,可以非常高效的處理數以百萬計的socket句柄。

2、Epoll創建

int epfd = epoll_create(intsize);

創建一個epoll的句柄,size用來告訴內核這個監聽的數目一共有多大。這個參數不同於select()中的第一個參數,給出最大監聽的fd+1的值。需要注意的是,當創建好epoll句柄後,它就是會佔用一個fd值,在linux下如果查看/proc/進程id/fd/,是能夠看到這個fd的,所以在使用完epoll後,必須調用close()關閉,否則可能導致fd被耗盡。

3、Epoll控制

函數聲明:int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
該函數用於控制某個epoll文件描述符上的事件,可以註冊事件,修改事件,刪除事件。
參數:
epfd:由 epoll_create 生成的epoll專用的文件描述符;
op:要進行的操作例如註冊事件,可能的取值EPOLL_CTL_ADD 註冊、EPOLL_CTL_MOD 修 改、EPOLL_CTL_DEL 刪除

fd:關聯的文件描述符;
event:指向epoll_event的指針;
如果調用成功返回0,不成功返回-1

int epoll_ctl(int epfd, intop, int fd, struct epoll_event*event);

epoll的事件註冊函數,它不同與select()是在監聽事件時告訴內核要監聽什麼類型的事件,而是在這裏先註冊要監聽的事件類型。

第一個參數是epoll_create()的返回值,
第二個參數表示動作,用三個宏來表示:
EPOLL_CTL_ADD: 註冊新的fd到epfd中;
EPOLL_CTL_MOD: 修改已經註冊的fd的監聽事件;
EPOLL_CTL_DEL: 從epfd中刪除一個fd;
第三個參數是需要監聽的fd,
第四個參數是告訴內核需要監聽什麼事件,structepoll_event結構如下:

typedef union epoll_data { 

void *ptr; 

int fd; 

__uint32_t u32; 

__uint64_t u64; 

} epoll_data_t; 

 

struct epoll_event { 

__uint32_t events; /* Epoll events */ 

epoll_data_t data; /* User data variable */ 

}; 

events可以是以下幾個宏的集合:
EPOLLIN: 觸發該事件,表示對應的文件描述符上有可讀數據。(包括對端SOCKET正常關閉);
EPOLLOUT: 觸發該事件,表示對應的文件描述符上可以寫數據;
EPOLLPRI: 表示對應的文件描述符有緊急的數據可讀(這裏應該表示有帶外數據到來);
EPOLLERR: 表示對應的文件描述符發生錯誤;
EPOLLHUP: 表示對應的文件描述符被掛斷;
EPOLLET: 將EPOLL設爲邊緣觸發(Edge Triggered)模式,這是相對於水平觸發(Level Triggered)來說的。
EPOLLONESHOT: 只監聽一次事件,當監聽完這次事件之後,如果還需要繼續監聽這個socket的話,需要再次把這個socket加入到EPOLL隊列裏。
如:
struct epoll_event ev;
//設置與要處理的事件相關的文件描述符
ev.data.fd=listenfd;
//設置要處理的事件類型
ev.events=EPOLLIN|EPOLLET;
//註冊epoll事件
epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev);

 

int epoll_wait(int epfd, struct epoll_event * events, intmaxevents, int timeout);
等待事件的產生,類似於select()調用。參數events用來從內核得到事件的集合,maxevents告之內核這個events有多大(數組成員的個數),這個maxevents的值不能大於創建epoll_create()時的size,參數timeout是超時時間(毫秒,0會立即返回,-1將不確定,也有說法說是永久阻塞)。
該函數返回需要處理的事件數目,如返回0表示已超時。
返回的事件集合在events數組中,數組中實際存放的成員個數是函數的返回值。返回0表示已經超時。
函數聲明:int epoll_wait(int epfd,struct epoll_event * events,int maxevents,int timeout)
該函數用於輪詢I/O事件的發生;
參數:
epfd:由epoll_create 生成的epoll專用的文件描述符;
epoll_event:用於回傳代處理事件的數組;
maxevents:每次能處理的事件數;
timeout:等待I/O事件發生的超時值(單位我也不太清楚);-1相當於阻塞,0相當於非阻塞。一般用-1即可
返回發生事件數。
epoll_wait運行的原理是
等侍註冊在epfd上的socket fd的事件的發生,如果發生則將發生的sokct fd和事件類型放入到events數組中。
並 且將註冊在epfd上的socket fd的事件類型給清空,所以如果下一個循環你還要關注這個socket fd的話,則需要用epoll_ctl(epfd,EPOLL_CTL_MOD,listenfd,&ev)來重新設置socket fd的事件類型。這時不用EPOLL_CTL_ADD,因爲socket fd並未清空,只是事件類型清空。

 

更多請查詢網絡。

4、Epoll讀取

第三章 Inotify機制

1、Inotify簡介

Inotify 是一個 Linux特性,它監控文件系統操作,比如讀取、寫入和創建。Inotify 反應靈敏,用法非常簡單,並且比 cron 任務的繁忙輪詢高效得多。學習如何將 inotify 集成到您的應用程序中,並發現一組可用來進一步自動化系統治理的命令行工具。

2、Inotify創建

有時候我們需要檢測某個目錄下文件或者子目錄的改動狀況,如添加、刪除、以及更新等,Linux系統上提供了inotify來完成這個功能。inotify是在版本2.6.13的內核中首次出現,現在的發行本應該都包含這個系統調用了。

下面的描述中的文件如無特別說明包括文件以及目錄

使用inotify的第一步就是調用inotify_init()創建一個inotify實例,該函數返回一個文件描述符。這個文件描述符關聯了一個inotify事件隊列,通過read讀取該文件描述符,就能獲取底層的inotify事件。

int inotify_fd = inotify_init();

還有另外一個系統調用inotify_init1(int flag),該函數提供了一個參數可用於設置文件描述符屬性

int inotify_fd = inotify_init1(flag);

 

其效果與如下代碼相同

int inotify_fd = inotify_init();

fcntl(inotify_fd, F_SETFL, flags)

一旦成功創建了inotify實例,獲得了相應的文件描述符,下一步就是告訴內核需要關注的文件以及關注的事件類型。這一步是通過函數inotify_add_watch()實現的。

int wd = inotify_add_watch(instance_fd, file_name, event_mask)

上面的調用中,file_name就是需要關注的文件,而event_mask是關注的事件類型掩碼。目前inotify支持的事件類型包括如下幾種

IN_ACCESS
IN_ATTRIB
IN_CLOSE_WRITE
IN_CLOSE_NOWRITE
IN_CREATE
IN_DELETE
IN_DELETE_SELF
IN_MODIFY
IN_MOVE_SELF
IN_MOVED_FROM
IN_MOVED_TO
IN_OPEN

這裏面值得注意的是IN_DELETE、IN_MOVE_TO和IN_DELETE_SELF、IN_MOVE_SELF,簡單來說帶有SELF結尾的事件,發生在被關注目錄自身,而不帶SELF的發生在關注對象的子目錄或者子文件之上。例如對於目錄A調用inotify_add_watch,如果目錄A中的文件B被刪除,內核會發出IN_DELETE事件,而目錄A被刪除,內核發出IN_DELETE_SELF事件。
如果決定不再關注某個文件,只需調用inotify_rm_watch(instance_fd, wd)即可,其中的wd爲inotify_add_watch的返回值。

設置好了關注文件以及事件類型,剩下的就是inotify事件的處理了。
首先第一步就是要獲取inotify事件,這一步非常簡單,只需要對於instance_fd調用read進行讀取即可。注意,read讀出的數據只是一些字符序列,你要通過強制轉換才能獲得inotify_event

struct inotify_event {

int wd;

uint32_t mask;

uint32_t cookie;

uint32_t len;

char name[]

};

具體的含義可以使用man命令去看,值得一體的是mask字段和cookie字段。這裏的mask字段除了包含事件類型之外,還可能包含其他信息,諸如IN_ISDIR標示事件是否是發生在目錄之上,IN_UMOUNT標示關注對象所在文件系統是否被卸載

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