Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9341d9d9 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "C2Fence: properly handle signal interruption of pipe fence wait" into main

parents c3b1d486 00b59e6a
Loading
Loading
Loading
Loading
+62 −59
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include <android-base/unique_fd.h>
#include <cutils/native_handle.h>
#include <utils/Log.h>
#include <utils/SystemClock.h>
#include <ui/Fence.h>

#include <C2FenceFactory.h>
@@ -631,26 +632,39 @@ C2Fence _C2FenceFactory::CreateMultiSyncFence(
 */
class _C2FenceFactory::PipeFenceImpl: public C2Fence::Impl {
private:
    bool waitEvent(c2_nsecs_t timeoutNs, bool *hangUp, bool *event) const {
    // Wait for an event using ::ppoll() and handle any interruptions by signals
    // (EINTR) by retrying and accounting for time already waited.
    // Note: while ppoll in theory supports blocking signals, Linux NPTL library does
    // not allow blocking 2 realtime signals (see man nptl), so we do need to handle
    // signal interruptions.
    bool waitEvent(c2_nsecs_t timeoutNs, bool *hangUp) const {
        if (!mValid) {
            *hangUp = true;
            return true;
            return false;
        }

        struct pollfd pfd;
        pfd.fd = mPipeFd.get();
        pfd.events = POLLIN;
        pfd.revents = 0;
        struct timespec ts;
        int64_t waitTimeNs = kPipeFenceWaitLimitSecs * 1000000000LL;
        if (timeoutNs >= 0) {
            ts.tv_sec = int(timeoutNs / 1000000000);
            ts.tv_nsec = timeoutNs % 1000000000;
            waitTimeNs = timeoutNs;
        } else {
            ALOGD("polling for indefinite duration requested, but changed to wait for %d sec",
                  kPipeFenceWaitLimitSecs);
            ts.tv_sec = kPipeFenceWaitLimitSecs;
            ts.tv_nsec = 0;
        }

        int64_t startTsNs = android::elapsedRealtimeNano();
        int64_t elapsedTsNs = 0;
        int tryNum = 0;
        int noEvent = 0;
        do {
            struct pollfd pfd;
            pfd.fd = mPipeFd.get();
            pfd.events = POLLIN;
            pfd.revents = 0;
            struct timespec ts;

            ts.tv_sec = int((waitTimeNs - elapsedTsNs) / 1000000000);
            ts.tv_nsec = (waitTimeNs - elapsedTsNs) % 1000000000;
            ++tryNum;
            int ret = ::ppoll(&pfd, 1, &ts, nullptr);
            if (ret >= 0) {
                if (pfd.revents) {
@@ -659,22 +673,25 @@ private:
                        *hangUp = true;
                        mValid = false;
                        ALOGD("PipeFenceImpl: pipe fd hangup or err event returned");
                        return false;
                    }
                *event = true;
                return true;
            }
            // event not ready yet.
                    return true;
                }
        if (errno == EINTR) {
            // poll() was cancelled by signal or inner kernel status.
            return false;
        }
        // Since poll error happened here, treat the error is irrecoverable.
                ++noEvent;
                // retry if the deadline does not meet yet.
            } else if (errno != EINTR) {
                ALOGE("PipeFenceImpl: poll() error %d", errno);
                *hangUp = true;
                mValid = false;
        return true;
                return false;
            }
            elapsedTsNs = android::elapsedRealtimeNano() - startTsNs;
        } while (elapsedTsNs < waitTimeNs);
        // EINTR till the end.
        // treat this as event not ready yet.
        ALOGV("PipeFenceImpl: tried %d times NoEvent %d times, spent %lld nanosecs",
              tryNum, noEvent, (long long)elapsedTsNs);
        return false;
    }

public:
@@ -683,8 +700,7 @@ public:
            return C2_BAD_STATE;
        }
        bool hangUp = false;
        bool event = false;
        if (waitEvent(timeoutNs, &hangUp, &event)) {
        bool event = waitEvent(timeoutNs, &hangUp);
        if (hangUp) {
            return C2_BAD_STATE;
        }
@@ -692,9 +708,6 @@ public:
            return C2_OK;
        }
        return C2_TIMED_OUT;
        } else {
            return C2_CANCELED;
        }
    }

    virtual bool valid() const {
@@ -702,13 +715,8 @@ public:
            return false;
        }
        bool hangUp = false;
        bool event = false;
        if (waitEvent(0, &hangUp, &event)) {
            if (hangUp) {
                return false;
            }
        }
        return true;
        (void)waitEvent(0, &hangUp);
        return !hangUp;
    }

    virtual bool ready() const {
@@ -716,13 +724,8 @@ public:
            return false;
        }
        bool hangUp = false;
        bool event = false;
        if (waitEvent(0, &hangUp, &event)) {
            if (event) {
                return true;
            }
        }
        return false;
        bool event = waitEvent(0, &hangUp);
        return event;
    }

    virtual int fd() const {