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

Commit bae84b79 authored by Ady Abraham's avatar Ady Abraham Committed by Android (Google) Code Review
Browse files

Merge "SF: call the timer's callback in case of an error"

parents c66a7aa6 3a3815a6
Loading
Loading
Loading
Loading
+23 −7
Original line number Diff line number Diff line
@@ -51,13 +51,25 @@ Timer::~Timer() {
}

void Timer::reset() {
    std::function<void()> cb;
    {
        std::lock_guard lock(mMutex);
        if (mExpectingCallback && mCallback) {
            cb = mCallback;
        }

        cleanup();
        mTimerFd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
        mEpollFd = epoll_create1(EPOLL_CLOEXEC);
        if (pipe2(mPipes.data(), O_CLOEXEC | O_NONBLOCK)) {
            ALOGE("could not create TimerDispatch mPipes");
        return;
    };
        }
    }
    if (cb) {
        setDebugState(DebugState::InCallback);
        cb();
        setDebugState(DebugState::Running);
    }
    setDebugState(DebugState::Reset);
}

@@ -81,6 +93,8 @@ void Timer::cleanup() {
        close(mPipes[kWritePipe]);
        mPipes[kWritePipe] = -1;
    }
    mExpectingCallback = false;
    mCallback = {};
}

void Timer::endDispatch() {
@@ -99,6 +113,7 @@ void Timer::alarmAt(std::function<void()> const& cb, nsecs_t time) {
            std::chrono::duration_cast<std::chrono::nanoseconds>(1s).count();

    mCallback = cb;
    mExpectingCallback = true;

    struct itimerspec old_timer;
    struct itimerspec new_timer {
@@ -198,6 +213,7 @@ bool Timer::dispatch() {
                {
                    std::lock_guard lock(mMutex);
                    cb = mCallback;
                    mExpectingCallback = false;
                }
                if (cb) {
                    setDebugState(DebugState::InCallback);
+8 −3
Original line number Diff line number Diff line
@@ -36,6 +36,10 @@ public:
    void alarmCancel() final;
    void dump(std::string& result) const final;

protected:
    // For unit testing
    int mEpollFd = -1;

private:
    enum class DebugState {
        Reset,
@@ -48,12 +52,12 @@ private:
        ftl_last = Terminated
    };

    void reset();
    void cleanup();
    void reset() EXCLUDES(mMutex);
    void cleanup() REQUIRES(mMutex);
    void setDebugState(DebugState state) EXCLUDES(mMutex);

    int mTimerFd = -1;
    int mEpollFd = -1;

    std::array<int, 2> mPipes = {-1, -1};

    std::thread mDispatchThread;
@@ -63,6 +67,7 @@ private:

    mutable std::mutex mMutex;
    std::function<void()> mCallback GUARDED_BY(mMutex);
    bool mExpectingCallback GUARDED_BY(mMutex) = false;
    DebugState mDebugState GUARDED_BY(mMutex);
};

+19 −1
Original line number Diff line number Diff line
@@ -26,11 +26,19 @@ using namespace std::literals;

namespace android::scheduler {

struct TestableTimer : public Timer {
public:
    void makeEpollError() {
        // close the epoll file descriptor to cause an epoll error
        close(mEpollFd);
    }
};

struct TimerTest : testing::Test {
    static constexpr int mIterations = 20;

    AsyncCallRecorder<void (*)()> mCallbackRecorder;
    Timer mTimer;
    TestableTimer mTimer;

    void timerCallback() { mCallbackRecorder.recordCall(); }
};
@@ -42,4 +50,14 @@ TEST_F(TimerTest, callsCallbackIfScheduledInPast) {
        EXPECT_FALSE(mCallbackRecorder.waitForUnexpectedCall().has_value());
    }
}

TEST_F(TimerTest, recoversAfterEpollError) {
    for (int i = 0; i < mIterations; i++) {
        mTimer.makeEpollError();
        mTimer.alarmAt(std::bind(&TimerTest::timerCallback, this), systemTime() - 10'000'00);
        EXPECT_TRUE(mCallbackRecorder.waitForCall().has_value());
        EXPECT_FALSE(mCallbackRecorder.waitForUnexpectedCall().has_value());
    }
}

} // namespace android::scheduler