diff --git a/src/gui/core/looper.cc b/src/gui/core/looper.cc index 1dff1c12..1ea950e7 100755 --- a/src/gui/core/looper.cc +++ b/src/gui/core/looper.cc @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -11,20 +11,19 @@ #define DEBUG_CALLBACKS 0 #if USED_POLL == NOPOLL -#define EPOLLIN 1 -#define EPOLLOUT 4 -#define EPOLLERR 8 -#define EPOLLHUP 0x10 + #define EPOLLIN 1 + #define EPOLLOUT 4 + #define EPOLLERR 8 + #define EPOLLHUP 0x10 #elif USED_POLL==POLL -#define EPOLLIN POLLIN -#define EPOLLOUT POLLOUT -#define EPOLLERR POLLERR -#define EPOLLHUP POLLHUP + #define EPOLLIN POLLIN + #define EPOLLOUT POLLOUT + #define EPOLLERR POLLERR + #define EPOLLHUP POLLHUP #endif /*REF:system/core/libutils/Looper.cpp*/ namespace cdroid{ -static constexpr int EPOLL_SIZE_HINT = 8; // Maximum number of file descriptors for which to retrieve poll events each iteration. static constexpr int EPOLL_MAX_EVENTS = 16; static pthread_once_t gTLSOnce = PTHREAD_ONCE_INIT; @@ -45,21 +44,18 @@ static int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime) return (int)timeoutDelayMillis; } -void Looper::Looper::Request::initEventItem(struct epoll_event* eventItem) const{ - int epollEvents = 0; - if (events & EVENT_INPUT) epollEvents |= EPOLLIN; - if (events & EVENT_OUTPUT)epollEvents |= EPOLLOUT; - - memset(eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union - eventItem->events = epollEvents; - eventItem->data.fd= fd; -} +namespace { + constexpr uint64_t WAKE_EVENT_FD_SEQ = 1; + epoll_event createEpollEvent(uint32_t events, uint64_t seq) { + return {.events = events, .data = {.u64 = seq}}; + } +} Looper* Looper::sMainLooper = nullptr; Looper::Looper(bool allowNonCallbacks) : mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false), mPolling(false), mEpollFd(-1), mEpollRebuildRequired(false), - mNextRequestSeq(0), mResponseIndex(0), mNextMessageUptime(LLONG_MAX) { + mNextRequestSeq(WAKE_EVENT_FD_SEQ+1), mResponseIndex(0), mNextMessageUptime(LLONG_MAX) { mWakeEventFd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); LOGE_IF(mWakeEventFd < 0, "Could not make wake event fd: %s",strerror(errno)); std::lock_guard_l(mLock); @@ -92,7 +88,7 @@ void Looper::threadDestructor(void *st) { } Looper*Looper::getDefault(){ - return getForThread(); + return getMainLooper(); } Looper*Looper::getMainLooper(){ @@ -147,33 +143,30 @@ void Looper::rebuildEpollLocked() { } // Allocate the new epoll instance and register the wake pipe. - mEpollFd = epoll_create(EPOLL_SIZE_HINT); + mEpollFd = epoll_create(EPOLL_CLOEXEC); LOGE_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno)); #endif - struct epoll_event eventItem; - memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union - eventItem.events = EPOLLIN; - eventItem.data.fd = mWakeEventFd; + struct epoll_event wakeEvent = createEpollEvent(EPOLLIN,WAKE_EVENT_FD_SEQ); #if USED_POLL == EPOLL - int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeEventFd, & eventItem); + int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeEventFd, &wakeEvent); LOGE_IF(result != 0, "Could not add wake event fd to epoll instance: %s",strerror(errno)); #endif for (auto it=mRequests.begin();it!=mRequests.end(); it++) { + const SequenceNumber& seq = it->first; const Request& request = it->second; - struct epoll_event eventItem; - request.initEventItem(&eventItem); + epoll_event eventItem =createEpollEvent(request.getEpollEvents(),seq); #if USED_POLL == EPOLL - int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, request.fd, & eventItem); - if (epollResult < 0) { - LOGE("Error adding epoll events for fd %d while rebuilding epoll set: %s",request.fd, strerror(errno)); - } + const int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, request.fd, & eventItem); + LOGE_IF(epollResult<0,"Error adding epoll events for fd %d while rebuilding epoll set: %s",request.fd, strerror(errno)); #endif } } void Looper::scheduleEpollRebuildLocked() { if (!mEpollRebuildRequired) { - LOGD_IF(DEBUG_CALLBACKS,"%p scheduleEpollRebuildLocked - scheduling epoll set rebuild", this); +#if DEBUG_CALLBACKS + LOGD("%p scheduleEpollRebuildLocked - scheduling epoll set rebuild", this); +#endif mEpollRebuildRequired = true; wake(); } @@ -189,7 +182,9 @@ int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outDa int fd = response.request.fd; int events = response.events; void* data = response.request.data; - LOGD_IF(DEBUG_POLL_AND_WAKE,"%p returning signalled identifier %d: fd=%d, events=0x%x, data=%p", this, ident, fd, events, data); +#if DEBUG_POLL_AND_WAKE + LOGD("%p returning signalled identifier %d: fd=%d, events=0x%x, data=%p", this, ident, fd, events, data); +#endif if (outFd != nullptr) *outFd = fd; if (outEvents != nullptr) *outEvents = events; if (outData != nullptr) *outData = data; @@ -197,7 +192,9 @@ int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outDa } } if (result != 0) { - LOGD_IF(DEBUG_POLL_AND_WAKE,"%p returning result %d", this, result); +#if DEBUG_POLL_AND_WAKE + LOGD("%p returning result %d", this, result); +#endif if (outFd != nullptr) *outFd = 0; if (outEvents != nullptr) *outEvents = 0; if (outData != nullptr) *outData = nullptr; @@ -207,118 +204,46 @@ int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outDa } } -int Looper::pollEvents(int timeoutMillis){ - int result = POLL_WAKE; - mResponses.clear(); - mResponseIndex = 0; - mPolling = true; - int eventCount; - struct epoll_event eventItems[EPOLL_MAX_EVENTS]; -#if USED_POLL == EPOLL - eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis); -#elif USED_POLL == POLL - std::vectorpollfds; - for (auto r:mRequests){ - struct pollfd pfd; - pfd.fd=r.second.fd; - pfd.events=r.second.events; - pollfds.push_back(pfd); - } - eventCount = poll(pollfds.data(),pollfds.size(),timeoutMillis); - int j = 0; - for(auto f:pollfds){ - if(f.revents==0)continue; - eventItems[j].data.fd= f.fd; - eventItems[j].events = f.revents; - j++; - } -#endif - // No longer idling. - mPolling = false; - - if (mEpollRebuildRequired) { - mEpollRebuildRequired = false; - rebuildEpollLocked(); - goto Done; - } - - // Check for poll error. - if (eventCount < 0) { - if (errno == EINTR) { - goto Done; - } - LOGW("Poll failed with an unexpected error: %s", strerror(errno)); - result = POLL_ERROR; - goto Done; - } - - // Check for poll timeout. - if (eventCount == 0) { - LOGD_IF(DEBUG_POLL_AND_WAKE,"%p pollOnce - timeout", this); - result = POLL_TIMEOUT; - goto Done; - } - - // Handle all events. - LOGD_IF(DEBUG_POLL_AND_WAKE,"%p handling events from %d fds", this, eventCount); - - for (int i = 0; i < eventCount; i++) { - int fd = eventItems[i].data.fd; - uint32_t epollEvents = eventItems[i].events; - if (fd == mWakeEventFd) { - if (epollEvents & EPOLLIN) { - awoken(); - } else { - LOGW("Ignoring unexpected epoll events 0x%x on wake event fd.", epollEvents); +int Looper::doEventHandlers(){ + int count = 0; + if(mNextMessageUptime>(nsecs_t)SystemClock::uptimeMillis()){ + for(auto it = mHandlers.begin();it != mHandlers.end();){ + MessageHandler*hdl = (*it); + uint32_t eFlags = (*it)->mFlags; + if((eFlags&1)==0){ + hdl->handleIdle(); count++; + eFlags = hdl->mFlags; } - } else { - auto it= mRequests.find(fd); - if (it!=mRequests.end()){ - int events = 0; - if (epollEvents & EPOLLIN) events |= EVENT_INPUT; - if (epollEvents & EPOLLOUT) events |= EVENT_OUTPUT; - if (epollEvents & EPOLLERR) events |= EVENT_ERROR; - if (epollEvents & EPOLLHUP) events |= EVENT_HANGUP; - pushResponse(events, it->second); - } else { - LOGW("Ignoring unexpected epoll events 0x%x on fd %d that is " - "no longer registered.", epollEvents, fd); + if(eFlags&2) delete hdl; + if(eFlags&1){ + it = mHandlers.erase(it); + continue; } - } + it++; + } } - // Invoke all response callbacks. - for (size_t i = 0; i < mResponses.size(); i++) { - Response& response = mResponses.at(i); - if (response.request.ident == POLL_CALLBACK) { - int fd = response.request.fd; - int events = response.events; - void* data = response.request.data; - LOGD_IF(DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS,"%pinvoking fd event callback %p: fd=%d, events=0x%x, data=%p", - this, response.request.callback, fd, events, data); - - // Invoke the callback. Note that the file descriptor may be closed by - // the callback (and potentially even reused) before the function returns so - // we need to be a little careful when removing the file descriptor afterwards. - int callbackResult = response.request.callback->handleEvent(fd, events, data); - if (callbackResult == 0) { - removeFd(fd, response.request.seq); + for(auto it=mEventHandlers.begin();it!=mEventHandlers.end();){ + EventHandler*es=(*it); + uint32_t eFlags = es->mFlags; + if(es&&((eFlags&1)==0)&&(es->checkEvents()>0)){ + es->handleEvents(); count++; + eFlags = es->mFlags;//Maybe EventHandler::handleEvents will destroy itself,recheck the flags + if((eFlags&3)==3) delete es;//make EventHandler::handleEvents can destroy itself + if((eFlags&1)==1){ + it = mEventHandlers.erase(it); + continue; } - - // Clear the callback reference in the response structure promptly because we - // will not clear the response vector itself until the next poll. - //response.request.callback.clear(); - result = POLL_CALLBACK; - } + //EventHandler owned by looper must be freed here + }it++; } -Done: - return result; + return count; } -int Looper::pollInner(int timeoutMillis) { - int result = POLL_WAKE; - LOGD_IF(DEBUG_POLL_AND_WAKE,"%p waiting: timeoutMillis=%d mNextMessageUptime=%lld/%lld", - this,timeoutMillis,mNextMessageUptime,LLONG_MAX); +int Looper::pollInner(int timeoutMillis) { +#if DEBUG_POLL_AND_WAKE + LOGD("%p waiting: timeoutMillis=%d mNextMessageUptime=%lld/%lld",this,timeoutMillis,mNextMessageUptime,LLONG_MAX); +#endif // Adjust the timeout based on when the next message is due. if (timeoutMillis != 0 && mNextMessageUptime != LLONG_MAX) { nsecs_t now = SystemClock::uptimeMillis(); @@ -326,38 +251,77 @@ int Looper::pollInner(int timeoutMillis) { if ( (messageTimeoutMillis >= 0 ) && (timeoutMillis < 0 || messageTimeoutMillis < timeoutMillis)) { timeoutMillis = messageTimeoutMillis; } - LOGD_IF(DEBUG_POLL_AND_WAKE,"%p next message in %lld ns, adjusted timeout:timeoutMillis=%d", - this,mNextMessageUptime - now, timeoutMillis); +#if DEBUG_POLL_AND_WAKE + LOGD("%p next message in %lld ns, adjusted timeout:timeoutMillis=%d",this,mNextMessageUptime - now, timeoutMillis); +#endif } - nsecs_t t1=SystemClock::uptimeMillis(); - if(1||mNextMessageUptime>(nsecs_t)SystemClock::uptimeMillis()){ - doIdleHandlers(); - } - for(auto it=mEventHandlers.begin();it!=mEventHandlers.end();it++){ - EventHandler*es=(*it); - if(es&&((es->mFlags&1)==0)&&(es->checkEvents()>0)){ - es->handleEvents(); - //may be EventHandler::handleEvents will destroy itself,recheck the flags - if((es->mFlags&1)==1) it = mEventHandlers.erase(it); - if((es->mFlags&3)==3) delete es;//make EventHandler::handleEvents can destroy itself - //EventHandler owned by looper must be freed here - } - } - for(auto it=mEventHandlers.begin();it!=mEventHandlers.end();it++){ - EventHandler*es=(*it); - if((es->mFlags&3)==3){ - it = mEventHandlers.erase(it); - delete es;//EventHandler owned by looper must be freed here - } - } - long elapsedMillis = SystemClock::uptimeMillis()-t1; + //Poll + int result = POLL_WAKE; + mResponses.clear(); + mResponseIndex =0; + //We are about to idle + mPolling = true; + struct epoll_event eventItems[EPOLL_MAX_EVENTS]; + const int eventCount = epoll_wait(mEpollFd,eventItems,EPOLL_MAX_EVENTS,timeoutMillis); + //No longer idling. + mPolling = false; // Acquire lock. mLock.lock(); + //Rebuild epoll set if needed. + if(mEpollRebuildRequired){ + mEpollRebuildRequired = false; + rebuildEpollLocked(); + goto Done; + } + //Check fore -poll error + if(eventCount<0){ + if(errno==EINTR)goto Done; + LOGW("Poll failed with an unexpected error: %s", strerror(errno)); + result = POLL_ERROR; + goto Done; + } + //Check for poll timeout + if(eventCount==0){ +#if DEBUG_POLL_AND_WAKE + LOGD("%p pollOnce - timeout",this); +#endif + result = POLL_TIMEOUT; + goto Done; + } + // Handle all events. +#if DEBUG_POLL_AND_WAKE + LOGD("%p pollOnce - handling events from %d fds", this, eventCount); +#endif + for (int i = 0; i < eventCount; i++) { + const SequenceNumber seq = eventItems[i].data.u64; + const uint32_t epollEvents = eventItems[i].events; + if (seq == WAKE_EVENT_FD_SEQ) { + if (epollEvents & EPOLLIN) { + awoken(); + } else { + LOGW("Ignoring unexpected epoll events 0x%x on wake event fd.", epollEvents); + } + } else { + const auto& request_it = mRequests.find(seq); + if (request_it != mRequests.end()) { + const auto& request = request_it->second; + int events = 0; + if (epollEvents & EPOLLIN) events |= EVENT_INPUT; + if (epollEvents & EPOLLOUT) events |= EVENT_OUTPUT; + if (epollEvents & EPOLLERR) events |= EVENT_ERROR; + if (epollEvents & EPOLLHUP) events |= EVENT_HANGUP; + mResponses.push_back({.seq = seq, .events = events, .request = request}); + } else { + LOGW("Ignoring unexpected epoll events 0x%x for sequence number %lld" + " that is no longer registered.",epollEvents, seq); + } + } + } +Done: ; // Invoke pending message callbacks. mNextMessageUptime = LLONG_MAX; - LOGD_IF(DEBUG_CALLBACKS,"mMessageEnvelopes.size=%d",mMessageEnvelopes.size()); while (mMessageEnvelopes.size() != 0) { nsecs_t now = SystemClock::uptimeMillis(); const MessageEnvelope& messageEnvelope = mMessageEnvelopes.front(); @@ -372,9 +336,9 @@ int Looper::pollInner(int timeoutMillis) { mMessageEnvelopes.pop_front(); mSendingMessage = true; mLock.unlock(); - - LOGD_IF(DEBUG_POLL_AND_WAKE||DEBUG_CALLBACKS,"%psending message: handler=%p, what=%d", - this, handler, message.what); +#if DEBUG_POLL_AND_WAKE||DEBUG_CALLBACKS + LOGD("%psending message: handler=%p, what=%d",this, handler, message.what); +#endif if(message.callback) message.callback(); else @@ -390,9 +354,36 @@ int Looper::pollInner(int timeoutMillis) { break; } } - pollEvents(timeoutMillis>elapsedMillis?(timeoutMillis-elapsedMillis):0); + //Release Lock. mLock.unlock(); + //EventHandlers; + doEventHandlers(); + //Invoke all response callbacks. + for (size_t i = 0; i < mResponses.size(); i++) { + Response& response = mResponses.at(i);//editItemAt(i); + if (response.request.ident == POLL_CALLBACK) { + const int fd = response.request.fd; + const int events = response.events; + void* data = response.request.data; +#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS + LOGD("%p ~ pollOnce - invoking fd event callback %p: fd=%d, events=0x%x, data=%p", + this, response.request.callback, fd, events, data); +#endif + // Invoke the callback. Note that the file descriptor may be closed by + // the callback (and potentially even reused) before the function returns so + // we need to be a little careful when removing the file descriptor afterwards. + int callbackResult = response.request.callback->handleEvent(fd, events, data); + if (callbackResult == 0) { + std::lock_guard _l(mLock); + removeSequenceNumberLocked(response.seq); + } + // Clear the callback reference in the response structure promptly because we + // will not clear the response vector itself until the next poll. + response.request.callback = nullptr;//clear(); + result = POLL_CALLBACK; + } + } return result; } @@ -420,19 +411,6 @@ int Looper::pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outDat } } -void Looper::doIdleHandlers(){ - for(auto it = mHandlers.begin();it != mHandlers.end();it++){ - const int flags = (*it)->mFlags; - if(flags&1){ - LOGD("delete Handler %p",(*it)); - if(flags&2)delete *it; - it = mHandlers.erase(it); - continue; - } - (*it)->handleIdle(); - } -} - //TEMP_FAILURE_RETRY defined in #ifndef TEMP_FAILURE_RETRY #define TEMP_FAILURE_RETRY(expression) \ @@ -468,8 +446,9 @@ int Looper::addFd(int fd, int ident, int events, Looper_callbackFunc callback, v } int Looper::addFd(int fd, int ident, int events,const LooperCallback* callback, void* data) { - LOGD_IF(DEBUG_CALLBACKS,"%p addFd - fd=%d, ident=%d, events=0x%x, callback=%p, data=%p", this, fd, ident, events, callback, data); - +#if DEBUG_CALLBACKS + LOGD("%p addFd - fd=%d, ident=%d, events=0x%x, callback=%p, data=%p", this, fd, ident, events, callback, data); +#endif if (callback == nullptr) { if (! mAllowNonCallbacks) { LOGE("Invalid attempt to set NULL callback but not allowed for this looper."); @@ -486,6 +465,8 @@ int Looper::addFd(int fd, int ident, int events,const LooperCallback* callback, { // acquire lock std::lock_guard _l(mLock); + if (mNextRequestSeq == WAKE_EVENT_FD_SEQ) mNextRequestSeq++; + const SequenceNumber seq = mNextRequestSeq++; Request request; request.fd = fd; @@ -496,19 +477,18 @@ int Looper::addFd(int fd, int ident, int events,const LooperCallback* callback, request.data = data; if (mNextRequestSeq == -1) mNextRequestSeq = 0; // reserve sequence number -1 - struct epoll_event eventItem; - request.initEventItem(&eventItem); - - auto itfd = mRequests.find(fd);//indexOfKey(fd); - if (itfd == mRequests.end()) { + epoll_event eventItem = createEpollEvent(request.getEpollEvents(),seq); + auto seq_it = mSequenceNumberByFd.find(fd); + if (seq_it == mSequenceNumberByFd.end()) { #if USED_POLL ==EPOLL - int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem); + int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem); if (epollResult < 0) { LOGE("Error adding epoll events for fd %d: %s", fd, strerror(errno)); return -1; } #endif - mRequests[fd]=request;//.add(fd, request); + mRequests.emplace(seq, request); + mSequenceNumberByFd.emplace(fd,seq); } else { #if USED_POLL ==EPOLL int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, & eventItem); @@ -527,8 +507,10 @@ int Looper::addFd(int fd, int ident, int events,const LooperCallback* callback, // now unable to remove since its file descriptor is no longer valid. // No such problem would have occurred if we were using the poll system // call instead, but that approach carries others disadvantages. - LOGD_IF(DEBUG_CALLBACKS,"%p addFd - EPOLL_CTL_MOD failed due to file descriptor " +#if DEBUG_CALLBACKS + LOGD("%p addFd - EPOLL_CTL_MOD failed due to file descriptor " "being recycled, falling back on EPOLL_CTL_ADD: %s", this, strerror(errno)); +#endif epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem); if (epollResult < 0) { LOGE("Error modifying or adding epoll events for fd %d: %s", fd, strerror(errno)); @@ -541,19 +523,70 @@ int Looper::addFd(int fd, int ident, int events,const LooperCallback* callback, } } #endif - itfd->second=request;//mRequests.replaceValueAt(requestIndex, request); + const SequenceNumber oldSeq = seq_it->second; + mRequests.erase(oldSeq); + mRequests.emplace(seq,request); + seq_it->second = seq; } } // release lock return 1; } int Looper::removeFd(int fd) { - return removeFd(fd, -1); + std::lock_guard _l(mLock); + const auto it = mSequenceNumberByFd.find(fd); + if(it == mSequenceNumberByFd.end() ) return 0; + return removeSequenceNumberLocked(it->second); +} + +int Looper::removeSequenceNumberLocked(SequenceNumber seq){ + const auto& request_it = mRequests.find(seq); + if (request_it == mRequests.end()) { + return 0; + } + const int fd = request_it->second.fd; + LOGD_IF(DEBUG_CALLBACKS,"%p ~ removeFd - fd=%d, seq=%u", this, fd, seq); + + // Always remove the FD from the request map even if an error occurs while + // updating the epoll set so that we avoid accidentally leaking callbacks. + mRequests.erase(request_it); + mSequenceNumberByFd.erase(fd); + + int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, nullptr); + if (epollResult < 0) { + if (errno == EBADF || errno == ENOENT) { + // Tolerate EBADF or ENOENT because it means that the file descriptor was closed + // before its callback was unregistered. This error may occur naturally when a + // callback has the side-effect of closing the file descriptor before returning and + // unregistering itself. + // + // Unfortunately due to kernel limitations we need to rebuild the epoll + // set from scratch because it may contain an old file handle that we are + // now unable to remove since its file descriptor is no longer valid. + // No such problem would have occurred if we were using the poll system + // call instead, but that approach carries other disadvantages. +#if DEBUG_CALLBACKS + LOGD("%p ~ removeFd - EPOLL_CTL_DEL failed due to file descriptor " + "being closed: %s",this, strerror(errno)); +#endif + scheduleEpollRebuildLocked(); + } else { + // Some other error occurred. This is really weird because it means + // our list of callbacks got out of sync with the epoll set somehow. + // We defensively rebuild the epoll set to avoid getting spurious + // notifications with nowhere to go. + LOGE("Error removing epoll events for fd %d: %s", fd, strerror(errno)); + scheduleEpollRebuildLocked(); + return -1; + } + } + return 1; } int Looper::removeFd(int fd, int seq) { - LOGD_IF(DEBUG_CALLBACKS,"%p removeFd - fd=%d, seq=%d", this, fd, seq); - +#if DEBUG_CALLBACKS + LOGD("%p removeFd - fd=%d, seq=%d", this, fd, seq); +#endif { // acquire lock std::lock_guard _l(mLock); auto itr = mRequests.find(fd);//indexOfKey(fd); @@ -563,7 +596,9 @@ int Looper::removeFd(int fd, int seq) { // Check the sequence number if one was given. if ( (seq != -1) && (itr->second.seq != seq) ) { - LOGD_IF(DEBUG_CALLBACKS,"%p removeFd - sequence number mismatch, oldSeq=%d", this, itr->second.seq); +#if DEBUG_CALLBACKS + LOGD("%p removeFd - sequence number mismatch, oldSeq=%d", this, itr->second.seq); +#endif return 0; } @@ -585,8 +620,10 @@ int Looper::removeFd(int fd, int seq) { // now unable to remove since its file descriptor is no longer valid. // No such problem would have occurred if we were using the poll system // call instead, but that approach carries others disadvantages. - LOGD_IF(DEBUG_CALLBACKS,"%p removeFd - EPOLL_CTL_DEL failed due to file descriptor " +#if DEBUG_CALLBACKS + LOGD("%p removeFd - EPOLL_CTL_DEL failed due to file descriptor " "being closed: %s", this, strerror(errno)); +#endif scheduleEpollRebuildLocked(); } else { // Some other error occurred. This is really weird because it means @@ -616,8 +653,9 @@ void Looper::sendMessageDelayed(nsecs_t uptimeDelay, const MessageHandler* handl void Looper::sendMessageAtTime(nsecs_t uptime, const MessageHandler* handler, const Message& message) { - LOGD_IF(DEBUG_CALLBACKS,"%p sendMessageAtTime - uptime=%lld, handler=%p, what=%d", this, uptime, handler, message.what); - +#if DEBUG_CALLBACKS + LOGD("%p sendMessageAtTime - uptime=%lld, handler=%p, what=%d", this, uptime, handler, message.what); +#endif size_t i = 0; { // acquire lock std::lock_guard _l(mLock); @@ -649,9 +687,7 @@ void Looper::addHandler(MessageHandler*handler){ void Looper::removeHandler(MessageHandler*handler){ for(auto it = mHandlers.begin();it != mHandlers.end();it++){ if( (*it) == handler){ - handler->mFlags |= 1; - if((handler->mFlags&2)==0)//handler is not owned by looper,erase at once - mHandlers.erase(it); + handler->mFlags |= 1;//set Erase Flags.removed in doEventHandlers break; } } @@ -664,16 +700,16 @@ void Looper::addEventHandler(const EventHandler*handler){ void Looper::removeEventHandler(const EventHandler*handler){ for(auto it = mEventHandlers.begin();it != mEventHandlers.end();it++){ if( (*it) ==handler){ - (*it)->mFlags |=1;//set removed flags - if((handler->mFlags&2)==0)//handler is not owned by looper,erase at once - mEventHandlers.erase(it); + (*it)->mFlags |=1;//set removed flags,removed in doEventHandlers break; } } } void Looper::removeMessages(const MessageHandler* handler) { - LOGD_IF(DEBUG_CALLBACKS,"%p removeMessages - handler=%p", this, handler); +#if DEBUG_CALLBACKS + LOGD("%p removeMessages - handler=%p", this, handler); +#endif { // acquire lock std::lock_guard _l(mLock); @@ -687,7 +723,9 @@ void Looper::removeMessages(const MessageHandler* handler) { } void Looper::removeMessages(const MessageHandler* handler, int what) { - LOGD_IF(DEBUG_CALLBACKS,"%p removeMessages - handler=%p, what=%d size=%d", this, handler, what,mMessageEnvelopes.size()); +#if DEBUG_CALLBACKS + LOGD("%p removeMessages - handler=%p, what=%d size=%d", this, handler, what,mMessageEnvelopes.size()); +#endif { // acquire lock std::lock_guard _l(mLock); @@ -714,6 +752,13 @@ bool Looper::isPolling() const { return mPolling; } +uint32_t Looper::Request::getEpollEvents() const{ + uint32_t epollEvents = 0; + if (events & EVENT_INPUT) epollEvents |= EPOLLIN; + if (events & EVENT_OUTPUT)epollEvents |= EPOLLOUT; + return epollEvents; +} + LooperCallback::~LooperCallback(){ } diff --git a/src/gui/core/looper.h b/src/gui/core/looper.h index adff362b..3b84794a 100755 --- a/src/gui/core/looper.h +++ b/src/gui/core/looper.h @@ -24,7 +24,7 @@ struct epoll_event{ #include #endif -#include +#include #include #include #include @@ -52,7 +52,7 @@ private: class MessageHandler{ private: - int mFlags; + uint32_t mFlags; friend class Looper; protected: MessageHandler(); @@ -65,7 +65,7 @@ public: class EventHandler{ protected: - int mFlags; + uint32_t mFlags; friend class Looper; protected: EventHandler(); @@ -78,6 +78,7 @@ public: class Looper{ private: + using SequenceNumber = uint64_t; struct Request { int fd; int ident; @@ -85,9 +86,10 @@ private: int seq; LooperCallback* callback; void* data; - void initEventItem(struct epoll_event* eventItem) const; + uint32_t getEpollEvents() const; }; struct Response { + SequenceNumber seq; int events; Request request; }; @@ -120,8 +122,9 @@ private: bool mEpollRebuildRequired; // guarded by mLock // Locked list of file descriptor monitoring requests. - std::map mRequests; // guarded by mLock - int mNextRequestSeq; + std::unordered_map mRequests; //guarded by mLock + std::unordered_mapmSequenceNumberByFd; //guarded by mLock + SequenceNumber mNextRequestSeq; // This state is only used privately by pollOnce and does not require a lock since // it runs on a single thread. @@ -130,14 +133,14 @@ private: nsecs_t mNextMessageUptime; private: static Looper*sMainLooper; - int pollEvents(int timeoutMillis); + int doEventHandlers(); int pollInner(int timeoutMillis); + int removeSequenceNumberLocked(SequenceNumber seq); int removeFd(int fd, int seq); void awoken(); void pushResponse(int events, const Request& request); void rebuildEpollLocked(); void scheduleEpollRebuildLocked(); - void doIdleHandlers(); static void initTLSKey(); static void threadDestructor(void*); protected: @@ -189,12 +192,12 @@ public: void removeMessages(const MessageHandler* handler); void removeMessages(const MessageHandler* handler, int what); void removeCallbacks(const MessageHandler* handler,Runnable r); + bool isPolling() const; + void addHandler(MessageHandler*); void removeHandler(MessageHandler*); void addEventHandler(const EventHandler*handler); void removeEventHandler(const EventHandler*handler); - bool isPolling() const; - }; } #endif diff --git a/tests/gui/looper_tests.cc b/tests/gui/looper_tests.cc index 27b3ca96..c0f8385e 100755 --- a/tests/gui/looper_tests.cc +++ b/tests/gui/looper_tests.cc @@ -13,14 +13,24 @@ #include class LOOPER:public testing::Test{ - - public : - virtual void SetUp(){ - } - virtual void TearDown(){ - LOGD("\r\n\r\n"); - } +protected: + static Looper*mLooper; +public : + static void SetUpTestCase(){ + Looper::prepare(false); + mLooper=Looper::getMainLooper(); + if(mLooper==nullptr)Looper::prepareMainLooper(); + mLooper=Looper::myLooper(); + } + static void TearDownCase(){ + } + virtual void SetUp(){ + } + virtual void TearDown(){ + LOGD("\r\n\r\n"); + } }; +Looper*LOOPER::mLooper=nullptr; class MyRunner{ public: @@ -74,49 +84,75 @@ public: }; TEST_F(LOOPER,pollonce){ - Looper loop(false); int64_t t1=SystemClock::uptimeMillis(); - loop.pollOnce(1000); + mLooper->pollOnce(1000); int64_t t2=SystemClock::uptimeMillis(); ASSERT_TRUE((t2-t1)>=1000&&(t2-t2)<1005); } TEST_F(LOOPER,sendMessage){ - Looper loop(false); Message msg(100); int processed=0; TestHandler ft; - loop.sendMessage(&ft,msg); - loop.pollOnce(10); + mLooper->sendMessage(&ft,msg); + mLooper->pollOnce(10); ASSERT_EQ(ft.getCount(),1); } TEST_F(LOOPER,sendMessageDelay){ - Looper loop(false); Message msg(100); TestHandler ft; int64_t t1=SystemClock::uptimeMillis(); - loop.sendMessageDelayed(1000,&ft,msg); - while(!ft.getCount()) loop.pollOnce(10); + mLooper->sendMessageDelayed(1000,&ft,msg); + while(!ft.getCount()) mLooper->pollOnce(10); int64_t t2=SystemClock::uptimeMillis(); ASSERT_TRUE((t2-t1)>=1000&&(t2-t2)<1005); } TEST_F(LOOPER,removeMessage){ - Looper loop(false); Message msg(100),msg2(200); TestHandler ft; int64_t t2,t1=SystemClock::uptimeMillis(); - loop.sendMessageDelayed(1000,&ft,msg); - loop.sendMessageDelayed(1000,&ft,msg2); + mLooper->sendMessageDelayed(1000,&ft,msg); + mLooper->sendMessageDelayed(1000,&ft,msg2); t2=t1; - loop.removeMessages(&ft,100); + mLooper->removeMessages(&ft,100); while(t2-t1<1100){ - loop.pollOnce(10); + mLooper->pollOnce(10); t2=SystemClock::uptimeMillis(); } ASSERT_EQ(ft.getCount(),1); } +class SelfDestroyHandler:public MessageHandler{ +private: + Looper*mLooper; +public: + SelfDestroyHandler(Looper*lp){mLooper=lp;} + void handleMessage(Message&msg)override{ + mLooper->removeMessages(this); + } +}; +class SelfDestroyEventHandler:public EventHandler{ +private: + Looper*mLooper; +public: + SelfDestroyEventHandler(Looper*lp){mLooper=lp;} + int checkEvents()override{return 1;}; + int handleEvents()override{ + mLooper->removeEventHandler(this); + return 1; + } +}; +TEST_F(LOOPER,removeHandler){ + SelfDestroyHandler*sd=new SelfDestroyHandler(mLooper); + SelfDestroyEventHandler*se=new SelfDestroyEventHandler(mLooper); + Message msg(100); + mLooper->addEventHandler(se); + mLooper->sendMessageDelayed(10,sd,msg); + + mLooper->pollOnce(100); + LOGD("==="); +} class TestRunner:public Runnable{ private: @@ -153,28 +189,13 @@ TEST_F(LOOPER,eventhandler){ ASSERT_FALSE(rc); } -TEST_F(LOOPER,loop){ - Looper loop(false); - //UIEventSource*handler=new UIEventSource(nullptr,nullptr); - //loop.addEventHandler(handler); - Handler handler; - TestRunner run; - int count=0; - ASSERT_TRUE((bool)run); - ASSERT_FALSE(run==nullptr); - ASSERT_TRUE(run!=nullptr); - run(); - handler.postDelayed(run,10); - while(1)loop.pollAll(100); -} - class MyHandler:public Handler{ public: + int count=0; void handleMessage(Message&msg)override{ - LOGD("rcv msg %d",msg.what); + count++; } void handleIdle(){ - LOGD("idle"); } ~MyHandler(){ LOGD("MyHandler destroied!"); @@ -183,36 +204,38 @@ public: TEST_F(LOOPER,handler){ Looper *loop= Looper::getMainLooper(); - Handler *handler=new MyHandler(); + MyHandler *handler=new MyHandler(); handler->sendEmptyMessage(1); handler->sendEmptyMessageDelayed(2,20); Runnable cbk([](){LOGD("---");}); handler->postDelayed(cbk,30); int count=0; while(count++<3) - loop->pollAll(10); - loop->removeHandler(handler); - while(count++<6)loop->pollAll(10); + mLooper->pollAll(10); + mLooper->removeHandler(handler); + while(count++<6)mLooper->pollAll(10); + delete handler; + ASSERT_EQ(handler->count,2); } TEST_F(LOOPER,asyncmsg){ - Looper *loop= Looper::getMainLooper(); - Handler *handler=new MyHandler(); - handler->sendEmptyMessage(1); - handler->sendEmptyMessageDelayed(2,20); + MyHandler *handler=new MyHandler(); + handler->sendEmptyMessage(0); + handler->sendEmptyMessageDelayed(0,20); Runnable cbk([](){LOGD("---");}); handler->postDelayed(cbk,30); + Message msg; std::thread th([&](){ - Message msg; - msg.what=0; - while(1){ - loop->sendMessageDelayed(10,handler,msg); - msg.what++; - usleep(100); - } + msg.what=0; + while(msg.what++<10000){ + mLooper->sendMessageDelayed(10,handler,msg); + usleep(100); + } }); th.detach(); - while(1)loop->pollAll(10); + int count=0; + while(count++<200)mLooper->pollAll(10); + ASSERT_EQ(handler->count,10002); } static void ms2timespec(int ms, struct timespec *ts){ @@ -226,18 +249,17 @@ static int fdcallback(int fd, int events, void* data){ struct timespec cur; clock_gettime(CLOCK_MONOTONIC,&cur); if(events&Looper::EVENT_INPUT) - ::read(fd, &count, sizeof(uint64_t)); + ::read(fd, &count, sizeof(uint64_t)); if(*loops>20){ - struct itimerspec new_value={{0,0},{0,0}}; - timerfd_settime(fd,0,&new_value, NULL); - Looper::getMainLooper()->removeFd(fd); + struct itimerspec new_value={{0,0},{0,0}}; + timerfd_settime(fd,0,&new_value, NULL); + Looper::getMainLooper()->removeFd(fd); } return 1; } TEST_F(LOOPER,timerfd){ #define INTERVAL 200 //ms - Looper*loop= Looper::getMainLooper(); int loops=0; struct itimerspec new_value={{0,0},{0,0}}; ms2timespec(INTERVAL,&new_value.it_value); @@ -245,8 +267,9 @@ TEST_F(LOOPER,timerfd){ int fd=timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC); int rc=timerfd_settime(fd, 0/*TFD_TIMER_ABSTIME*/, &new_value,NULL); - loop->addFd(fd,0,Looper::EVENT_INPUT,fdcallback,&loops); - while(1)loop->pollAll(10); + mLooper->addFd(fd,0,Looper::EVENT_INPUT,fdcallback,&loops); + + while(1)mLooper->pollAll(10); } TEST_F(LOOPER,timerfd2){