Android系统--输入系统(一)必备的Linux知识_inotify和epoll

Android系统--输入系统(一)必备的Linux知识_inotify和epoll

引入

1. 笔记本电脑插入外接键盘,两个键盘都可以使用

a. 键盘即插即用--如何检测键盘的接入和拔出

  • hotplug机制:内核发现键盘接入或拨出之后启动hotplug进程,进程发出信号告诉输入系统,输入系统处理

  • inotify机制:输入系统使用inotify检测/dev/input的节点变化

b. 可用使用多键盘--如何知道哪个键盘被按下

  • epoll机制:可以检测多个事件

c. 如何使用inotify和epoll机制:

(1) inotify使用(用于检测目录或者文件的变化)

  • 初始化得到文件句柄--fd=inotify_init();

  • 检测对象--inotify_add_watch(fd,目录/文件,创建/删除);

  • 对象变化--read();返回一个或者多个结构体:struct inotify_event

           struct inotify_event {

               __s32 wd;

               __u32 mask;    //发生的变化状态

               __u32 cookie;

               __u32 len;     //name的长度

               char name[0];  //发生变化的文件

           }
范例代码:

inotify.c


 *Author  : LKQ

 *Date    : 2017-2-23

 *Desc    : use inotify watch dir change

 *参考: frameworks
ativeservicesinputflingerEventHub.cpp

 */

 /*Usage: inotify <dir> */

 

#include <unistd.h>

#include <stdio.h>

#include <sys/inotify.h>

#include <string.h>

#include <errno.h>

int read_process_inotify_fd(int fd)

{

    int res;

    char event_buf[512];

    int event_size;

    int event_pos = 0;

    struct inotify_event *event;

	/* read */	

    res = read(fd, event_buf, sizeof(event_buf));  //return a struct 

	

    if(res < (int)sizeof(*event)) {

        if(errno == EINTR)

            return 0;

        printf("could not get event, %s
", strerror(errno));

        return -1;

    }	

	

	//procee : read a and more inotify_event

	//deal with each struct 

	

    while(res >= (int)sizeof(*event)) {

        event = (struct inotify_event *)(event_buf + event_pos);

        //printf("%d: %08x "%s"
", event->wd, event->mask, event->len ? event->name : "");

        if(event->len) {

            if(event->mask & IN_CREATE) {

                printf("create file: %s
", event->name);

            } else {

                printf("delete file: %s
", event->name);

            }

        }

        event_size = sizeof(*event) + event->len;

        res -= event_size;

        event_pos += event_size;

    }

	return 0;

	

}

int main(int argc,char **argv)

{

    int mINotifyFd;

	int result;

    if(argc != 2)

    {

        printf("Usage : %s <dir> 
",argv[1]);

	}

	/*1. inotify init*/

    mINotifyFd = inotify_init();	

	/*2. add watch*/

    result = inotify_add_watch(mINotifyFd, argv[1], IN_DELETE | IN_CREATE);	

	/*3. read*/

	while (1)

	{

		read_process_inotify_fd(mINotifyFd);

	}

	return 0;

}

使用过程:

gcc -o inotify inotify.c

mkdir tmp

./inotify tmp &

echo > tmp/1

echo > tmp/2

rm tmp/1 tmp/2

(2) epoll使用(用于检测多个文件:1. 有无数据可供读取;2. 有无空间写入)

  • 初始化得到文件句柄--fd=epoll_create();

  • 对于每一个文件执行epoll_ctl(fd,EPOLL_CRTL_ADD,...);表示监测该文件的行为

  • epoll_wait();等待某个文件可用epoll_ctl(fd,EPOLL_CRTL_DEL,...);

范例代码:

epoll.c


/*

 *Author  : LKQ

 *Date    : 2017-2-23

 *Desc    :how to use epoll

 *参考: frameworks
ativeservicesinputflingerEventHub.cpp

 */

/* usage: epoll <file1> [file2] [file3] ... */

#include <stdio.h>

#include <sys/epoll.h>

#include <unistd.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <string.h>

#if 0

typedef union epoll_data {

   void        *ptr;

   int          fd;

   uint32_t     u32;

   uint64_t     u64;

} epoll_data_t;

#endif

#define DATA_MAX_LEN 512

int add_to_epoll(int fd, int epollFd)

{

	int result;

    struct epoll_event eventItem;

    memset(&eventItem, 0, sizeof(eventItem));

    eventItem.events = EPOLLIN;

    eventItem.data.fd = fd;

    result = epoll_ctl(epollFd, EPOLL_CTL_ADD, fd, &eventItem);

	return result;

}

void rm_from_epoll(int fd, int epollFd)

{

	epoll_ctl(epollFd, EPOLL_CTL_DEL, fd, NULL);

}

int main(int argc,char **argv)

{

    int mEpollFd;

	int i;

	char buf[DATA_MAX_LEN];

    // Maximum number of signalled FDs to handle at a time.

    static const int EPOLL_MAX_EVENTS = 16;

    // The array of pending epoll events and the index of the next event to be handled.

    struct epoll_event mPendingEventItems[EPOLL_MAX_EVENTS];

	

	if (argc < 2)

    {

		printf("Usage: %s <file1> [file2] [file3] ...
", argv[0]);

		return -1;

    }

	/*1. epoll create*/

    mEpollFd = epoll_create(8);	

	/*2.  for each file:

	 *      open it

	 *      add it to epoll: epoll_ctl(...EPOLL_CTL_ADD...)

	 */

	for(i=1;i<argc;i++){

               //int tmpFd = open(argv[i], O_RDONLY|O_NONBLOCK);

               int tmpFd = open(argv[i],O_RDWR);

               add_to_epoll(tmpFd,mEpollFd);

	}

	/*3.  epoll_wait */

	while (1)

	{

		

        int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, -1);

		for (i = 0; i < pollResult; i++)

		{

			printf("Reason: 0x%x
", mPendingEventItems[i].events);

			int len = read(mPendingEventItems[i].data.fd, buf, DATA_MAX_LEN);

			buf[len] = '';

			printf("get data: %s
", buf);

		}

	}

	/*remove epoll*/

	for(i=1;i<argc;i++){

		rm_from_epoll(mPendingEventItems[i].data.fd,mEpollFd);

	}

	return 0;

}

操作方法:

gcc -o epoll epoll.c

mkdir tmp

mkfifo tmp/1 tmp/2 tmp/3

./epoll tmp/1 tmp/2 tmp/3 &

echo aaa > tmp/1

echo bbb > tmp/2

echo ccc > tmp/3

补充:

当fifo文件以 O_RDONLY|O_NONBLOCK 方式打开,会出现不断返回epoll_wait,导致崩溃。

原因:使用fifo是, 我们的epoll程序是reader;echo aa > tmp/1 是writer

a. 如果reader以 O_RDONLY|O_NONBLOCK打开FIFO文件,writer写入数据时, epoll_wait会立刻返回;
当writer关闭FIFO之后, reader再次调用epoll_wait, 它也会立刻返回(原因是EPPLLHUP, 描述符被挂断)

b. 如果reader以 O_RDWR打开FIFO文件当writer写入数据时, epoll_wait会立刻返回;
当writer关闭FIFO之后, reader再次调用epoll_wait, 它并不会立刻返回, 而是继续等待有数据

原文地址:https://www.cnblogs.com/lkq1220/p/6434184.html