前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[039]Looper的wake机制升级

[039]Looper的wake机制升级

作者头像
王小二
发布2020-06-08 12:07:10
1.2K0
发布2020-06-08 12:07:10
举报
文章被收录于专栏:王小二的Android站

前言

我做了两期有关Looper的视频,目前来看播放量还不错,有兴趣的可以去B站观看,视频中我提到Looper采用pipe机制wake,纠正一下自己的错误,新版本的Looper已经采用eventfd代替pipe。

王小二图解Android【001】Looper上篇 王小二图解Android【002】Looper下篇

一、Android 5.1或更早版本

代码语言:javascript
复制
//初始化
Looper::Looper(bool allowNonCallbacks) :
        mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),
        mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {
    int wakeFds[2];
    int result = pipe(wakeFds);//创建一个pipe
    mWakeReadPipeFd = wakeFds[0];
    mWakeWritePipeFd = wakeFds[1];
    ....
    //epoll 监听pipe的读端mWakeReadPipeFd
    result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, & eventItem);
}

void Looper::wake() {
    ssize_t nWrite;
    do {
        //wake的时候往pipe的写端mWakeWritePipeFd写一字符"W"
        nWrite = write(mWakeWritePipeFd, "W", 1);
    } while (nWrite == -1 && errno == EINTR);

    if (nWrite != 1) {
        if (errno != EAGAIN) {
            ALOGW("Could not write wake signal, errno=%d", errno);
        }
    }
}

第一步:初始化创建pipe,产生2个fd,分别是mWakeReadPipeFd和mWakeWritePipeFd 第二步:epoll机制监听pipe的读端mWakeReadPipeFd 第三步:wake的时候往pipe的写端mWakeWritePipeFd,写入一个字符w就可以唤醒Looper

二、Android 6.0或更高的版本

代码语言:javascript
复制
Looper::Looper(bool allowNonCallbacks) :
        mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),
        mPolling(false), mEpollFd(-1), mEpollRebuildRequired(false),
        mNextRequestSeq(0), mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {
    mWakeEventFd = eventfd(0, EFD_NONBLOCK);//用eventfd初始化mWakeEventFd

    AutoMutex _l(mLock);
    rebuildEpollLocked();
}

void Looper::rebuildEpollLocked() {
    ...
    //用epoll机制监听mWakeEventFd
    int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeEventFd, & eventItem);
    ...
}

void Looper::wake() {
    uint64_t inc = 1;
    //直接write一个1到mWakeEventFd唤醒
    ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd, &inc, sizeof(uint64_t)));
    if (nWrite != sizeof(uint64_t)) {
        if (errno != EAGAIN) {
            ALOGW("Could not write wake signal, errno=%d", errno);
        }
    }
}

第一步:eventfd初始化mWakeEventFd 第二步:epoll机制监听eventfd的mWakeEventFd 第三步:wake的时候往mWakeEventFd,写入一个数字1就可以唤醒Looper

三、为什么用eventfd代替pipe

3.1 fd减少一个

每个进程fd是有上限的,一般是1024个,超出了就是OOM

pipe产生2个fd
eventfd只会产生1个fd

3.2 轻量化

虽然wake的时候都是往fd写入一个字符或者数字,但是内核中pipe和eventfd对write的系统调用的实现可不同,可以观看我的视频,了解详情。

王小二图解Android【005】一切皆文件

pipe需要维护一个内存缓冲区,一般是4096B
eventfd只需要维护一个无符号的64位整形计数器 counte

四、总结

很明显eventfd用更少的代价达到了相同的目的,所以Android官方果断就换了,很多旧书上可能还是介绍用pipe,这里需要注意一下,但是你只要理解Looper设计的精髓,这些升级对你来说,看一下源码就知道了。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 一、Android 5.1或更早版本
  • 二、Android 6.0或更高的版本
  • 三、为什么用eventfd代替pipe
    • 3.1 fd减少一个
      • 3.2 轻量化
      • 四、总结
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档