inotify和epoll机制

假设你买了一台笔记本,但是你嫌它自带的键盘不好用,于是你买了个键盘,这样你可以两个键盘同时使用,这里面涉及了什么呢?

  1. 键盘即插即用
    a) 那么怎么检测键盘的接入和拔出,两种机制
    1. Hotplug机制:内核发现键盘接入/拔出->启动hotplug进程->消息传入输入系统,这种机制非常复杂,Android并不使用这种机制
    2. Inotift:输入系统使用inotify检测一个目录“/dev/input”
  2. 可使用多键盘同时使用
    a) 怎么知道哪个键盘被按下:使用epoll,只要一有数据这个epoll就能读取到

Inotify的使用

功能:检测目录/文件的变化

  1. fd = inotify_init()
  2. inotify_add_watch(目录/文件,创建/删除)
  3. read(fd ) 无文件发生变化则休眠,有文件发生变化则返回,返回一个或多个结构体,结构体内容如下:
struct inotify_event {
    __s32       wd;     /* watch descriptor */
    __u32       mask;       /* watch mask */
    __u32       cookie;     /* cookie to synchronize two events */
    __u32       len;        /* length (including nulls) of name */
    char        name[0];    /* stub for possible name */
};

inotify代码:

/*
 * 参考: frameworks\native\services\inputflinger\EventHub.cpp
 */

#include <unistd.h>
#include <stdio.h>
#include <sys/inotify.h>
#include <string.h>
#include <errno.h>


 /* 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;

    /* read */
    /* 无文件发生变化则休眠,有文件发生变化则返回,返回一个或多个结构体 */
    res = read(fd, event_buf, sizeof(event_buf));//读到的数据放入event_buf

    /* 如果一个event都没有的话返回错误 */
    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
     * 它们的长度不一样
     * 逐个处理
     */
    /* 逐个取出event_buf里面的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);
            } else {/* 如果是删除文件也是打印文件名 */
                printf("delete file: %s\n", 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>\n", argv[0]);
        return -1;
    }

    /* inotify_init */
    mINotifyFd = inotify_init();

    /* add watch */
    /* 检测哪个目录, 检测它是否有删除文件(IN_DELETE)或创建文件(IN_CREATE) */
    result = inotify_add_watch(mINotifyFd, argv[1], IN_DELETE | IN_CREATE);

    /* read */
    while (1)
    {
        /* 读数据 */
        read_process_inotify_fd(mINotifyFd);
    }

    return 0;
 }

测试:

gcc -o inotify inotify.c /* 编译 */

mkdir tmp /* 创建tmp这个目录 */

./inotify tmp & /* 检测tmp这个目录 */

echo > tmp/1 /* 在tmp目录下创建文件1 */

echo > tmp/2 /* 在tmp目录下创建文件2 */

rm tmp/1 tmp/2 /* 删除这两个文件 */

效果:
这里写图片描述


epoll的使用

功能:用来监测多个文件(有无数据供读出、有无空间供写入)

  1. epoll_create(创建fd)
  2. 对每个文件,执行epoll_ctl(…, epoll_ctl_add, …),表示要检测它
  3. 执行epoll_wait(等待某个文件可用)
  4. 不再想检测某个文件:epoll_ctl(…, epoll_ctl_del, …)

epoll代码:

#include <sys/epoll.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

#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;/* 监测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.
    /* 每次调用epoll_wait最多可以得到16个事件,可以再次调用,可以监测多个文件 */
    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] ...\n", argv[0]);
        return -1;
    }

    /* epoll_create */
    mEpollFd = epoll_create(8);

    /* 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)
    {
        //-1:永远检测直到有数据返回
        int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, -1);
        for (i = 0; i < pollResult; i++)
        {
            printf("Reason: 0x%x\n", mPendingEventItems[i].events);//打印返回数据的原因
            int len = read(mPendingEventItems[i].data.fd, buf, DATA_MAX_LEN);//从 mPendingEventItems[i].data.fd 读到的数据放到 buf 里面
            buf[len] = '\0';
            printf("get data: %s\n", buf);
            //sleep(3);
        }

    }

    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

效果:
这里写图片描述

总结:
android使用inotify来检测驱动目录,从而知道某个键盘被插入拔出,使用epoll来检测目录下的文件,从而知道某个键盘是否有数据

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值