一、inotify 和 epoll
1.Android不使用hotplug机制,使用的是inotify机制。inotify监听的是/dev/input目录。
2.使用inotify来监听文件的创建与删除,使用epoll来监听设备文件句柄的变化,包括inotify的fd。
3.epoll支持管道,FIFO,套接字,POSIX消息队列,终端,设备等,但是就是不支持普通文件或目录的fd。
测试验证,使用fifo测试epoll是可以的,但是使用普通文件来测试epoll的并发监听是不行的。
3.参考代码: frameworks ativeservicesinputflingerEventHub.cpp
参考文章:《深入理解Android 卷III》第五章 深入理解Android输入系统: http://blog.csdn.net/innost/article/details/47660387
4.测试遇到问题:使用O_RDONLY|O_NONBLOCK打开的FIFO让epoll去监听,echo一个数据到fifo中后,epoll_wait()一直无法阻塞住。
tmpFd = open(argv[i], O_RDONLY|O_NONBLOCK);
解答: epoll,fifo : http://stackoverflow.com/questions/15055065/o-rdwr-on-named-pipes-with-poll
使用fifo,epoll程序是reader
echo aa > tmp/1 是writer
a.
如果reader以O_RDONLY|O_NONBLOCK打开FIFO文件,
当writer写入数据时, epoll_wait会立刻返回;
当writer关闭FIFO之后, reader再次调用epoll_wait, 它也会立刻返回(原因是EPPLLHUP, 描述符被挂断(这个可以从epoll_event结构中看到EPPLLHUP码))
b.
如果reader以O_RDWR打开FIFO文件
当writer写入数据时, epoll_wait会立刻返回;
当writer关闭FIFO之后, reader再次调用epoll_wait, 它并不会立刻返回, 而是继续等待有数据
5.使用分号隔开可以实现在命令行中输入多条语句:eg:# echo 1 > tmp/5; echo 2 > tmp/2
6.试验Demo
inotify.c
#include <unistd.h> #include <stdio.h> #include <sys/inotify.h> #include <string.h> #include <errno.h> /* *²Î¿¼: frameworks ativeservicesinputflingerEventHub.cpp */ /*Usage: inotify <dir> */ int read_process_inotify_fd(int fd) { int res; char event_buf[512]; int event_size; int event_pos = 0; struct inotify_event *event; /* block read */ res = read(fd, event_buf, sizeof(event_buf)); if(res < (int)sizeof(*event)) { if(errno == EINTR) return 0; printf("could not get event, %s ", strerror(errno)); return -1; } /* process * ¶Áµ½µÄÊý¾ÝÊÇ1¸ö»ò¶à¸öinotify_event * ËüÃǵij¤¶È²»Ò»Ñù * Öð¸ö´¦Àí */ 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; // buf[0] with no length 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[0]); return -1; } /* inotify_init */ mINotifyFd = inotify_init(); /* add watch */ result = inotify_add_watch(mINotifyFd, argv[1], IN_DELETE | IN_CREATE); /* read */ while (1) { read_process_inotify_fd(mINotifyFd); } return 0; }
epoll.c
#include <sys/epoll.h> #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> #if 0 typedef union epoll_data { // it is a union. 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 */ }; #endif #define DATA_MAX_LEN 500 /* usage: epoll <file1> [file2] [file3] ... */ 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; } /* epoll_create */ mEpollFd = epoll_create(8); // man epoll said that 8 not used. /* 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); } /* epoll_wait */ while (1) { int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, -1); for (i = 0; i < pollResult; i++) { printf("Event code is: 0x%x ", mPendingEventItems[i].events); int len = read(mPendingEventItems[i].data.fd, buf, DATA_MAX_LEN); buf[len] = '