|  | /* | 
|  | * Copyright 2018 The Android Open Source Project | 
|  | * | 
|  | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | * you may not use this file except in compliance with the License. | 
|  | * You may obtain a copy of the License at | 
|  | * | 
|  | *      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, software | 
|  | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | * See the License for the specific language governing permissions and | 
|  | * limitations under the License. | 
|  | */ | 
|  |  | 
|  | #define LOG_TAG "BufferHubEventFdTest" | 
|  |  | 
|  | #include <sys/epoll.h> | 
|  | #include <sys/eventfd.h> | 
|  |  | 
|  | #include <array> | 
|  | #include <condition_variable> | 
|  | #include <mutex> | 
|  | #include <thread> | 
|  |  | 
|  | #include <gmock/gmock.h> | 
|  | #include <gtest/gtest.h> | 
|  | #include <log/log.h> | 
|  | #include <ui/BufferHubEventFd.h> | 
|  |  | 
|  | namespace android { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | const int kTimeout = 100; | 
|  | const std::chrono::milliseconds kTimeoutMs(kTimeout); | 
|  |  | 
|  | using ::testing::Contains; | 
|  | using BufferHubEventFdTest = ::testing::Test; | 
|  |  | 
|  | } // namespace | 
|  |  | 
|  | TEST_F(BufferHubEventFdTest, EventFd_testSingleEpollFd) { | 
|  | BufferHubEventFd eventFd; | 
|  | ASSERT_TRUE(eventFd.isValid()); | 
|  |  | 
|  | base::unique_fd epollFd(epoll_create(64)); | 
|  | epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}}; | 
|  |  | 
|  | ASSERT_GE(epollFd.get(), 0); | 
|  | ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0); | 
|  |  | 
|  | std::array<epoll_event, 1> events; | 
|  | EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0); | 
|  |  | 
|  | eventFd.signal(); | 
|  | EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1); | 
|  |  | 
|  | // The epoll fd is edge triggered, so it only responds to the eventFd once. | 
|  | EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0); | 
|  | } | 
|  |  | 
|  | TEST_F(BufferHubEventFdTest, EventFd_testClear) { | 
|  | BufferHubEventFd eventFd; | 
|  | ASSERT_TRUE(eventFd.isValid()); | 
|  |  | 
|  | base::unique_fd epollFd(epoll_create(64)); | 
|  | epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}}; | 
|  |  | 
|  | ASSERT_GE(epollFd.get(), 0); | 
|  | ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0); | 
|  |  | 
|  | eventFd.signal(); | 
|  | eventFd.clear(); | 
|  |  | 
|  | std::array<epoll_event, 1> events; | 
|  | EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0); | 
|  | } | 
|  |  | 
|  | TEST_F(BufferHubEventFdTest, EventFd_testDupEventFd) { | 
|  | BufferHubEventFd eventFd; | 
|  | ASSERT_TRUE(eventFd.isValid()); | 
|  |  | 
|  | base::unique_fd epollFd(epoll_create(64)); | 
|  | epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}}; | 
|  |  | 
|  | ASSERT_GE(epollFd.get(), 0); | 
|  | ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0); | 
|  |  | 
|  | // Technically, the dupliated eventFd and the original eventFd are pointing | 
|  | // to the same kernel object. This test signals the duplicated eventFd but epolls the origianl | 
|  | // eventFd. | 
|  | base::unique_fd dupedEventFd(dup(eventFd.get())); | 
|  | ASSERT_GE(dupedEventFd.get(), 0); | 
|  |  | 
|  | std::array<epoll_event, 1> events; | 
|  | EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0); | 
|  |  | 
|  | eventfd_write(dupedEventFd.get(), 1); | 
|  | EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1); | 
|  |  | 
|  | // The epoll fd is edge triggered, so it only responds to the eventFd once. | 
|  | EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0); | 
|  |  | 
|  | eventfd_write(dupedEventFd.get(), 1); | 
|  |  | 
|  | eventfd_t value; | 
|  | eventfd_read(dupedEventFd.get(), &value); | 
|  | EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0); | 
|  | } | 
|  |  | 
|  | TEST_F(BufferHubEventFdTest, EventFd_testTwoEpollFds) { | 
|  | BufferHubEventFd eventFd; | 
|  | ASSERT_TRUE(eventFd.isValid()); | 
|  |  | 
|  | base::unique_fd epollFd1(epoll_create(64)); | 
|  | base::unique_fd epollFd2(epoll_create(64)); | 
|  | epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}}; | 
|  |  | 
|  | ASSERT_GE(epollFd1.get(), 0); | 
|  | ASSERT_GE(epollFd2.get(), 0); | 
|  |  | 
|  | // Register the same eventFd to two EpollFds. | 
|  | ASSERT_EQ(epoll_ctl(epollFd1.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0); | 
|  | ASSERT_EQ(epoll_ctl(epollFd2.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0); | 
|  |  | 
|  | std::array<epoll_event, 1> events; | 
|  | EXPECT_EQ(epoll_wait(epollFd1.get(), events.data(), events.size(), 0), 0); | 
|  | EXPECT_EQ(epoll_wait(epollFd2.get(), events.data(), events.size(), 0), 0); | 
|  |  | 
|  | eventFd.signal(); | 
|  | EXPECT_EQ(epoll_wait(epollFd1.get(), events.data(), events.size(), 0), 1); | 
|  | EXPECT_EQ(epoll_wait(epollFd2.get(), events.data(), events.size(), 0), 1); | 
|  |  | 
|  | // The epoll fd is edge triggered, so it only responds to the eventFd once. | 
|  | EXPECT_EQ(epoll_wait(epollFd1.get(), events.data(), events.size(), 0), 0); | 
|  | EXPECT_EQ(epoll_wait(epollFd2.get(), events.data(), events.size(), 0), 0); | 
|  |  | 
|  | eventFd.signal(); | 
|  | EXPECT_EQ(epoll_wait(epollFd1.get(), events.data(), events.size(), 0), 1); | 
|  |  | 
|  | eventFd.clear(); | 
|  | EXPECT_EQ(epoll_wait(epollFd1.get(), events.data(), events.size(), 0), 0); | 
|  | EXPECT_EQ(epoll_wait(epollFd2.get(), events.data(), events.size(), 0), 0); | 
|  | } | 
|  |  | 
|  | TEST_F(BufferHubEventFdTest, EventFd_testTwoEventFds) { | 
|  | BufferHubEventFd eventFd1; | 
|  | BufferHubEventFd eventFd2; | 
|  |  | 
|  | ASSERT_TRUE(eventFd1.isValid()); | 
|  | ASSERT_TRUE(eventFd2.isValid()); | 
|  |  | 
|  | base::unique_fd epollFd(epoll_create(64)); | 
|  | epoll_event e1 = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 1}}; | 
|  | epoll_event e2 = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 2}}; | 
|  |  | 
|  | ASSERT_GE(epollFd.get(), 0); | 
|  | ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd1.get(), &e1), 0); | 
|  | ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd2.get(), &e2), 0); | 
|  |  | 
|  | std::array<epoll_event, 2> events; | 
|  | EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0); | 
|  |  | 
|  | // Signal one by one. | 
|  | eventFd1.signal(); | 
|  | EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1); | 
|  | EXPECT_EQ(events[0].data.u32, e1.data.u32); | 
|  |  | 
|  | eventFd2.signal(); | 
|  | EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1); | 
|  | EXPECT_EQ(events[0].data.u32, e2.data.u32); | 
|  |  | 
|  | // Signal both. | 
|  | eventFd1.signal(); | 
|  | eventFd2.signal(); | 
|  | EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 2); | 
|  |  | 
|  | uint32_t u32s[] = {events[0].data.u32, events[1].data.u32}; | 
|  | EXPECT_THAT(u32s, Contains(e1.data.u32)); | 
|  | EXPECT_THAT(u32s, Contains(e2.data.u32)); | 
|  |  | 
|  | // The epoll fd is edge triggered, so it only responds to the eventFd once. | 
|  | EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0); | 
|  |  | 
|  | eventFd1.signal(); | 
|  | eventFd2.signal(); | 
|  | eventFd2.clear(); | 
|  | EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1); | 
|  | } | 
|  |  | 
|  | TEST_F(BufferHubEventFdTest, EventFd_testPollingThreadWithTwoEventFds) { | 
|  | BufferHubEventFd eventFd1; | 
|  | BufferHubEventFd eventFd2; | 
|  |  | 
|  | ASSERT_TRUE(eventFd1.isValid()); | 
|  | ASSERT_TRUE(eventFd2.isValid()); | 
|  |  | 
|  | base::unique_fd epollFd(epoll_create(64)); | 
|  | epoll_event e1 = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 1}}; | 
|  | epoll_event e2 = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 2}}; | 
|  |  | 
|  | ASSERT_GE(epollFd.get(), 0); | 
|  | ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd1.get(), &e1), 0); | 
|  | ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd2.get(), &e2), 0); | 
|  |  | 
|  | int countEvent1 = 0; | 
|  | int countEvent2 = 0; | 
|  | std::atomic<bool> stop{false}; | 
|  | std::mutex mx; | 
|  | std::condition_variable cv; | 
|  |  | 
|  | std::thread pollingThread([&] { | 
|  | std::array<epoll_event, 2> events; | 
|  | while (true) { | 
|  | if (stop.load()) { | 
|  | break; | 
|  | } | 
|  | int ret = epoll_wait(epollFd.get(), events.data(), events.size(), kTimeout); | 
|  | ALOGE_IF(ret < 0 && errno != ETIMEDOUT, "Epoll failed."); | 
|  |  | 
|  | std::lock_guard<std::mutex> lock(mx); | 
|  | for (int i = 0; i < ret; i++) { | 
|  | if (events[i].data.u32 == e1.data.u32) { | 
|  | countEvent1++; | 
|  | cv.notify_one(); | 
|  | } else if (events[i].data.u32 == e2.data.u32) { | 
|  | countEvent2++; | 
|  | cv.notify_one(); | 
|  | } | 
|  | } | 
|  | } | 
|  | }); | 
|  |  | 
|  | { | 
|  | std::unique_lock<std::mutex> lock(mx); | 
|  |  | 
|  | eventFd1.signal(); | 
|  | EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEvent1 == 1; })); | 
|  |  | 
|  | eventFd1.signal(); | 
|  | EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEvent1 == 2; })); | 
|  |  | 
|  | eventFd2.signal(); | 
|  | EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEvent2 == 1; })); | 
|  |  | 
|  | eventFd1.clear(); | 
|  | eventFd2.clear(); | 
|  | EXPECT_EQ(countEvent1, 2); | 
|  | EXPECT_EQ(countEvent2, 1); | 
|  |  | 
|  | eventFd1.signal(); | 
|  | EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEvent1 == 3; })); | 
|  |  | 
|  | eventFd2.signal(); | 
|  | EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEvent2 == 2; })); | 
|  | } | 
|  |  | 
|  | stop.store(true); | 
|  | pollingThread.join(); | 
|  | } | 
|  |  | 
|  | TEST_F(BufferHubEventFdTest, EventFd_testTwoPollingThreads) { | 
|  | BufferHubEventFd eventFd; | 
|  | ASSERT_TRUE(eventFd.isValid()); | 
|  |  | 
|  | base::unique_fd epollFd1(epoll_create(64)); | 
|  | base::unique_fd epollFd2(epoll_create(64)); | 
|  | epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}}; | 
|  |  | 
|  | ASSERT_GE(epollFd1.get(), 0); | 
|  | ASSERT_GE(epollFd2.get(), 0); | 
|  |  | 
|  | // Register the same eventFd to two EpollFds. | 
|  | ASSERT_EQ(epoll_ctl(epollFd1.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0); | 
|  | ASSERT_EQ(epoll_ctl(epollFd2.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0); | 
|  |  | 
|  | int countEpoll1 = 0; | 
|  | int countEpoll2 = 0; | 
|  | std::atomic<bool> stop{false}; | 
|  | std::mutex mx; | 
|  | std::condition_variable cv; | 
|  |  | 
|  | std::thread pollingThread1([&] { | 
|  | std::array<epoll_event, 1> events; | 
|  | while (!stop.load()) { | 
|  | int ret = epoll_wait(epollFd1.get(), events.data(), events.size(), kTimeout); | 
|  | ALOGE_IF(ret < 0 && errno != ETIMEDOUT, "Epoll failed."); | 
|  |  | 
|  | if (ret > 0) { | 
|  | std::lock_guard<std::mutex> lock(mx); | 
|  | countEpoll1++; | 
|  | cv.notify_one(); | 
|  | } | 
|  | } | 
|  | }); | 
|  |  | 
|  | std::thread pollingThread2([&] { | 
|  | std::array<epoll_event, 1> events; | 
|  | while (!stop.load()) { | 
|  | int ret = epoll_wait(epollFd2.get(), events.data(), events.size(), kTimeout); | 
|  | ALOGE_IF(ret < 0 && errno != ETIMEDOUT, "Epoll failed."); | 
|  |  | 
|  | if (ret > 0) { | 
|  | std::lock_guard<std::mutex> lock(mx); | 
|  | countEpoll2++; | 
|  | cv.notify_one(); | 
|  | } | 
|  | } | 
|  | }); | 
|  |  | 
|  | { | 
|  | std::unique_lock<std::mutex> lock(mx); | 
|  |  | 
|  | eventFd.signal(); | 
|  | EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEpoll1 == 1; })); | 
|  | EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEpoll2 == 1; })); | 
|  |  | 
|  | eventFd.signal(); | 
|  | EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEpoll1 == 2; })); | 
|  | EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEpoll2 == 2; })); | 
|  |  | 
|  | eventFd.clear(); | 
|  | EXPECT_EQ(countEpoll1, 2); | 
|  | EXPECT_EQ(countEpoll2, 2); | 
|  |  | 
|  | eventFd.signal(); | 
|  | EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEpoll1 == 3; })); | 
|  | EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEpoll2 == 3; })); | 
|  | } | 
|  |  | 
|  | stop.store(true); | 
|  | pollingThread1.join(); | 
|  | pollingThread2.join(); | 
|  | } | 
|  |  | 
|  | } // namespace android |