upgrade Looper to android14,add some looper testcase

This commit is contained in:
侯歌 2024-08-02 14:22:46 +08:00
parent 0f72981397
commit d794129bc7
3 changed files with 349 additions and 278 deletions

View File

@ -1,4 +1,4 @@
#include <looper.h>
#include <core/looper.h>
#include <unistd.h>
#include <string.h>
#include <sys/eventfd.h>
@ -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<std::recursive_mutex>_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::vector<struct pollfd>pollfds;
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<std::recursive_mutex> _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 <unistd.h>
#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<std::recursive_mutex> _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<std::recursive_mutex> _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<std::recursive_mutex> _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<std::recursive_mutex> _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<std::recursive_mutex> _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<std::recursive_mutex> _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(){
}

View File

@ -24,7 +24,7 @@ struct epoll_event{
#include <sys/epoll.h>
#endif
#include <map>
#include <unordered_map>
#include <vector>
#include <mutex>
#include <list>
@ -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<int, Request> mRequests; // guarded by mLock
int mNextRequestSeq;
std::unordered_map<SequenceNumber, Request> mRequests; //guarded by mLock
std::unordered_map<int/*fd*/,SequenceNumber>mSequenceNumberByFd; //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

View File

@ -13,14 +13,24 @@
#include <time.h>
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){