这里,首先是调用epoll_wait函数来看看epoll专用文件描述符mEpollFd所监控的文件描述符是否有IO事件发生,它设置监控的超时时间为timeoutMillis:
- [cpp] view plaincopyint eventCount = epoll_wait(mEpollFd, eventItems,
- EPOLL_MAX_EVENTS, timeoutMillis);
回忆一下前面的Looper的构造函数,我们在里面设置了要监控mWakeReadPipeFd文件描述符的EPOLLIN事件。
当mEpollFd所监控的文件描述符发生了要监控的IO事件后或者监控时间超时后,线程就从epoll_wait返回了,否则线程就会在epoll_wait函数中进入睡眠状态了。
返回后如果eventCount等于0,就说明是超时了:
- [cpp] view plaincopyif (eventCount == 0) {
- ......
- result = ALOOPER_POLL_TIMEOUT;
- goto Done;
- }
如果eventCount不等于0,就说明发生要监控的事件:
- [cpp] view plaincopyfor (int i = 0; i < eventCount; i++) {
- int fd = eventItems[i].data.fd;
- uint32_t epollEvents = eventItems[i].events;
- if (fd == mWakeReadPipeFd) {
- if (epollEvents & EPOLLIN) {
- awoken();
- } else {
- LOGW("Ignoring unexpected epoll events 0x%x on wake read pipe.",
- epollEvents);
- }
- } else {
- ......
- }
- }
这里我们只关注mWakeReadPipeFd文件描述符上的事件,如果在mWakeReadPipeFd文件描述符上发生了EPOLLIN就说明应用程 序中的消息队列里面有新的消息需要处理了,接下来它就会先调用awoken函数清空管道中把内容,以便下次再调用pollInner函数时,知道自从上次 处理完消息队列中的消息后,有没有新的消息加进来。
函数awoken的实现很简单,它只是把管道中的内容都读取出来:
- [cpp] view plaincopyvoid Looper::awoken() {
- ......
- char buffer[16];
- ssize_t nRead;
- do {
- nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
- } while ((nRead == -1 && errno == EINTR) || nRead ==
- zeof(buffer));
- }
因为当其它的线程向应用程序的消息队列加入新的消息时,会向这个管道写入新的内容来通知应用程序主线程有新的消息需要处理了,下面我们分析消息的发送的时候将会看到。
这样,消息的循环过程就分析完了,这部分逻辑还是比较复杂的,它利用Linux系统中的管道(pipe)进程间通信机制来实现消息的等待和处理,不过,了解了这部分内容之后,下面我们分析消息的发送和处理就简单多了。