Loading libs/gui/BLASTBufferQueue.cpp +209 −64 Original line number Diff line number Diff line Loading @@ -50,9 +50,28 @@ using namespace com::android::graphics::libgui; using namespace std::chrono_literals; namespace { #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) // RAII wrapper to defer arbitrary work until the Deferred instance is deleted. template <class F> class Deferred { public: explicit Deferred(F f) : mF{std::move(f)} {} ~Deferred() { mF(); } Deferred(const Deferred&) = delete; Deferred& operator=(const Deferred&) = delete; private: F mF; }; #endif inline const char* boolToString(bool b) { return b ? "true" : "false"; } } // namespace namespace android { Loading @@ -77,12 +96,6 @@ namespace android { std::unique_lock _lock{mutex}; \ base::ScopedLockAssertion assumeLocked(mutex); #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) static ReleaseBufferCallback EMPTY_RELEASE_CALLBACK = [](const ReleaseCallbackId&, const sp<Fence>& /*releaseFence*/, std::optional<uint32_t> /*currentMaxAcquiredBufferCount*/) {}; #endif void BLASTBufferItemConsumer::onDisconnect() { Mutex::Autolock lock(mMutex); mPreviouslyConnected = mCurrentlyConnected; Loading Loading @@ -225,9 +238,8 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, bool updateDestinati this); #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) std::unique_ptr<gui::BufferReleaseChannel::ConsumerEndpoint> bufferReleaseConsumer; gui::BufferReleaseChannel::open(mName, bufferReleaseConsumer, mBufferReleaseProducer); mBufferReleaseReader = std::make_shared<BufferReleaseReader>(std::move(bufferReleaseConsumer)); gui::BufferReleaseChannel::open(mName, mBufferReleaseConsumer, mBufferReleaseProducer); mBufferReleaseReader.emplace(*this); #endif BQA_LOGV("BLASTBufferQueue created"); Loading Loading @@ -260,7 +272,7 @@ void BLASTBufferQueue::onFirstRef() { // safe default, most producers are expected to override this mProducer->setMaxDequeuedBufferCount(2); #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) mBufferReleaseThread.start(sp<BLASTBufferQueue>::fromExisting(this)); mBufferReleaseThread.emplace(sp<BLASTBufferQueue>::fromExisting(this)); #endif } Loading Loading @@ -636,7 +648,7 @@ status_t BLASTBufferQueue::acquireNextBufferLocked( #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) ReleaseBufferCallback releaseBufferCallback = applyTransaction ? EMPTY_RELEASE_CALLBACK : makeReleaseBufferCallbackThunk(); applyTransaction ? nullptr : makeReleaseBufferCallbackThunk(); #else auto releaseBufferCallback = makeReleaseBufferCallbackThunk(); #endif Loading Loading @@ -1137,6 +1149,24 @@ public: #endif }; #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) class BBQBufferQueueCore : public BufferQueueCore { public: explicit BBQBufferQueueCore(const wp<BLASTBufferQueue>& bbq) : mBLASTBufferQueue{bbq} {} void notifyBufferReleased() const override { sp<BLASTBufferQueue> bbq = mBLASTBufferQueue.promote(); if (!bbq) { return; } bbq->mBufferReleaseReader->interruptBlockingRead(); } private: wp<BLASTBufferQueue> mBLASTBufferQueue; }; #endif // Extends the BufferQueueProducer to create a wrapper around the listener so the listener calls // can be non-blocking when the producer is in the client process. class BBQBufferQueueProducer : public BufferQueueProducer { Loading Loading @@ -1188,6 +1218,44 @@ public: return BufferQueueProducer::query(what, value); } #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) status_t waitForBufferRelease(std::unique_lock<std::mutex>& bufferQueueLock, nsecs_t timeout) const override { sp<BLASTBufferQueue> bbq = mBLASTBufferQueue.promote(); if (!bbq) { return OK; } // BufferQueue has already checked if we have a free buffer. If there's an unread interrupt, // we want to ignore it. This must be done before unlocking the BufferQueue lock to ensure // we don't miss an interrupt. bbq->mBufferReleaseReader->clearInterrupts(); bbq->mThreadsBlockingOnDequeue++; bufferQueueLock.unlock(); Deferred cleanup{[&]() { bufferQueueLock.lock(); bbq->mThreadsBlockingOnDequeue--; }}; ATRACE_FORMAT("waiting for free buffer"); ReleaseCallbackId id; sp<Fence> fence; uint32_t maxAcquiredBufferCount; status_t status = bbq->mBufferReleaseReader->readBlocking(id, fence, maxAcquiredBufferCount, timeout); if (status == TIMED_OUT) { return TIMED_OUT; } else if (status != OK) { // Waiting was interrupted or an error occurred. BufferQueueProducer will check if we // have a free buffer and call this method again if not. return OK; } bbq->releaseBufferCallback(id, fence, maxAcquiredBufferCount); return OK; } #endif private: const wp<BLASTBufferQueue> mBLASTBufferQueue; }; Loading @@ -1201,14 +1269,18 @@ void BLASTBufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer LOG_ALWAYS_FATAL_IF(outProducer == nullptr, "BLASTBufferQueue: outProducer must not be NULL"); LOG_ALWAYS_FATAL_IF(outConsumer == nullptr, "BLASTBufferQueue: outConsumer must not be NULL"); sp<BufferQueueCore> core(new BufferQueueCore()); #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) auto core = sp<BBQBufferQueueCore>::make(this); #else auto core = sp<BufferQueueCore>::make(); #endif LOG_ALWAYS_FATAL_IF(core == nullptr, "BLASTBufferQueue: failed to create BufferQueueCore"); sp<IGraphicBufferProducer> producer(new BBQBufferQueueProducer(core, this)); auto producer = sp<BBQBufferQueueProducer>::make(core, this); LOG_ALWAYS_FATAL_IF(producer == nullptr, "BLASTBufferQueue: failed to create BBQBufferQueueProducer"); sp<BufferQueueConsumer> consumer(new BufferQueueConsumer(core)); auto consumer = sp<BufferQueueConsumer>::make(core); consumer->setAllowExtraAcquire(true); LOG_ALWAYS_FATAL_IF(consumer == nullptr, "BLASTBufferQueue: failed to create BufferQueueConsumer"); Loading Loading @@ -1273,10 +1345,8 @@ void BLASTBufferQueue::setApplyToken(sp<IBinder> applyToken) { #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) BLASTBufferQueue::BufferReleaseReader::BufferReleaseReader( std::unique_ptr<gui::BufferReleaseChannel::ConsumerEndpoint> endpoint) : mEndpoint{std::move(endpoint)} { mEpollFd = android::base::unique_fd{epoll_create1(0)}; BLASTBufferQueue::BufferReleaseReader::BufferReleaseReader(BLASTBufferQueue& bbq) : mBbq{bbq} { mEpollFd = android::base::unique_fd{epoll_create1(EPOLL_CLOEXEC)}; LOG_ALWAYS_FATAL_IF(!mEpollFd.ok(), "Failed to create buffer release epoll file descriptor. errno=%d " "message='%s'", Loading @@ -1284,9 +1354,9 @@ BLASTBufferQueue::BufferReleaseReader::BufferReleaseReader( epoll_event registerEndpointFd{}; registerEndpointFd.events = EPOLLIN; registerEndpointFd.data.fd = mEndpoint->getFd(); status_t status = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, mEndpoint->getFd(), ®isterEndpointFd); registerEndpointFd.data.fd = mBbq.mBufferReleaseConsumer->getFd(); status_t status = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, mBbq.mBufferReleaseConsumer->getFd(), ®isterEndpointFd); LOG_ALWAYS_FATAL_IF(status == -1, "Failed to register buffer release consumer file descriptor with epoll. " "errno=%d message='%s'", Loading @@ -1308,78 +1378,153 @@ BLASTBufferQueue::BufferReleaseReader::BufferReleaseReader( errno, strerror(errno)); } BLASTBufferQueue::BufferReleaseReader& BLASTBufferQueue::BufferReleaseReader::operator=( BufferReleaseReader&& other) { if (this != &other) { ftl::FakeGuard guard{mMutex}; ftl::FakeGuard otherGuard{other.mMutex}; mEndpoint = std::move(other.mEndpoint); mEpollFd = std::move(other.mEpollFd); mEventFd = std::move(other.mEventFd); status_t BLASTBufferQueue::BufferReleaseReader::readBlocking(ReleaseCallbackId& outId, sp<Fence>& outFence, uint32_t& outMaxAcquiredBufferCount, nsecs_t timeout) { // TODO(b/363290953) epoll_wait only has millisecond timeout precision. If timeout is less than // 1ms, then we round timeout up to 1ms. Otherwise, we round timeout to the nearest // millisecond. Once epoll_pwait2 can be used in libgui, we can specify timeout with nanosecond // precision. int timeoutMs = -1; if (timeout == 0) { timeoutMs = 0; } else if (timeout > 0) { const int nsPerMs = 1000000; if (timeout < nsPerMs) { timeoutMs = 1; } else { timeoutMs = static_cast<int>( std::chrono::round<std::chrono::milliseconds>(std::chrono::nanoseconds{timeout}) .count()); } return *this; } status_t BLASTBufferQueue::BufferReleaseReader::readBlocking(ReleaseCallbackId& outId, sp<Fence>& outFence, uint32_t& outMaxAcquiredBufferCount) { epoll_event event{}; while (true) { int eventCount = epoll_wait(mEpollFd.get(), &event, 1 /* maxevents */, -1 /* timeout */); if (eventCount == 1) { break; } if (eventCount == -1 && errno != EINTR) { int eventCount; do { eventCount = epoll_wait(mEpollFd.get(), &event, 1 /*maxevents*/, timeoutMs); } while (eventCount == -1 && errno != EINTR); if (eventCount == -1) { ALOGE("epoll_wait error while waiting for buffer release. errno=%d message='%s'", errno, strerror(errno)); return UNKNOWN_ERROR; } if (eventCount == 0) { return TIMED_OUT; } if (event.data.fd == mEventFd.get()) { uint64_t value; if (read(mEventFd.get(), &value, sizeof(uint64_t)) == -1 && errno != EWOULDBLOCK) { ALOGE("error while reading from eventfd. errno=%d message='%s'", errno, strerror(errno)); } clearInterrupts(); return WOULD_BLOCK; } std::lock_guard lock{mMutex}; return mEndpoint->readReleaseFence(outId, outFence, outMaxAcquiredBufferCount); return mBbq.mBufferReleaseConsumer->readReleaseFence(outId, outFence, outMaxAcquiredBufferCount); } void BLASTBufferQueue::BufferReleaseReader::interruptBlockingRead() { uint64_t value = 1; if (write(mEventFd.get(), &value, sizeof(uint64_t)) == -1) { if (eventfd_write(mEventFd.get(), 1) == -1) { ALOGE("failed to notify dequeue event. errno=%d message='%s'", errno, strerror(errno)); } } void BLASTBufferQueue::BufferReleaseThread::start(const sp<BLASTBufferQueue>& bbq) { mRunning = std::make_shared<std::atomic_bool>(true); mReader = bbq->mBufferReleaseReader; std::thread([running = mRunning, reader = mReader, weakBbq = wp<BLASTBufferQueue>(bbq)]() { void BLASTBufferQueue::BufferReleaseReader::clearInterrupts() { eventfd_t value; if (eventfd_read(mEventFd.get(), &value) == -1 && errno != EWOULDBLOCK) { ALOGE("error while reading from eventfd. errno=%d message='%s'", errno, strerror(errno)); } } BLASTBufferQueue::BufferReleaseThread::BufferReleaseThread(const sp<BLASTBufferQueue>& bbq) { android::base::unique_fd epollFd{epoll_create1(EPOLL_CLOEXEC)}; LOG_ALWAYS_FATAL_IF(!epollFd.ok(), "Failed to create buffer release background thread epoll file descriptor. " "errno=%d message='%s'", errno, strerror(errno)); epoll_event registerEndpointFd{}; registerEndpointFd.events = EPOLLIN; registerEndpointFd.data.fd = bbq->mBufferReleaseConsumer->getFd(); status_t status = epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, bbq->mBufferReleaseConsumer->getFd(), ®isterEndpointFd); LOG_ALWAYS_FATAL_IF(status == -1, "Failed to register background thread buffer release consumer file " "descriptor with epoll. errno=%d message='%s'", errno, strerror(errno)); // EventFd is used to break the background thread's loop. android::base::unique_fd eventFd{eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)}; LOG_ALWAYS_FATAL_IF(!eventFd.ok(), "Failed to create background thread buffer release event file descriptor. " "errno=%d message='%s'", errno, strerror(errno)); epoll_event registerEventFd{}; registerEventFd.events = EPOLLIN; registerEventFd.data.fd = eventFd.get(); status = epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), ®isterEventFd); LOG_ALWAYS_FATAL_IF(status == -1, "Failed to register background thread event file descriptor with epoll. " "errno=%d message='%s'", errno, strerror(errno)); mEventFd = eventFd.get(); std::thread([epollFd = std::move(epollFd), eventFd = std::move(eventFd), weakBbq = wp<BLASTBufferQueue>(bbq)]() { pthread_setname_np(pthread_self(), "BufferReleaseThread"); while (*running) { ReleaseCallbackId id; sp<Fence> fence; uint32_t maxAcquiredBufferCount; if (status_t status = reader->readBlocking(id, fence, maxAcquiredBufferCount); status != OK) { while (true) { epoll_event event{}; int eventCount; do { eventCount = epoll_wait(epollFd.get(), &event, 1 /*maxevents*/, -1 /*timeout*/); } while (eventCount == -1 && errno != EINTR); if (eventCount == -1) { ALOGE("epoll_wait error while waiting for buffer release in background thread. " "errno=%d message='%s'", errno, strerror(errno)); continue; } // EventFd is used to join this thread. if (event.data.fd == eventFd.get()) { return; } sp<BLASTBufferQueue> bbq = weakBbq.promote(); if (!bbq) { return; } // If there are threads blocking on dequeue, give those threads priority for handling // the release. if (bbq->mThreadsBlockingOnDequeue > 0) { std::this_thread::sleep_for(0ms); continue; } ReleaseCallbackId id; sp<Fence> fence; uint32_t maxAcquiredBufferCount; status_t status = bbq->mBufferReleaseConsumer->readReleaseFence(id, fence, maxAcquiredBufferCount); if (status != OK) { ALOGE("failed to read from buffer release consumer in background thread. errno=%d " "message='%s'", errno, strerror(errno)); continue; } bbq->releaseBufferCallback(id, fence, maxAcquiredBufferCount); } }).detach(); } BLASTBufferQueue::BufferReleaseThread::~BufferReleaseThread() { *mRunning = false; mReader->interruptBlockingRead(); eventfd_write(mEventFd, 1); } #endif Loading libs/gui/BufferQueueConsumer.cpp +18 −0 Original line number Diff line number Diff line Loading @@ -297,7 +297,11 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, // We might have freed a slot while dropping old buffers, or the producer // may be blocked waiting for the number of buffers in the queue to // decrease. #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) mCore->notifyBufferReleased(); #else mCore->mDequeueCondition.notify_all(); #endif ATRACE_INT(mCore->mConsumerName.c_str(), static_cast<int32_t>(mCore->mQueue.size())); #ifndef NO_BINDER Loading Loading @@ -350,7 +354,12 @@ status_t BufferQueueConsumer::detachBuffer(int slot) { mCore->mActiveBuffers.erase(slot); mCore->mFreeSlots.insert(slot); mCore->clearBufferSlotLocked(slot); #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) mCore->notifyBufferReleased(); #else mCore->mDequeueCondition.notify_all(); #endif VALIDATE_CONSISTENCY(); } Loading Loading @@ -520,7 +529,12 @@ status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber, } BQ_LOGV("releaseBuffer: releasing slot %d", slot); #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) mCore->notifyBufferReleased(); #else mCore->mDequeueCondition.notify_all(); #endif VALIDATE_CONSISTENCY(); } // Autolock scope Loading Loading @@ -574,7 +588,11 @@ status_t BufferQueueConsumer::disconnect() { mCore->mQueue.clear(); mCore->freeAllBuffersLocked(); mCore->mSharedBufferSlot = BufferQueueCore::INVALID_BUFFER_SLOT; #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) mCore->notifyBufferReleased(); #else mCore->mDequeueCondition.notify_all(); #endif return NO_ERROR; } Loading libs/gui/BufferQueueCore.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -371,6 +371,12 @@ void BufferQueueCore::waitWhileAllocatingLocked(std::unique_lock<std::mutex>& lo } } #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) void BufferQueueCore::notifyBufferReleased() const { mDequeueCondition.notify_all(); } #endif #if DEBUG_ONLY_CODE void BufferQueueCore::validateConsistencyLocked() const { static const useconds_t PAUSE_TIME = 0; Loading libs/gui/BufferQueueProducer.cpp +48 −0 Original line number Diff line number Diff line Loading @@ -202,7 +202,11 @@ status_t BufferQueueProducer::setMaxDequeuedBufferCount(int maxDequeuedBuffers, if (delta < 0) { listener = mCore->mConsumerListener; } #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) mCore->notifyBufferReleased(); #else mCore->mDequeueCondition.notify_all(); #endif } // Autolock scope // Call back without lock held Loading Loading @@ -254,7 +258,12 @@ status_t BufferQueueProducer::setAsyncMode(bool async) { } mCore->mAsyncMode = async; VALIDATE_CONSISTENCY(); #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) mCore->notifyBufferReleased(); #else mCore->mDequeueCondition.notify_all(); #endif if (delta < 0) { listener = mCore->mConsumerListener; } Loading Loading @@ -376,6 +385,12 @@ status_t BufferQueueProducer::waitForFreeSlotThenRelock(FreeSlotCaller caller, (acquiredCount <= mCore->mMaxAcquiredBufferCount)) { return WOULD_BLOCK; } #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) if (status_t status = waitForBufferRelease(lock, mDequeueTimeout); status == TIMED_OUT) { return TIMED_OUT; } #else if (mDequeueTimeout >= 0) { std::cv_status result = mCore->mDequeueCondition.wait_for(lock, std::chrono::nanoseconds(mDequeueTimeout)); Loading @@ -385,12 +400,29 @@ status_t BufferQueueProducer::waitForFreeSlotThenRelock(FreeSlotCaller caller, } else { mCore->mDequeueCondition.wait(lock); } #endif } } // while (tryAgain) return NO_ERROR; } #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) status_t BufferQueueProducer::waitForBufferRelease(std::unique_lock<std::mutex>& lock, nsecs_t timeout) const { if (mDequeueTimeout >= 0) { std::cv_status result = mCore->mDequeueCondition.wait_for(lock, std::chrono::nanoseconds(timeout)); if (result == std::cv_status::timeout) { return TIMED_OUT; } } else { mCore->mDequeueCondition.wait(lock); } return OK; } #endif status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp<android::Fence>* outFence, uint32_t width, uint32_t height, PixelFormat format, uint64_t usage, uint64_t* outBufferAge, Loading Loading @@ -741,7 +773,11 @@ status_t BufferQueueProducer::detachBuffer(int slot) { mCore->mActiveBuffers.erase(slot); mCore->mFreeSlots.insert(slot); mCore->clearBufferSlotLocked(slot); #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) mCore->notifyBufferReleased(); #else mCore->mDequeueCondition.notify_all(); #endif VALIDATE_CONSISTENCY(); } Loading Loading @@ -1082,7 +1118,11 @@ status_t BufferQueueProducer::queueBuffer(int slot, } mCore->mBufferHasBeenQueued = true; #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) mCore->notifyBufferReleased(); #else mCore->mDequeueCondition.notify_all(); #endif mCore->mLastQueuedSlot = slot; output->width = mCore->mDefaultWidth; Loading Loading @@ -1218,7 +1258,11 @@ status_t BufferQueueProducer::cancelBuffer(int slot, const sp<Fence>& fence) { bufferId = gb->getId(); } mSlots[slot].mFence = fence; #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) mCore->notifyBufferReleased(); #else mCore->mDequeueCondition.notify_all(); #endif listener = mCore->mConsumerListener; VALIDATE_CONSISTENCY(); } Loading Loading @@ -1457,7 +1501,11 @@ status_t BufferQueueProducer::disconnect(int api, DisconnectMode mode) { mCore->mConnectedApi = BufferQueueCore::NO_CONNECTED_API; mCore->mConnectedPid = -1; mCore->mSidebandStream.clear(); #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) mCore->notifyBufferReleased(); #else mCore->mDequeueCondition.notify_all(); #endif mCore->mAutoPrerotation = false; #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_EXTENDEDALLOCATE) mCore->mAdditionalOptions.clear(); Loading libs/gui/BufferReleaseChannel.cpp +3 −2 Original line number Diff line number Diff line Loading @@ -136,6 +136,7 @@ status_t BufferReleaseChannel::Message::unflatten(void const*& buffer, size_t& s status_t BufferReleaseChannel::ConsumerEndpoint::readReleaseFence( ReleaseCallbackId& outReleaseCallbackId, sp<Fence>& outReleaseFence, uint32_t& outMaxAcquiredBufferCount) { std::lock_guard lock{mMutex}; Message message; mFlattenedBuffer.resize(message.getFlattenedSize()); std::array<uint8_t, CMSG_SPACE(sizeof(int))> controlMessageBuffer; Loading @@ -152,7 +153,7 @@ status_t BufferReleaseChannel::ConsumerEndpoint::readReleaseFence( .msg_controllen = controlMessageBuffer.size(), }; int result; ssize_t result; do { result = recvmsg(mFd, &msg, 0); } while (result == -1 && errno == EINTR); Loading Loading @@ -242,7 +243,7 @@ int BufferReleaseChannel::ProducerEndpoint::writeReleaseFence(const ReleaseCallb memcpy(CMSG_DATA(cmsg), &flattenedFd, sizeof(int)); } int result; ssize_t result; do { result = sendmsg(mFd, &msg, 0); } while (result == -1 && errno == EINTR); Loading Loading
libs/gui/BLASTBufferQueue.cpp +209 −64 Original line number Diff line number Diff line Loading @@ -50,9 +50,28 @@ using namespace com::android::graphics::libgui; using namespace std::chrono_literals; namespace { #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) // RAII wrapper to defer arbitrary work until the Deferred instance is deleted. template <class F> class Deferred { public: explicit Deferred(F f) : mF{std::move(f)} {} ~Deferred() { mF(); } Deferred(const Deferred&) = delete; Deferred& operator=(const Deferred&) = delete; private: F mF; }; #endif inline const char* boolToString(bool b) { return b ? "true" : "false"; } } // namespace namespace android { Loading @@ -77,12 +96,6 @@ namespace android { std::unique_lock _lock{mutex}; \ base::ScopedLockAssertion assumeLocked(mutex); #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) static ReleaseBufferCallback EMPTY_RELEASE_CALLBACK = [](const ReleaseCallbackId&, const sp<Fence>& /*releaseFence*/, std::optional<uint32_t> /*currentMaxAcquiredBufferCount*/) {}; #endif void BLASTBufferItemConsumer::onDisconnect() { Mutex::Autolock lock(mMutex); mPreviouslyConnected = mCurrentlyConnected; Loading Loading @@ -225,9 +238,8 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, bool updateDestinati this); #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) std::unique_ptr<gui::BufferReleaseChannel::ConsumerEndpoint> bufferReleaseConsumer; gui::BufferReleaseChannel::open(mName, bufferReleaseConsumer, mBufferReleaseProducer); mBufferReleaseReader = std::make_shared<BufferReleaseReader>(std::move(bufferReleaseConsumer)); gui::BufferReleaseChannel::open(mName, mBufferReleaseConsumer, mBufferReleaseProducer); mBufferReleaseReader.emplace(*this); #endif BQA_LOGV("BLASTBufferQueue created"); Loading Loading @@ -260,7 +272,7 @@ void BLASTBufferQueue::onFirstRef() { // safe default, most producers are expected to override this mProducer->setMaxDequeuedBufferCount(2); #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) mBufferReleaseThread.start(sp<BLASTBufferQueue>::fromExisting(this)); mBufferReleaseThread.emplace(sp<BLASTBufferQueue>::fromExisting(this)); #endif } Loading Loading @@ -636,7 +648,7 @@ status_t BLASTBufferQueue::acquireNextBufferLocked( #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) ReleaseBufferCallback releaseBufferCallback = applyTransaction ? EMPTY_RELEASE_CALLBACK : makeReleaseBufferCallbackThunk(); applyTransaction ? nullptr : makeReleaseBufferCallbackThunk(); #else auto releaseBufferCallback = makeReleaseBufferCallbackThunk(); #endif Loading Loading @@ -1137,6 +1149,24 @@ public: #endif }; #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) class BBQBufferQueueCore : public BufferQueueCore { public: explicit BBQBufferQueueCore(const wp<BLASTBufferQueue>& bbq) : mBLASTBufferQueue{bbq} {} void notifyBufferReleased() const override { sp<BLASTBufferQueue> bbq = mBLASTBufferQueue.promote(); if (!bbq) { return; } bbq->mBufferReleaseReader->interruptBlockingRead(); } private: wp<BLASTBufferQueue> mBLASTBufferQueue; }; #endif // Extends the BufferQueueProducer to create a wrapper around the listener so the listener calls // can be non-blocking when the producer is in the client process. class BBQBufferQueueProducer : public BufferQueueProducer { Loading Loading @@ -1188,6 +1218,44 @@ public: return BufferQueueProducer::query(what, value); } #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) status_t waitForBufferRelease(std::unique_lock<std::mutex>& bufferQueueLock, nsecs_t timeout) const override { sp<BLASTBufferQueue> bbq = mBLASTBufferQueue.promote(); if (!bbq) { return OK; } // BufferQueue has already checked if we have a free buffer. If there's an unread interrupt, // we want to ignore it. This must be done before unlocking the BufferQueue lock to ensure // we don't miss an interrupt. bbq->mBufferReleaseReader->clearInterrupts(); bbq->mThreadsBlockingOnDequeue++; bufferQueueLock.unlock(); Deferred cleanup{[&]() { bufferQueueLock.lock(); bbq->mThreadsBlockingOnDequeue--; }}; ATRACE_FORMAT("waiting for free buffer"); ReleaseCallbackId id; sp<Fence> fence; uint32_t maxAcquiredBufferCount; status_t status = bbq->mBufferReleaseReader->readBlocking(id, fence, maxAcquiredBufferCount, timeout); if (status == TIMED_OUT) { return TIMED_OUT; } else if (status != OK) { // Waiting was interrupted or an error occurred. BufferQueueProducer will check if we // have a free buffer and call this method again if not. return OK; } bbq->releaseBufferCallback(id, fence, maxAcquiredBufferCount); return OK; } #endif private: const wp<BLASTBufferQueue> mBLASTBufferQueue; }; Loading @@ -1201,14 +1269,18 @@ void BLASTBufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer LOG_ALWAYS_FATAL_IF(outProducer == nullptr, "BLASTBufferQueue: outProducer must not be NULL"); LOG_ALWAYS_FATAL_IF(outConsumer == nullptr, "BLASTBufferQueue: outConsumer must not be NULL"); sp<BufferQueueCore> core(new BufferQueueCore()); #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) auto core = sp<BBQBufferQueueCore>::make(this); #else auto core = sp<BufferQueueCore>::make(); #endif LOG_ALWAYS_FATAL_IF(core == nullptr, "BLASTBufferQueue: failed to create BufferQueueCore"); sp<IGraphicBufferProducer> producer(new BBQBufferQueueProducer(core, this)); auto producer = sp<BBQBufferQueueProducer>::make(core, this); LOG_ALWAYS_FATAL_IF(producer == nullptr, "BLASTBufferQueue: failed to create BBQBufferQueueProducer"); sp<BufferQueueConsumer> consumer(new BufferQueueConsumer(core)); auto consumer = sp<BufferQueueConsumer>::make(core); consumer->setAllowExtraAcquire(true); LOG_ALWAYS_FATAL_IF(consumer == nullptr, "BLASTBufferQueue: failed to create BufferQueueConsumer"); Loading Loading @@ -1273,10 +1345,8 @@ void BLASTBufferQueue::setApplyToken(sp<IBinder> applyToken) { #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) BLASTBufferQueue::BufferReleaseReader::BufferReleaseReader( std::unique_ptr<gui::BufferReleaseChannel::ConsumerEndpoint> endpoint) : mEndpoint{std::move(endpoint)} { mEpollFd = android::base::unique_fd{epoll_create1(0)}; BLASTBufferQueue::BufferReleaseReader::BufferReleaseReader(BLASTBufferQueue& bbq) : mBbq{bbq} { mEpollFd = android::base::unique_fd{epoll_create1(EPOLL_CLOEXEC)}; LOG_ALWAYS_FATAL_IF(!mEpollFd.ok(), "Failed to create buffer release epoll file descriptor. errno=%d " "message='%s'", Loading @@ -1284,9 +1354,9 @@ BLASTBufferQueue::BufferReleaseReader::BufferReleaseReader( epoll_event registerEndpointFd{}; registerEndpointFd.events = EPOLLIN; registerEndpointFd.data.fd = mEndpoint->getFd(); status_t status = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, mEndpoint->getFd(), ®isterEndpointFd); registerEndpointFd.data.fd = mBbq.mBufferReleaseConsumer->getFd(); status_t status = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, mBbq.mBufferReleaseConsumer->getFd(), ®isterEndpointFd); LOG_ALWAYS_FATAL_IF(status == -1, "Failed to register buffer release consumer file descriptor with epoll. " "errno=%d message='%s'", Loading @@ -1308,78 +1378,153 @@ BLASTBufferQueue::BufferReleaseReader::BufferReleaseReader( errno, strerror(errno)); } BLASTBufferQueue::BufferReleaseReader& BLASTBufferQueue::BufferReleaseReader::operator=( BufferReleaseReader&& other) { if (this != &other) { ftl::FakeGuard guard{mMutex}; ftl::FakeGuard otherGuard{other.mMutex}; mEndpoint = std::move(other.mEndpoint); mEpollFd = std::move(other.mEpollFd); mEventFd = std::move(other.mEventFd); status_t BLASTBufferQueue::BufferReleaseReader::readBlocking(ReleaseCallbackId& outId, sp<Fence>& outFence, uint32_t& outMaxAcquiredBufferCount, nsecs_t timeout) { // TODO(b/363290953) epoll_wait only has millisecond timeout precision. If timeout is less than // 1ms, then we round timeout up to 1ms. Otherwise, we round timeout to the nearest // millisecond. Once epoll_pwait2 can be used in libgui, we can specify timeout with nanosecond // precision. int timeoutMs = -1; if (timeout == 0) { timeoutMs = 0; } else if (timeout > 0) { const int nsPerMs = 1000000; if (timeout < nsPerMs) { timeoutMs = 1; } else { timeoutMs = static_cast<int>( std::chrono::round<std::chrono::milliseconds>(std::chrono::nanoseconds{timeout}) .count()); } return *this; } status_t BLASTBufferQueue::BufferReleaseReader::readBlocking(ReleaseCallbackId& outId, sp<Fence>& outFence, uint32_t& outMaxAcquiredBufferCount) { epoll_event event{}; while (true) { int eventCount = epoll_wait(mEpollFd.get(), &event, 1 /* maxevents */, -1 /* timeout */); if (eventCount == 1) { break; } if (eventCount == -1 && errno != EINTR) { int eventCount; do { eventCount = epoll_wait(mEpollFd.get(), &event, 1 /*maxevents*/, timeoutMs); } while (eventCount == -1 && errno != EINTR); if (eventCount == -1) { ALOGE("epoll_wait error while waiting for buffer release. errno=%d message='%s'", errno, strerror(errno)); return UNKNOWN_ERROR; } if (eventCount == 0) { return TIMED_OUT; } if (event.data.fd == mEventFd.get()) { uint64_t value; if (read(mEventFd.get(), &value, sizeof(uint64_t)) == -1 && errno != EWOULDBLOCK) { ALOGE("error while reading from eventfd. errno=%d message='%s'", errno, strerror(errno)); } clearInterrupts(); return WOULD_BLOCK; } std::lock_guard lock{mMutex}; return mEndpoint->readReleaseFence(outId, outFence, outMaxAcquiredBufferCount); return mBbq.mBufferReleaseConsumer->readReleaseFence(outId, outFence, outMaxAcquiredBufferCount); } void BLASTBufferQueue::BufferReleaseReader::interruptBlockingRead() { uint64_t value = 1; if (write(mEventFd.get(), &value, sizeof(uint64_t)) == -1) { if (eventfd_write(mEventFd.get(), 1) == -1) { ALOGE("failed to notify dequeue event. errno=%d message='%s'", errno, strerror(errno)); } } void BLASTBufferQueue::BufferReleaseThread::start(const sp<BLASTBufferQueue>& bbq) { mRunning = std::make_shared<std::atomic_bool>(true); mReader = bbq->mBufferReleaseReader; std::thread([running = mRunning, reader = mReader, weakBbq = wp<BLASTBufferQueue>(bbq)]() { void BLASTBufferQueue::BufferReleaseReader::clearInterrupts() { eventfd_t value; if (eventfd_read(mEventFd.get(), &value) == -1 && errno != EWOULDBLOCK) { ALOGE("error while reading from eventfd. errno=%d message='%s'", errno, strerror(errno)); } } BLASTBufferQueue::BufferReleaseThread::BufferReleaseThread(const sp<BLASTBufferQueue>& bbq) { android::base::unique_fd epollFd{epoll_create1(EPOLL_CLOEXEC)}; LOG_ALWAYS_FATAL_IF(!epollFd.ok(), "Failed to create buffer release background thread epoll file descriptor. " "errno=%d message='%s'", errno, strerror(errno)); epoll_event registerEndpointFd{}; registerEndpointFd.events = EPOLLIN; registerEndpointFd.data.fd = bbq->mBufferReleaseConsumer->getFd(); status_t status = epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, bbq->mBufferReleaseConsumer->getFd(), ®isterEndpointFd); LOG_ALWAYS_FATAL_IF(status == -1, "Failed to register background thread buffer release consumer file " "descriptor with epoll. errno=%d message='%s'", errno, strerror(errno)); // EventFd is used to break the background thread's loop. android::base::unique_fd eventFd{eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)}; LOG_ALWAYS_FATAL_IF(!eventFd.ok(), "Failed to create background thread buffer release event file descriptor. " "errno=%d message='%s'", errno, strerror(errno)); epoll_event registerEventFd{}; registerEventFd.events = EPOLLIN; registerEventFd.data.fd = eventFd.get(); status = epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), ®isterEventFd); LOG_ALWAYS_FATAL_IF(status == -1, "Failed to register background thread event file descriptor with epoll. " "errno=%d message='%s'", errno, strerror(errno)); mEventFd = eventFd.get(); std::thread([epollFd = std::move(epollFd), eventFd = std::move(eventFd), weakBbq = wp<BLASTBufferQueue>(bbq)]() { pthread_setname_np(pthread_self(), "BufferReleaseThread"); while (*running) { ReleaseCallbackId id; sp<Fence> fence; uint32_t maxAcquiredBufferCount; if (status_t status = reader->readBlocking(id, fence, maxAcquiredBufferCount); status != OK) { while (true) { epoll_event event{}; int eventCount; do { eventCount = epoll_wait(epollFd.get(), &event, 1 /*maxevents*/, -1 /*timeout*/); } while (eventCount == -1 && errno != EINTR); if (eventCount == -1) { ALOGE("epoll_wait error while waiting for buffer release in background thread. " "errno=%d message='%s'", errno, strerror(errno)); continue; } // EventFd is used to join this thread. if (event.data.fd == eventFd.get()) { return; } sp<BLASTBufferQueue> bbq = weakBbq.promote(); if (!bbq) { return; } // If there are threads blocking on dequeue, give those threads priority for handling // the release. if (bbq->mThreadsBlockingOnDequeue > 0) { std::this_thread::sleep_for(0ms); continue; } ReleaseCallbackId id; sp<Fence> fence; uint32_t maxAcquiredBufferCount; status_t status = bbq->mBufferReleaseConsumer->readReleaseFence(id, fence, maxAcquiredBufferCount); if (status != OK) { ALOGE("failed to read from buffer release consumer in background thread. errno=%d " "message='%s'", errno, strerror(errno)); continue; } bbq->releaseBufferCallback(id, fence, maxAcquiredBufferCount); } }).detach(); } BLASTBufferQueue::BufferReleaseThread::~BufferReleaseThread() { *mRunning = false; mReader->interruptBlockingRead(); eventfd_write(mEventFd, 1); } #endif Loading
libs/gui/BufferQueueConsumer.cpp +18 −0 Original line number Diff line number Diff line Loading @@ -297,7 +297,11 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, // We might have freed a slot while dropping old buffers, or the producer // may be blocked waiting for the number of buffers in the queue to // decrease. #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) mCore->notifyBufferReleased(); #else mCore->mDequeueCondition.notify_all(); #endif ATRACE_INT(mCore->mConsumerName.c_str(), static_cast<int32_t>(mCore->mQueue.size())); #ifndef NO_BINDER Loading Loading @@ -350,7 +354,12 @@ status_t BufferQueueConsumer::detachBuffer(int slot) { mCore->mActiveBuffers.erase(slot); mCore->mFreeSlots.insert(slot); mCore->clearBufferSlotLocked(slot); #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) mCore->notifyBufferReleased(); #else mCore->mDequeueCondition.notify_all(); #endif VALIDATE_CONSISTENCY(); } Loading Loading @@ -520,7 +529,12 @@ status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber, } BQ_LOGV("releaseBuffer: releasing slot %d", slot); #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) mCore->notifyBufferReleased(); #else mCore->mDequeueCondition.notify_all(); #endif VALIDATE_CONSISTENCY(); } // Autolock scope Loading Loading @@ -574,7 +588,11 @@ status_t BufferQueueConsumer::disconnect() { mCore->mQueue.clear(); mCore->freeAllBuffersLocked(); mCore->mSharedBufferSlot = BufferQueueCore::INVALID_BUFFER_SLOT; #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) mCore->notifyBufferReleased(); #else mCore->mDequeueCondition.notify_all(); #endif return NO_ERROR; } Loading
libs/gui/BufferQueueCore.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -371,6 +371,12 @@ void BufferQueueCore::waitWhileAllocatingLocked(std::unique_lock<std::mutex>& lo } } #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) void BufferQueueCore::notifyBufferReleased() const { mDequeueCondition.notify_all(); } #endif #if DEBUG_ONLY_CODE void BufferQueueCore::validateConsistencyLocked() const { static const useconds_t PAUSE_TIME = 0; Loading
libs/gui/BufferQueueProducer.cpp +48 −0 Original line number Diff line number Diff line Loading @@ -202,7 +202,11 @@ status_t BufferQueueProducer::setMaxDequeuedBufferCount(int maxDequeuedBuffers, if (delta < 0) { listener = mCore->mConsumerListener; } #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) mCore->notifyBufferReleased(); #else mCore->mDequeueCondition.notify_all(); #endif } // Autolock scope // Call back without lock held Loading Loading @@ -254,7 +258,12 @@ status_t BufferQueueProducer::setAsyncMode(bool async) { } mCore->mAsyncMode = async; VALIDATE_CONSISTENCY(); #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) mCore->notifyBufferReleased(); #else mCore->mDequeueCondition.notify_all(); #endif if (delta < 0) { listener = mCore->mConsumerListener; } Loading Loading @@ -376,6 +385,12 @@ status_t BufferQueueProducer::waitForFreeSlotThenRelock(FreeSlotCaller caller, (acquiredCount <= mCore->mMaxAcquiredBufferCount)) { return WOULD_BLOCK; } #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) if (status_t status = waitForBufferRelease(lock, mDequeueTimeout); status == TIMED_OUT) { return TIMED_OUT; } #else if (mDequeueTimeout >= 0) { std::cv_status result = mCore->mDequeueCondition.wait_for(lock, std::chrono::nanoseconds(mDequeueTimeout)); Loading @@ -385,12 +400,29 @@ status_t BufferQueueProducer::waitForFreeSlotThenRelock(FreeSlotCaller caller, } else { mCore->mDequeueCondition.wait(lock); } #endif } } // while (tryAgain) return NO_ERROR; } #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) status_t BufferQueueProducer::waitForBufferRelease(std::unique_lock<std::mutex>& lock, nsecs_t timeout) const { if (mDequeueTimeout >= 0) { std::cv_status result = mCore->mDequeueCondition.wait_for(lock, std::chrono::nanoseconds(timeout)); if (result == std::cv_status::timeout) { return TIMED_OUT; } } else { mCore->mDequeueCondition.wait(lock); } return OK; } #endif status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp<android::Fence>* outFence, uint32_t width, uint32_t height, PixelFormat format, uint64_t usage, uint64_t* outBufferAge, Loading Loading @@ -741,7 +773,11 @@ status_t BufferQueueProducer::detachBuffer(int slot) { mCore->mActiveBuffers.erase(slot); mCore->mFreeSlots.insert(slot); mCore->clearBufferSlotLocked(slot); #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) mCore->notifyBufferReleased(); #else mCore->mDequeueCondition.notify_all(); #endif VALIDATE_CONSISTENCY(); } Loading Loading @@ -1082,7 +1118,11 @@ status_t BufferQueueProducer::queueBuffer(int slot, } mCore->mBufferHasBeenQueued = true; #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) mCore->notifyBufferReleased(); #else mCore->mDequeueCondition.notify_all(); #endif mCore->mLastQueuedSlot = slot; output->width = mCore->mDefaultWidth; Loading Loading @@ -1218,7 +1258,11 @@ status_t BufferQueueProducer::cancelBuffer(int slot, const sp<Fence>& fence) { bufferId = gb->getId(); } mSlots[slot].mFence = fence; #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) mCore->notifyBufferReleased(); #else mCore->mDequeueCondition.notify_all(); #endif listener = mCore->mConsumerListener; VALIDATE_CONSISTENCY(); } Loading Loading @@ -1457,7 +1501,11 @@ status_t BufferQueueProducer::disconnect(int api, DisconnectMode mode) { mCore->mConnectedApi = BufferQueueCore::NO_CONNECTED_API; mCore->mConnectedPid = -1; mCore->mSidebandStream.clear(); #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) mCore->notifyBufferReleased(); #else mCore->mDequeueCondition.notify_all(); #endif mCore->mAutoPrerotation = false; #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_EXTENDEDALLOCATE) mCore->mAdditionalOptions.clear(); Loading
libs/gui/BufferReleaseChannel.cpp +3 −2 Original line number Diff line number Diff line Loading @@ -136,6 +136,7 @@ status_t BufferReleaseChannel::Message::unflatten(void const*& buffer, size_t& s status_t BufferReleaseChannel::ConsumerEndpoint::readReleaseFence( ReleaseCallbackId& outReleaseCallbackId, sp<Fence>& outReleaseFence, uint32_t& outMaxAcquiredBufferCount) { std::lock_guard lock{mMutex}; Message message; mFlattenedBuffer.resize(message.getFlattenedSize()); std::array<uint8_t, CMSG_SPACE(sizeof(int))> controlMessageBuffer; Loading @@ -152,7 +153,7 @@ status_t BufferReleaseChannel::ConsumerEndpoint::readReleaseFence( .msg_controllen = controlMessageBuffer.size(), }; int result; ssize_t result; do { result = recvmsg(mFd, &msg, 0); } while (result == -1 && errno == EINTR); Loading Loading @@ -242,7 +243,7 @@ int BufferReleaseChannel::ProducerEndpoint::writeReleaseFence(const ReleaseCallb memcpy(CMSG_DATA(cmsg), &flattenedFd, sizeof(int)); } int result; ssize_t result; do { result = sendmsg(mFd, &msg, 0); } while (result == -1 && errno == EINTR); Loading