Android系统--输入系统(二)必备Linux知识_实现inotify_epoll.c

Android系统--输入系统(二)必备Linux知识_实现inotify_epoll.c

课后作业

1. 编写 inotify_epoll.c, 用它来监测tmp/目录: 有文件被创建/删除, 有文件可读出数据

  • a. 当在tmp/下创建文件时, 会立刻监测到,并且使用epoll监测该文件

  • b. 当文件有数据时,读出数据

  • c. 当tmp/下文件被删除时,会立刻监测到,并且把它从epoll中移除不再监测

2. 程序基本框架

(1)初始化--初始化epoll和inotify,获取其fd

(2)添加事件

  • 对文件夹中文件的创建和删除进行检测--inotify_add_watch(mINotifyFd, dir, IN_DELETE | IN_CREATE);

  • 将监听事件加入epoll池中,监听事件行为--add_to_epoll(mINotifyFd, mEpollFd);

(3)等待事件发生

  • 添加、删除文件事件--read_process_inotify_fd(int mINotifyFd, int mEpollFd)

  • 往文件写入数据--read(mPendingEventItems[i].data.fd, buf, DATA_MAX_LEN);

实现代码:

#include <sys/epoll.h>

#include <stdio.h>

#include <unistd.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <string.h>

#include <sys/inotify.h>

#include <stdlib.h>

#include <errno.h>


#define DATA_MAX_LEN 512

#define MAX_FILES    1024


static char *base_dir;

static char *epoll_files[MAX_FILES];


#if 0

typedef union epoll_data {

   void        *ptr;

   int          fd;

   uint32_t     u32;

   uint64_t     u64;

} epoll_data_t;

#endif


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);

}


/*函数说明:传入文件名,根据epoll_file数组指针,判断每一项指向的是否有内容,如有则比较文件名是否相同*/
int get_epoll_fd_for_name(char *name)

{

	int i;

	char name_to_find[512];

	sprintf(name_to_find, "%s/%s", base_dir, name);

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

	{

		if (!epoll_files[i])

			continue;

		

		if (!strcmp(epoll_files[i], name_to_find))

			return i;

	}

	return -1;

}


int read_process_inotify_fd(int mINotifyFd, int mEpollFd)

{

	int res;

    char event_buf[512];

    int event_size;

    int event_pos = 0;

    struct inotify_event *event;

	

	/* read */	

    res = read(mINotifyFd, event_buf, sizeof(event_buf));

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

        if(errno == EINTR)

            return 0;

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

        return -1;

    }

	/* process

	 * 读到的数据是1个或多个inotify_event

	 * 它们的长度不一样

	 * 逐个处理

	 */

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

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

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

        if(event->len) {

            if(event->mask & IN_CREATE) {

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

				char *name = malloc(512);

				sprintf(name, "%s/%s", base_dir, event->name);

				int tmpFd = open(name, O_RDWR);  //如有创建文件,则打开

				printf("add to epoll: %s\n", name);

				add_to_epoll(tmpFd, mEpollFd);   //将读取写入文件的事件加入epoll中

				epoll_files[tmpFd] = name;       //暂时保存文件名称,用于后面释放epoll中的该事件

					

            } else {

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

				int tmpFd = get_epoll_fd_for_name(event->name);  //利用文件名查找对应的事件fd

				if (tmpFd >= 0)

				{

					printf("remove from epoll: %s/%s\n", base_dir, event->name);

					rm_from_epoll(tmpFd, mEpollFd);

					free(epoll_files[tmpFd]);

				}

            }

        }

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

        res -= event_size;

        event_pos += event_size;

    }

	return 0;

}


int main(int argc,char **argv)

{

	int mEpollFd;

	int i;

	char buf[DATA_MAX_LEN];

	int mINotifyFd;

	int result;

	 // 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 <tmp>\n",argv[0]);

		return -1;

	}

	base_dir = argv[1];

	//1. init

	

	/* 1.1  epoll_create */

    mEpollFd = epoll_create(8);

	/* 1.2 inotify_init */

    mINotifyFd = inotify_init();

	//2. add

	/* 2.1 add watch */

    result = inotify_add_watch(mINotifyFd, base_dir, IN_DELETE | IN_CREATE);

	/* 2.2 addto epoll*/

	add_to_epoll(mINotifyFd, mEpollFd);

	/* 3. epoll_wait */

	while (1)

	{

		

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

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

		{

			if (mPendingEventItems[i].data.fd == mINotifyFd)  //事件fd为文件添加和删除,则跳转到inotify处理函数

			{

				read_process_inotify_fd(mINotifyFd, mEpollFd);

			}

			else

			{

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

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

				buf[len] = '\0';

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

			}

		}

		

	}


	return 0;
}

具体操作:
  • gcc -o inotify_epoll inotify_epoll.c

  • mkdir tmp

  • ./inotify_epoll tmp/ &

  • mkfifo tmp/1 tmp/2 tmp/3

  • echo aaa > tmp/1
    echo bbb > tmp/2
    echo ccc > tmp/3

  • rm tmp/3

posted @ 2017-02-23 19:49  lkq1220  阅读(716)  评论(0编辑  收藏  举报