mirror of
https://gitee.com/houstudio/Cdroid.git
synced 2024-11-29 18:59:14 +08:00
upgrade Looper to android14,add some looper testcase
This commit is contained in:
parent
0f72981397
commit
d794129bc7
@ -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(){
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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){
|
||||
|
Loading…
Reference in New Issue
Block a user