其他
Looper的wake机制升级
前言
我做了两期有关Looper的视频,目前来看播放量还不错,有兴趣的可以去B站观看,视频中我提到Looper采用pipe机制wake,纠正一下自己的错误,新版本的Looper已经采用eventfd代替pipe。
王小二图解Android【001】Looper上篇
王小二图解Android【002】Looper下篇
一、Android 5.1或更早版本
//初始化
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或更高的版本
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设计的精髓,这些升级对你来说,看一下源码就知道了。
回答网友的问题
因为我的B站等级不够无法直接回复网友问题,你们可以在视频留言,我就可以回答了。如果我在视频或者文章中有错误,欢迎大家提出来纠正。