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

Android系统--输入系统(二)必备Linux知识_实现inotify_epoll.c的更多相关文章

  1. Android系统--输入系统(三)必备Linux知识_双向通信(scoketpair)

    Android系统--输入系统(三)必备Linux知识_双向通信(scoketpair) 引入 1. 进程和APP通信 创建进程 读取.分发 - 进程发送输入事件给APP 进程读取APP回应的事件 输 ...

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

    Android系统--输入系统(一)必备的Linux知识_inotify和epoll 引入 1. 笔记本电脑插入外接键盘,两个键盘都可以使用 a. 键盘即插即用--如何检测键盘的接入和拔出 hotpl ...

  3. Android系统--输入系统(十二)Dispatch线程_总体框架

    Android系统--输入系统(十二)Dispatch线程_总体框架 1. Dispatch线程框架 我们知道Dispatch线程是分发之意,那么便可以引入两个问题:1. 发什么;2. 发给谁.这两个 ...

  4. Android系统--输入系统(五)输入系统框架

    Android系统--输入系统(五)输入系统框架 1. Android设备使用场景: 假设一个Android平板,APP功能.系统功能(开机关机.调节音量).外接设备功能(键盘.触摸屏.USB外接键盘 ...

  5. Android系统--输入系统(六)模拟输入驱动程序

    Android系统--输入系统(六)模拟输入驱动程序 1. 回顾输入子系统 简单字符设备驱动:应用程序通过调用驱动所实现的函数使能硬件. 输入子系统:由于有多个应用程序使用输入子系统,故肯定使用的是早 ...

  6. Android系统--输入系统(九)Reader线程_核心类及配置文件

    Android系统--输入系统(九)Reader线程_核心类及配置文件 1. Reader线程核心类--EventHub 1.1 Reader线程核心结构体 实例化对象:mEventHub--表示多个 ...

  7. Android系统--输入系统(十)Reader线程_核心类及配置文件深入分析

    Android系统--输入系统(十)Reader线程_核心类及配置文件深入分析 0. 前言 个人认为该知识点阅读Android源代码会不仅容易走进死胡同,并且效果并不好,前脚看完后脚忘记,故进行总结, ...

  8. Android系统--输入系统(七)Reader_Dispatcher线程启动分析

    Android系统--输入系统(七)Reader_Dispatcher线程启动分析 1. Reader/Dispatcher的引入 对于输入系统来说,将会创建两个线程: Reader线程(读取事件) ...

  9. Android系统--输入系统(八)Reader线程_使用EventHub读取事件

    Android系统--输入系统(八)Reader线程_使用EventHub读取事件 1. Reader线程工作流程 获得事件 size_t count = mEventHub->getEvent ...

随机推荐

  1. Shell脚本之监视指定进程的执行状态

    在之前的博客中,以前写了自己主动化測试程序的实现方法,如今开发人员须要知道被測试的进程(在此指执行在LINUX上的主进程的)在异常退出之前的进程的执行状态,比如内存的使用率.CPU的使用率等. 现用s ...

  2. oracle高水位

    oracle高水位http://www.cnblogs.com/chuyuhuashi/p/3548260.htmlhttp://blog.csdn.net/wyzxg/article/details ...

  3. Python中的多进程与多线程/分布式该如何使用

    在批评Python的讨论中,常常说起Python多线程是多么的难用.还有人对 global interpreter lock(也被亲切的称为“GIL”)指指点点,说它阻碍了Python的多线程程序同时 ...

  4. 改动MySQL数据库port号 2.0

    这里通过改动数据库服务启动时的配置文件来达到改动的目的 Linux下的配置文件夹文件(演示样例):/usr/local/mysql/my.cnf [mysqld] # Remove leading # ...

  5. python 线程(thread)

    #coding:utf-8#多线程#Python的标准库提供了两个模块:thread和threading,thread是低级模块,threading是高级模块,对thread进行了封装 #绝大数情况下 ...

  6. Android开发:TableFixHeaders源码分析

    最近需要在android上的展示表格数据,在github上找到了TableFixHeaders(https://github.com/InQBarna/TableFixHeaders). 项目文件最主 ...

  7. JSON Extractor/jp@gc - JSON Path Extractor 举例2

    测试描述 使用json返回结果做校验 测试步骤 1.配置http请求 2.根据结果树返回的json,取值 { "status_code":200, "message&qu ...

  8. Censor(KMP)

    Censor frog is now a editor to censor so-called sensitive words (敏感词). She has a long text pp. Her j ...

  9. Maven + Jetty 部署锁文件解决办法

    用Maven + Jetty 在Eclipse环境启动后,改静态文件的时候出现如下提示 就表示文件被锁住了. 解决办法如下: <plugin> <groupId>org.ecl ...

  10. Lucene索引数计算

    Elasticsearch默认在创建索引结束时得到5个分片及1个副本: 分片是有0-n个副本,“5个分片及1个副本”即“5个分片及5个相应分片副本”:共10个Lucene索引 副本数:指的是“单个分片 ...