diff options
Diffstat (limited to 'libutils')
-rw-r--r-- | libutils/Android.mk | 6 | ||||
-rw-r--r-- | libutils/BlobCache.cpp | 19 | ||||
-rw-r--r-- | libutils/LinearAllocator.cpp | 227 | ||||
-rw-r--r-- | libutils/Looper.cpp | 234 |
4 files changed, 186 insertions, 300 deletions
diff --git a/libutils/Android.mk b/libutils/Android.mk index e9c5f89..40cd31e 100644 --- a/libutils/Android.mk +++ b/libutils/Android.mk @@ -16,11 +16,9 @@ LOCAL_PATH:= $(call my-dir) commonSources:= \ BasicHashtable.cpp \ - BlobCache.cpp \ CallStack.cpp \ FileMap.cpp \ JenkinsHash.cpp \ - LinearAllocator.cpp \ LinearTransform.cpp \ Log.cpp \ NativeHandle.cpp \ @@ -75,6 +73,7 @@ include $(CLEAR_VARS) # we have the common sources, plus some device-specific stuff LOCAL_SRC_FILES:= \ $(commonSources) \ + BlobCache.cpp \ Looper.cpp \ Trace.cpp @@ -84,7 +83,8 @@ endif LOCAL_CFLAGS += -Werror LOCAL_STATIC_LIBRARIES := \ - libcutils + libcutils \ + libc LOCAL_SHARED_LIBRARIES := \ libbacktrace \ diff --git a/libutils/BlobCache.cpp b/libutils/BlobCache.cpp index 0ea09cf..126995b 100644 --- a/libutils/BlobCache.cpp +++ b/libutils/BlobCache.cpp @@ -25,13 +25,15 @@ #include <utils/Errors.h> #include <utils/Log.h> +#include <cutils/properties.h> + namespace android { // BlobCache::Header::mMagicNumber value static const uint32_t blobCacheMagic = ('_' << 24) + ('B' << 16) + ('b' << 8) + '$'; // BlobCache::Header::mBlobCacheVersion value -static const uint32_t blobCacheVersion = 2; +static const uint32_t blobCacheVersion = 3; // BlobCache::Header::mDeviceVersion value static const uint32_t blobCacheDeviceVersion = 1; @@ -165,7 +167,7 @@ static inline size_t align4(size_t size) { } size_t BlobCache::getFlattenedSize() const { - size_t size = align4(sizeof(Header)); + size_t size = align4(sizeof(Header) + PROPERTY_VALUE_MAX); for (size_t i = 0; i < mCacheEntries.size(); i++) { const CacheEntry& e(mCacheEntries[i]); sp<Blob> keyBlob = e.getKey(); @@ -187,10 +189,13 @@ status_t BlobCache::flatten(void* buffer, size_t size) const { header->mBlobCacheVersion = blobCacheVersion; header->mDeviceVersion = blobCacheDeviceVersion; header->mNumEntries = mCacheEntries.size(); + char buildId[PROPERTY_VALUE_MAX]; + header->mBuildIdLength = property_get("ro.build.id", buildId, ""); + memcpy(header->mBuildId, buildId, header->mBuildIdLength); // Write cache entries uint8_t* byteBuffer = reinterpret_cast<uint8_t*>(buffer); - off_t byteOffset = align4(sizeof(Header)); + off_t byteOffset = align4(sizeof(Header) + header->mBuildIdLength); for (size_t i = 0; i < mCacheEntries.size(); i++) { const CacheEntry& e(mCacheEntries[i]); sp<Blob> keyBlob = e.getKey(); @@ -239,15 +244,19 @@ status_t BlobCache::unflatten(void const* buffer, size_t size) { ALOGE("unflatten: bad magic number: %" PRIu32, header->mMagicNumber); return BAD_VALUE; } + char buildId[PROPERTY_VALUE_MAX]; + int len = property_get("ro.build.id", buildId, ""); if (header->mBlobCacheVersion != blobCacheVersion || - header->mDeviceVersion != blobCacheDeviceVersion) { + header->mDeviceVersion != blobCacheDeviceVersion || + len != header->mBuildIdLength || + strncmp(buildId, header->mBuildId, len)) { // We treat version mismatches as an empty cache. return OK; } // Read cache entries const uint8_t* byteBuffer = reinterpret_cast<const uint8_t*>(buffer); - off_t byteOffset = align4(sizeof(Header)); + off_t byteOffset = align4(sizeof(Header) + header->mBuildIdLength); size_t numEntries = header->mNumEntries; for (size_t i = 0; i < numEntries; i++) { if (byteOffset + sizeof(EntryHeader) > size) { diff --git a/libutils/LinearAllocator.cpp b/libutils/LinearAllocator.cpp deleted file mode 100644 index 8b90696..0000000 --- a/libutils/LinearAllocator.cpp +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright 2012, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#define LOG_TAG "LinearAllocator" -#define LOG_NDEBUG 1 - -#include <stdlib.h> -#include <utils/LinearAllocator.h> -#include <utils/Log.h> - - -// The ideal size of a page allocation (these need to be multiples of 8) -#define INITIAL_PAGE_SIZE ((size_t)4096) // 4kb -#define MAX_PAGE_SIZE ((size_t)131072) // 128kb - -// The maximum amount of wasted space we can have per page -// Allocations exceeding this will have their own dedicated page -// If this is too low, we will malloc too much -// Too high, and we may waste too much space -// Must be smaller than INITIAL_PAGE_SIZE -#define MAX_WASTE_SIZE ((size_t)1024) - -#if ALIGN_DOUBLE -#define ALIGN_SZ (sizeof(double)) -#else -#define ALIGN_SZ (sizeof(int)) -#endif - -#define ALIGN(x) ((x + ALIGN_SZ - 1 ) & ~(ALIGN_SZ - 1)) -#define ALIGN_PTR(p) ((void*)(ALIGN((size_t)p))) - -#if LOG_NDEBUG -#define ADD_ALLOCATION(size) -#define RM_ALLOCATION(size) -#else -#include <utils/Thread.h> -#include <utils/Timers.h> -static size_t s_totalAllocations = 0; -static nsecs_t s_nextLog = 0; -static android::Mutex s_mutex; - -static void _logUsageLocked() { - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - if (now > s_nextLog) { - s_nextLog = now + milliseconds_to_nanoseconds(10); - ALOGV("Total memory usage: %zu kb", s_totalAllocations / 1024); - } -} - -static void _addAllocation(size_t size) { - android::AutoMutex lock(s_mutex); - s_totalAllocations += size; - _logUsageLocked(); -} - -#define ADD_ALLOCATION(size) _addAllocation(size); -#define RM_ALLOCATION(size) _addAllocation(-size); -#endif - -#define min(x,y) (((x) < (y)) ? (x) : (y)) - -namespace android { - -class LinearAllocator::Page { -public: - Page* next() { return mNextPage; } - void setNext(Page* next) { mNextPage = next; } - - Page() - : mNextPage(0) - {} - - void* operator new(size_t /*size*/, void* buf) { return buf; } - - void* start() { - return (void*) (((size_t)this) + sizeof(Page)); - } - - void* end(int pageSize) { - return (void*) (((size_t)start()) + pageSize); - } - -private: - Page(const Page& /*other*/) {} - Page* mNextPage; -}; - -LinearAllocator::LinearAllocator() - : mPageSize(INITIAL_PAGE_SIZE) - , mMaxAllocSize(MAX_WASTE_SIZE) - , mNext(0) - , mCurrentPage(0) - , mPages(0) - , mTotalAllocated(0) - , mWastedSpace(0) - , mPageCount(0) - , mDedicatedPageCount(0) {} - -LinearAllocator::~LinearAllocator(void) { - Page* p = mPages; - while (p) { - Page* next = p->next(); - p->~Page(); - free(p); - RM_ALLOCATION(mPageSize); - p = next; - } -} - -void* LinearAllocator::start(Page* p) { - return ALIGN_PTR(((size_t*)p) + sizeof(Page)); -} - -void* LinearAllocator::end(Page* p) { - return ((char*)p) + mPageSize; -} - -bool LinearAllocator::fitsInCurrentPage(size_t size) { - return mNext && ((char*)mNext + size) <= end(mCurrentPage); -} - -void LinearAllocator::ensureNext(size_t size) { - if (fitsInCurrentPage(size)) return; - - if (mCurrentPage && mPageSize < MAX_PAGE_SIZE) { - mPageSize = min(MAX_PAGE_SIZE, mPageSize * 2); - mPageSize = ALIGN(mPageSize); - } - mWastedSpace += mPageSize; - Page* p = newPage(mPageSize); - if (mCurrentPage) { - mCurrentPage->setNext(p); - } - mCurrentPage = p; - if (!mPages) { - mPages = mCurrentPage; - } - mNext = start(mCurrentPage); -} - -void* LinearAllocator::alloc(size_t size) { - size = ALIGN(size); - if (size > mMaxAllocSize && !fitsInCurrentPage(size)) { - ALOGV("Exceeded max size %zu > %zu", size, mMaxAllocSize); - // Allocation is too large, create a dedicated page for the allocation - Page* page = newPage(size); - mDedicatedPageCount++; - page->setNext(mPages); - mPages = page; - if (!mCurrentPage) - mCurrentPage = mPages; - return start(page); - } - ensureNext(size); - void* ptr = mNext; - mNext = ((char*)mNext) + size; - mWastedSpace -= size; - return ptr; -} - -void LinearAllocator::rewindIfLastAlloc(void* ptr, size_t allocSize) { - // Don't bother rewinding across pages - allocSize = ALIGN(allocSize); - if (ptr >= start(mCurrentPage) && ptr < end(mCurrentPage) - && ptr == ((char*)mNext - allocSize)) { - mTotalAllocated -= allocSize; - mWastedSpace += allocSize; - mNext = ptr; - } -} - -LinearAllocator::Page* LinearAllocator::newPage(size_t pageSize) { - pageSize = ALIGN(pageSize + sizeof(LinearAllocator::Page)); - ADD_ALLOCATION(pageSize); - mTotalAllocated += pageSize; - mPageCount++; - void* buf = malloc(pageSize); - return new (buf) Page(); -} - -static const char* toSize(size_t value, float& result) { - if (value < 2000) { - result = value; - return "B"; - } - if (value < 2000000) { - result = value / 1024.0f; - return "KB"; - } - result = value / 1048576.0f; - return "MB"; -} - -void LinearAllocator::dumpMemoryStats(const char* prefix) { - float prettySize; - const char* prettySuffix; - prettySuffix = toSize(mTotalAllocated, prettySize); - ALOGD("%sTotal allocated: %.2f%s", prefix, prettySize, prettySuffix); - prettySuffix = toSize(mWastedSpace, prettySize); - ALOGD("%sWasted space: %.2f%s (%.1f%%)", prefix, prettySize, prettySuffix, - (float) mWastedSpace / (float) mTotalAllocated * 100.0f); - ALOGD("%sPages %zu (dedicated %zu)", prefix, mPageCount, mDedicatedPageCount); -} - -}; // namespace android diff --git a/libutils/Looper.cpp b/libutils/Looper.cpp index 9a2dd6c..5b0ff3a 100644 --- a/libutils/Looper.cpp +++ b/libutils/Looper.cpp @@ -20,6 +20,8 @@ #include <unistd.h> #include <fcntl.h> #include <limits.h> +#include <inttypes.h> +#include <sys/eventfd.h> namespace android { @@ -68,41 +70,20 @@ static pthread_key_t gTLSKey = 0; Looper::Looper(bool allowNonCallbacks) : mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false), - mResponseIndex(0), mNextMessageUptime(LLONG_MAX) { - int wakeFds[2]; - int result = pipe(wakeFds); - LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno); + mPolling(false), mEpollFd(-1), mEpollRebuildRequired(false), + mNextRequestSeq(0), mResponseIndex(0), mNextMessageUptime(LLONG_MAX) { + mWakeEventFd = eventfd(0, EFD_NONBLOCK); + LOG_ALWAYS_FATAL_IF(mWakeEventFd < 0, "Could not make wake event fd. errno=%d", errno); - mWakeReadPipeFd = wakeFds[0]; - mWakeWritePipeFd = wakeFds[1]; - - result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK); - LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d", - errno); - - result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK); - LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d", - errno); - - mIdling = false; - - // Allocate the epoll instance and register the wake pipe. - mEpollFd = epoll_create(EPOLL_SIZE_HINT); - LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance. errno=%d", errno); - - struct epoll_event eventItem; - memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union - eventItem.events = EPOLLIN; - eventItem.data.fd = mWakeReadPipeFd; - result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, & eventItem); - LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d", - errno); + AutoMutex _l(mLock); + rebuildEpollLocked(); } Looper::~Looper() { - close(mWakeReadPipeFd); - close(mWakeWritePipeFd); - close(mEpollFd); + close(mWakeEventFd); + if (mEpollFd >= 0) { + close(mEpollFd); + } } void Looper::initTLSKey() { @@ -156,6 +137,50 @@ bool Looper::getAllowNonCallbacks() const { return mAllowNonCallbacks; } +void Looper::rebuildEpollLocked() { + // Close old epoll instance if we have one. + if (mEpollFd >= 0) { +#if DEBUG_CALLBACKS + ALOGD("%p ~ rebuildEpollLocked - rebuilding epoll set", this); +#endif + close(mEpollFd); + } + + // Allocate the new epoll instance and register the wake pipe. + mEpollFd = epoll_create(EPOLL_SIZE_HINT); + LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance. errno=%d", errno); + + 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; + int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeEventFd, & eventItem); + LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake event fd to epoll instance. errno=%d", + errno); + + for (size_t i = 0; i < mRequests.size(); i++) { + const Request& request = mRequests.valueAt(i); + struct epoll_event eventItem; + request.initEventItem(&eventItem); + + int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, request.fd, & eventItem); + if (epollResult < 0) { + ALOGE("Error adding epoll events for fd %d while rebuilding epoll set, errno=%d", + request.fd, errno); + } + } +} + +void Looper::scheduleEpollRebuildLocked() { + if (!mEpollRebuildRequired) { +#if DEBUG_CALLBACKS + ALOGD("%p ~ scheduleEpollRebuildLocked - scheduling epoll set rebuild", this); +#endif + mEpollRebuildRequired = true; + wake(); + } +} + int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) { int result = 0; for (;;) { @@ -206,7 +231,7 @@ int Looper::pollInner(int timeoutMillis) { timeoutMillis = messageTimeoutMillis; } #if DEBUG_POLL_AND_WAKE - ALOGD("%p ~ pollOnce - next message in %lldns, adjusted timeout: timeoutMillis=%d", + ALOGD("%p ~ pollOnce - next message in %" PRId64 "ns, adjusted timeout: timeoutMillis=%d", this, mNextMessageUptime - now, timeoutMillis); #endif } @@ -217,17 +242,24 @@ int Looper::pollInner(int timeoutMillis) { mResponseIndex = 0; // We are about to idle. - mIdling = true; + mPolling = true; struct epoll_event eventItems[EPOLL_MAX_EVENTS]; int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis); // No longer idling. - mIdling = false; + mPolling = false; // Acquire lock. mLock.lock(); + // Rebuild epoll set if needed. + if (mEpollRebuildRequired) { + mEpollRebuildRequired = false; + rebuildEpollLocked(); + goto Done; + } + // Check for poll error. if (eventCount < 0) { if (errno == EINTR) { @@ -255,11 +287,11 @@ int Looper::pollInner(int timeoutMillis) { for (int i = 0; i < eventCount; i++) { int fd = eventItems[i].data.fd; uint32_t epollEvents = eventItems[i].events; - if (fd == mWakeReadPipeFd) { + if (fd == mWakeEventFd) { if (epollEvents & EPOLLIN) { awoken(); } else { - ALOGW("Ignoring unexpected epoll events 0x%x on wake read pipe.", epollEvents); + ALOGW("Ignoring unexpected epoll events 0x%x on wake event fd.", epollEvents); } } else { ssize_t requestIndex = mRequests.indexOfKey(fd); @@ -326,10 +358,14 @@ Done: ; ALOGD("%p ~ pollOnce - invoking fd event callback %p: fd=%d, events=0x%x, data=%p", this, response.request.callback.get(), 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) { - removeFd(fd); + removeFd(fd, response.request.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.clear(); @@ -370,12 +406,9 @@ void Looper::wake() { ALOGD("%p ~ wake", this); #endif - ssize_t nWrite; - do { - nWrite = write(mWakeWritePipeFd, "W", 1); - } while (nWrite == -1 && errno == EINTR); - - if (nWrite != 1) { + uint64_t inc = 1; + ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd, &inc, sizeof(uint64_t))); + if (nWrite != sizeof(uint64_t)) { if (errno != EAGAIN) { ALOGW("Could not write wake signal, errno=%d", errno); } @@ -387,11 +420,8 @@ void Looper::awoken() { ALOGD("%p ~ awoken", this); #endif - char buffer[16]; - ssize_t nRead; - do { - nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer)); - } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer)); + uint64_t counter; + TEMP_FAILURE_RETRY(read(mWakeEventFd, &counter, sizeof(uint64_t))); } void Looper::pushResponse(int events, const Request& request) { @@ -425,23 +455,20 @@ int Looper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callb ident = POLL_CALLBACK; } - int epollEvents = 0; - if (events & EVENT_INPUT) epollEvents |= EPOLLIN; - if (events & EVENT_OUTPUT) epollEvents |= EPOLLOUT; - { // acquire lock AutoMutex _l(mLock); Request request; request.fd = fd; request.ident = ident; + request.events = events; + request.seq = mNextRequestSeq++; request.callback = callback; request.data = data; + if (mNextRequestSeq == -1) mNextRequestSeq = 0; // reserve sequence number -1 struct epoll_event eventItem; - memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union - eventItem.events = epollEvents; - eventItem.data.fd = fd; + request.initEventItem(&eventItem); ssize_t requestIndex = mRequests.indexOfKey(fd); if (requestIndex < 0) { @@ -454,8 +481,36 @@ int Looper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callb } else { int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, & eventItem); if (epollResult < 0) { - ALOGE("Error modifying epoll events for fd %d, errno=%d", fd, errno); - return -1; + if (errno == ENOENT) { + // Tolerate ENOENT because it means that an older file descriptor was + // closed before its callback was unregistered and meanwhile a new + // file descriptor with the same number has been created and is now + // being registered for the first time. This error may occur naturally + // when a callback has the side-effect of closing the file descriptor + // before returning and unregistering itself. Callback sequence number + // checks further ensure that the race is benign. + // + // 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 others disadvantages. +#if DEBUG_CALLBACKS + ALOGD("%p ~ addFd - EPOLL_CTL_MOD failed due to file descriptor " + "being recycled, falling back on EPOLL_CTL_ADD, errno=%d", + this, errno); +#endif + epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem); + if (epollResult < 0) { + ALOGE("Error modifying or adding epoll events for fd %d, errno=%d", + fd, errno); + return -1; + } + scheduleEpollRebuildLocked(); + } else { + ALOGE("Error modifying epoll events for fd %d, errno=%d", fd, errno); + return -1; + } } mRequests.replaceValueAt(requestIndex, request); } @@ -464,8 +519,12 @@ int Looper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callb } int Looper::removeFd(int fd) { + return removeFd(fd, -1); +} + +int Looper::removeFd(int fd, int seq) { #if DEBUG_CALLBACKS - ALOGD("%p ~ removeFd - fd=%d", this, fd); + ALOGD("%p ~ removeFd - fd=%d, seq=%d", this, fd, seq); #endif { // acquire lock @@ -475,13 +534,48 @@ int Looper::removeFd(int fd) { return 0; } - int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, NULL); - if (epollResult < 0) { - ALOGE("Error removing epoll events for fd %d, errno=%d", fd, errno); - return -1; + // Check the sequence number if one was given. + if (seq != -1 && mRequests.valueAt(requestIndex).seq != seq) { +#if DEBUG_CALLBACKS + ALOGD("%p ~ removeFd - sequence number mismatch, oldSeq=%d", + this, mRequests.valueAt(requestIndex).seq); +#endif + return 0; } + // 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.removeItemsAt(requestIndex); + + int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, NULL); + if (epollResult < 0) { + if (seq != -1 && (errno == EBADF || errno == ENOENT)) { + // Tolerate EBADF or ENOENT when the sequence number is known 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 others disadvantages. +#if DEBUG_CALLBACKS + ALOGD("%p ~ removeFd - EPOLL_CTL_DEL failed due to file descriptor " + "being closed, errno=%d", this, 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. + ALOGE("Error removing epoll events for fd %d, errno=%d", fd, errno); + scheduleEpollRebuildLocked(); + return -1; + } + } } // release lock return 1; } @@ -500,7 +594,7 @@ void Looper::sendMessageDelayed(nsecs_t uptimeDelay, const sp<MessageHandler>& h void Looper::sendMessageAtTime(nsecs_t uptime, const sp<MessageHandler>& handler, const Message& message) { #if DEBUG_CALLBACKS - ALOGD("%p ~ sendMessageAtTime - uptime=%lld, handler=%p, what=%d", + ALOGD("%p ~ sendMessageAtTime - uptime=%" PRId64 ", handler=%p, what=%d", this, uptime, handler.get(), message.what); #endif @@ -566,8 +660,18 @@ void Looper::removeMessages(const sp<MessageHandler>& handler, int what) { } // release lock } -bool Looper::isIdling() const { - return mIdling; +bool Looper::isPolling() const { + return mPolling; +} + +void 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 android |