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中全靠这两个机制来读取事件和在适当的时机唤醒读取线程。

Epoll机制

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标示关注对象所在文件系统是否被卸载

你可能感兴趣的:(InputManagerService入门之Epoll&INotify机制)