| Alex Vakulenko | e4eec20 | 2017-01-27 14:41:04 -0800 | [diff] [blame] | 1 | #include <gtest/gtest.h> | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 2 | #include <poll.h> | 
| Alex Vakulenko | e4eec20 | 2017-01-27 14:41:04 -0800 | [diff] [blame] | 3 | #include <private/dvr/buffer_hub_client.h> | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 4 | #include <private/dvr/bufferhub_rpc.h> | 
 | 5 | #include <sys/epoll.h> | 
 | 6 | #include <sys/eventfd.h> | 
| Alex Vakulenko | e4eec20 | 2017-01-27 14:41:04 -0800 | [diff] [blame] | 7 |  | 
 | 8 | #include <mutex> | 
 | 9 | #include <thread> | 
 | 10 |  | 
| Alex Vakulenko | 4fe6058 | 2017-02-02 11:35:59 -0800 | [diff] [blame] | 11 | #define RETRY_EINTR(fnc_call)                 \ | 
 | 12 |   ([&]() -> decltype(fnc_call) {              \ | 
 | 13 |     decltype(fnc_call) result;                \ | 
 | 14 |     do {                                      \ | 
 | 15 |       result = (fnc_call);                    \ | 
 | 16 |     } while (result == -1 && errno == EINTR); \ | 
 | 17 |     return result;                            \ | 
 | 18 |   })() | 
 | 19 |  | 
| Alex Vakulenko | e4eec20 | 2017-01-27 14:41:04 -0800 | [diff] [blame] | 20 | using android::dvr::BufferConsumer; | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 21 | using android::dvr::BufferHubDefs::kConsumerStateMask; | 
 | 22 | using android::dvr::BufferHubDefs::kProducerStateBit; | 
| Jiwen 'Steve' Cai | 9e7f303 | 2017-10-20 18:39:47 -0700 | [diff] [blame] | 23 | using android::dvr::BufferHubDefs::IsBufferGained; | 
 | 24 | using android::dvr::BufferHubDefs::IsBufferPosted; | 
 | 25 | using android::dvr::BufferHubDefs::IsBufferAcquired; | 
 | 26 | using android::dvr::BufferHubDefs::IsBufferReleased; | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 27 | using android::dvr::BufferProducer; | 
| Jiwen 'Steve' Cai | 23c1a73 | 2018-03-12 12:16:47 -0700 | [diff] [blame] | 28 | using android::pdx::LocalChannelHandle; | 
| Alex Vakulenko | e4eec20 | 2017-01-27 14:41:04 -0800 | [diff] [blame] | 29 | using android::pdx::LocalHandle; | 
| Jiwen 'Steve' Cai | 23c1a73 | 2018-03-12 12:16:47 -0700 | [diff] [blame] | 30 | using android::pdx::Status; | 
| Alex Vakulenko | e4eec20 | 2017-01-27 14:41:04 -0800 | [diff] [blame] | 31 |  | 
 | 32 | const int kWidth = 640; | 
 | 33 | const int kHeight = 480; | 
 | 34 | const int kFormat = HAL_PIXEL_FORMAT_RGBA_8888; | 
 | 35 | const int kUsage = 0; | 
 | 36 | const uint64_t kContext = 42; | 
| Jiwen 'Steve' Cai | 9e7f303 | 2017-10-20 18:39:47 -0700 | [diff] [blame] | 37 | const size_t kMaxConsumerCount = 63; | 
| Jiwen 'Steve' Cai | 30be111 | 2017-11-08 17:12:20 -0800 | [diff] [blame] | 38 | const int kPollTimeoutMs = 100; | 
| Alex Vakulenko | e4eec20 | 2017-01-27 14:41:04 -0800 | [diff] [blame] | 39 |  | 
 | 40 | using LibBufferHubTest = ::testing::Test; | 
 | 41 |  | 
 | 42 | TEST_F(LibBufferHubTest, TestBasicUsage) { | 
 | 43 |   std::unique_ptr<BufferProducer> p = BufferProducer::Create( | 
 | 44 |       kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); | 
 | 45 |   ASSERT_TRUE(p.get() != nullptr); | 
 | 46 |   std::unique_ptr<BufferConsumer> c = | 
 | 47 |       BufferConsumer::Import(p->CreateConsumer()); | 
 | 48 |   ASSERT_TRUE(c.get() != nullptr); | 
 | 49 |   // Check that consumers can spawn other consumers. | 
 | 50 |   std::unique_ptr<BufferConsumer> c2 = | 
 | 51 |       BufferConsumer::Import(c->CreateConsumer()); | 
 | 52 |   ASSERT_TRUE(c2.get() != nullptr); | 
 | 53 |  | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 54 |   // Producer state mask is unique, i.e. 1. | 
 | 55 |   EXPECT_EQ(p->buffer_state_bit(), kProducerStateBit); | 
 | 56 |   // Consumer state mask cannot have producer bit on. | 
| Jiwen 'Steve' Cai | 30be111 | 2017-11-08 17:12:20 -0800 | [diff] [blame] | 57 |   EXPECT_EQ(c->buffer_state_bit() & kProducerStateBit, 0U); | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 58 |   // Consumer state mask must be a single, i.e. power of 2. | 
| Jiwen 'Steve' Cai | 30be111 | 2017-11-08 17:12:20 -0800 | [diff] [blame] | 59 |   EXPECT_NE(c->buffer_state_bit(), 0U); | 
 | 60 |   EXPECT_EQ(c->buffer_state_bit() & (c->buffer_state_bit() - 1), 0U); | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 61 |   // Consumer state mask cannot have producer bit on. | 
| Jiwen 'Steve' Cai | 30be111 | 2017-11-08 17:12:20 -0800 | [diff] [blame] | 62 |   EXPECT_EQ(c2->buffer_state_bit() & kProducerStateBit, 0U); | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 63 |   // Consumer state mask must be a single, i.e. power of 2. | 
| Jiwen 'Steve' Cai | 30be111 | 2017-11-08 17:12:20 -0800 | [diff] [blame] | 64 |   EXPECT_NE(c2->buffer_state_bit(), 0U); | 
 | 65 |   EXPECT_EQ(c2->buffer_state_bit() & (c2->buffer_state_bit() - 1), 0U); | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 66 |   // Each consumer should have unique bit. | 
| Jiwen 'Steve' Cai | 30be111 | 2017-11-08 17:12:20 -0800 | [diff] [blame] | 67 |   EXPECT_EQ(c->buffer_state_bit() & c2->buffer_state_bit(), 0U); | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 68 |  | 
 | 69 |   // Initial state: producer not available, consumers not available. | 
| Jiwen 'Steve' Cai | 30be111 | 2017-11-08 17:12:20 -0800 | [diff] [blame] | 70 |   EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs))); | 
 | 71 |   EXPECT_EQ(0, RETRY_EINTR(c->Poll(kPollTimeoutMs))); | 
 | 72 |   EXPECT_EQ(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs))); | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 73 |  | 
| Alex Vakulenko | e4eec20 | 2017-01-27 14:41:04 -0800 | [diff] [blame] | 74 |   EXPECT_EQ(0, p->Post(LocalHandle(), kContext)); | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 75 |  | 
 | 76 |   // New state: producer not available, consumers available. | 
| Jiwen 'Steve' Cai | 30be111 | 2017-11-08 17:12:20 -0800 | [diff] [blame] | 77 |   EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs))); | 
 | 78 |   EXPECT_EQ(1, RETRY_EINTR(c->Poll(kPollTimeoutMs))); | 
 | 79 |   EXPECT_EQ(1, RETRY_EINTR(c2->Poll(kPollTimeoutMs))); | 
| Alex Vakulenko | e4eec20 | 2017-01-27 14:41:04 -0800 | [diff] [blame] | 80 |  | 
 | 81 |   uint64_t context; | 
 | 82 |   LocalHandle fence; | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 83 |   EXPECT_EQ(0, c->Acquire(&fence, &context)); | 
| Alex Vakulenko | e4eec20 | 2017-01-27 14:41:04 -0800 | [diff] [blame] | 84 |   EXPECT_EQ(kContext, context); | 
| Jiwen 'Steve' Cai | 30be111 | 2017-11-08 17:12:20 -0800 | [diff] [blame] | 85 |   EXPECT_EQ(0, RETRY_EINTR(c->Poll(kPollTimeoutMs))); | 
 | 86 |   EXPECT_EQ(1, RETRY_EINTR(c2->Poll(kPollTimeoutMs))); | 
| Alex Vakulenko | e4eec20 | 2017-01-27 14:41:04 -0800 | [diff] [blame] | 87 |  | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 88 |   EXPECT_EQ(0, c2->Acquire(&fence, &context)); | 
| Alex Vakulenko | e4eec20 | 2017-01-27 14:41:04 -0800 | [diff] [blame] | 89 |   EXPECT_EQ(kContext, context); | 
| Jiwen 'Steve' Cai | 30be111 | 2017-11-08 17:12:20 -0800 | [diff] [blame] | 90 |   EXPECT_EQ(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs))); | 
 | 91 |   EXPECT_EQ(0, RETRY_EINTR(c->Poll(kPollTimeoutMs))); | 
| Alex Vakulenko | e4eec20 | 2017-01-27 14:41:04 -0800 | [diff] [blame] | 92 |  | 
 | 93 |   EXPECT_EQ(0, c->Release(LocalHandle())); | 
| Jiwen 'Steve' Cai | 30be111 | 2017-11-08 17:12:20 -0800 | [diff] [blame] | 94 |   EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs))); | 
| Alex Vakulenko | e4eec20 | 2017-01-27 14:41:04 -0800 | [diff] [blame] | 95 |   EXPECT_EQ(0, c2->Discard()); | 
 | 96 |  | 
| Jiwen 'Steve' Cai | 30be111 | 2017-11-08 17:12:20 -0800 | [diff] [blame] | 97 |   EXPECT_EQ(1, RETRY_EINTR(p->Poll(kPollTimeoutMs))); | 
| Alex Vakulenko | e4eec20 | 2017-01-27 14:41:04 -0800 | [diff] [blame] | 98 |   EXPECT_EQ(0, p->Gain(&fence)); | 
| Jiwen 'Steve' Cai | 30be111 | 2017-11-08 17:12:20 -0800 | [diff] [blame] | 99 |   EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs))); | 
 | 100 |   EXPECT_EQ(0, RETRY_EINTR(c->Poll(kPollTimeoutMs))); | 
 | 101 |   EXPECT_EQ(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs))); | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 102 | } | 
 | 103 |  | 
 | 104 | TEST_F(LibBufferHubTest, TestEpoll) { | 
 | 105 |   std::unique_ptr<BufferProducer> p = BufferProducer::Create( | 
 | 106 |       kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); | 
 | 107 |   ASSERT_TRUE(p.get() != nullptr); | 
 | 108 |   std::unique_ptr<BufferConsumer> c = | 
 | 109 |       BufferConsumer::Import(p->CreateConsumer()); | 
 | 110 |   ASSERT_TRUE(c.get() != nullptr); | 
 | 111 |  | 
 | 112 |   LocalHandle epoll_fd{epoll_create1(EPOLL_CLOEXEC)}; | 
 | 113 |   ASSERT_TRUE(epoll_fd.IsValid()); | 
 | 114 |  | 
 | 115 |   epoll_event event; | 
 | 116 |   std::array<epoll_event, 64> events; | 
 | 117 |  | 
 | 118 |   auto event_sources = p->GetEventSources(); | 
 | 119 |   ASSERT_LT(event_sources.size(), events.size()); | 
 | 120 |  | 
 | 121 |   for (const auto& event_source : event_sources) { | 
 | 122 |     event = {.events = event_source.event_mask | EPOLLET, | 
 | 123 |              .data = {.fd = p->event_fd()}}; | 
 | 124 |     ASSERT_EQ(0, epoll_ctl(epoll_fd.Get(), EPOLL_CTL_ADD, event_source.event_fd, | 
 | 125 |                            &event)); | 
 | 126 |   } | 
 | 127 |  | 
 | 128 |   event_sources = c->GetEventSources(); | 
 | 129 |   ASSERT_LT(event_sources.size(), events.size()); | 
 | 130 |  | 
 | 131 |   for (const auto& event_source : event_sources) { | 
 | 132 |     event = {.events = event_source.event_mask | EPOLLET, | 
 | 133 |              .data = {.fd = c->event_fd()}}; | 
 | 134 |     ASSERT_EQ(0, epoll_ctl(epoll_fd.Get(), EPOLL_CTL_ADD, event_source.event_fd, | 
 | 135 |                            &event)); | 
 | 136 |   } | 
 | 137 |  | 
 | 138 |   // No events should be signaled initially. | 
 | 139 |   ASSERT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 0)); | 
 | 140 |  | 
 | 141 |   // Post the producer and check for consumer signal. | 
 | 142 |   EXPECT_EQ(0, p->Post({}, kContext)); | 
| Jiwen 'Steve' Cai | 30be111 | 2017-11-08 17:12:20 -0800 | [diff] [blame] | 143 |   ASSERT_EQ(1, epoll_wait(epoll_fd.Get(), events.data(), events.size(), | 
 | 144 |                           kPollTimeoutMs)); | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 145 |   ASSERT_TRUE(events[0].events & EPOLLIN); | 
 | 146 |   ASSERT_EQ(c->event_fd(), events[0].data.fd); | 
 | 147 |  | 
 | 148 |   // Save the event bits to translate later. | 
 | 149 |   event = events[0]; | 
 | 150 |  | 
 | 151 |   // Check for events again. Edge-triggered mode should prevent any. | 
| Jiwen 'Steve' Cai | 30be111 | 2017-11-08 17:12:20 -0800 | [diff] [blame] | 152 |   EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), | 
 | 153 |                           kPollTimeoutMs)); | 
 | 154 |   EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), | 
 | 155 |                           kPollTimeoutMs)); | 
 | 156 |   EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), | 
 | 157 |                           kPollTimeoutMs)); | 
 | 158 |   EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), | 
 | 159 |                           kPollTimeoutMs)); | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 160 |  | 
 | 161 |   // Translate the events. | 
 | 162 |   auto event_status = c->GetEventMask(event.events); | 
 | 163 |   ASSERT_TRUE(event_status); | 
 | 164 |   ASSERT_TRUE(event_status.get() & EPOLLIN); | 
 | 165 |  | 
 | 166 |   // Check for events again. Edge-triggered mode should prevent any. | 
| Jiwen 'Steve' Cai | 30be111 | 2017-11-08 17:12:20 -0800 | [diff] [blame] | 167 |   EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), | 
 | 168 |                           kPollTimeoutMs)); | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 169 | } | 
 | 170 |  | 
 | 171 | TEST_F(LibBufferHubTest, TestStateMask) { | 
 | 172 |   std::unique_ptr<BufferProducer> p = BufferProducer::Create( | 
 | 173 |       kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); | 
 | 174 |   ASSERT_TRUE(p.get() != nullptr); | 
 | 175 |  | 
| Jiwen 'Steve' Cai | 9e7f303 | 2017-10-20 18:39:47 -0700 | [diff] [blame] | 176 |   // It's ok to create up to kMaxConsumerCount consumer buffers. | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 177 |   uint64_t buffer_state_bits = p->buffer_state_bit(); | 
| Jiwen 'Steve' Cai | 9e7f303 | 2017-10-20 18:39:47 -0700 | [diff] [blame] | 178 |   std::array<std::unique_ptr<BufferConsumer>, kMaxConsumerCount> cs; | 
 | 179 |   for (size_t i = 0; i < kMaxConsumerCount; i++) { | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 180 |     cs[i] = BufferConsumer::Import(p->CreateConsumer()); | 
 | 181 |     ASSERT_TRUE(cs[i].get() != nullptr); | 
 | 182 |     // Expect all buffers have unique state mask. | 
| Jiwen 'Steve' Cai | 30be111 | 2017-11-08 17:12:20 -0800 | [diff] [blame] | 183 |     EXPECT_EQ(buffer_state_bits & cs[i]->buffer_state_bit(), 0U); | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 184 |     buffer_state_bits |= cs[i]->buffer_state_bit(); | 
 | 185 |   } | 
 | 186 |   EXPECT_EQ(buffer_state_bits, kProducerStateBit | kConsumerStateMask); | 
 | 187 |  | 
 | 188 |   // The 64th creation will fail with out-of-memory error. | 
 | 189 |   auto state = p->CreateConsumer(); | 
 | 190 |   EXPECT_EQ(state.error(), E2BIG); | 
 | 191 |  | 
 | 192 |   // Release any consumer should allow us to re-create. | 
| Jiwen 'Steve' Cai | 9e7f303 | 2017-10-20 18:39:47 -0700 | [diff] [blame] | 193 |   for (size_t i = 0; i < kMaxConsumerCount; i++) { | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 194 |     buffer_state_bits &= ~cs[i]->buffer_state_bit(); | 
 | 195 |     cs[i] = nullptr; | 
 | 196 |     cs[i] = BufferConsumer::Import(p->CreateConsumer()); | 
 | 197 |     ASSERT_TRUE(cs[i].get() != nullptr); | 
 | 198 |     // The released state mask will be reused. | 
| Jiwen 'Steve' Cai | 30be111 | 2017-11-08 17:12:20 -0800 | [diff] [blame] | 199 |     EXPECT_EQ(buffer_state_bits & cs[i]->buffer_state_bit(), 0U); | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 200 |     buffer_state_bits |= cs[i]->buffer_state_bit(); | 
 | 201 |     EXPECT_EQ(buffer_state_bits, kProducerStateBit | kConsumerStateMask); | 
 | 202 |   } | 
| Alex Vakulenko | e4eec20 | 2017-01-27 14:41:04 -0800 | [diff] [blame] | 203 | } | 
 | 204 |  | 
| Corey Tabaka | d53870c | 2017-07-06 18:04:27 -0700 | [diff] [blame] | 205 | TEST_F(LibBufferHubTest, TestStateTransitions) { | 
 | 206 |   std::unique_ptr<BufferProducer> p = BufferProducer::Create( | 
 | 207 |       kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); | 
 | 208 |   ASSERT_TRUE(p.get() != nullptr); | 
 | 209 |   std::unique_ptr<BufferConsumer> c = | 
 | 210 |       BufferConsumer::Import(p->CreateConsumer()); | 
 | 211 |   ASSERT_TRUE(c.get() != nullptr); | 
 | 212 |  | 
 | 213 |   uint64_t context; | 
 | 214 |   LocalHandle fence; | 
 | 215 |  | 
 | 216 |   // The producer buffer starts in gained state. | 
 | 217 |  | 
 | 218 |   // Acquire, release, and gain in gained state should fail. | 
 | 219 |   EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context)); | 
 | 220 |   EXPECT_EQ(-EBUSY, c->Release(LocalHandle())); | 
 | 221 |   EXPECT_EQ(-EALREADY, p->Gain(&fence)); | 
 | 222 |  | 
 | 223 |   // Post in gained state should succeed. | 
 | 224 |   EXPECT_EQ(0, p->Post(LocalHandle(), kContext)); | 
 | 225 |  | 
 | 226 |   // Post, release, and gain in posted state should fail. | 
 | 227 |   EXPECT_EQ(-EBUSY, p->Post(LocalHandle(), kContext)); | 
 | 228 |   EXPECT_EQ(-EBUSY, c->Release(LocalHandle())); | 
 | 229 |   EXPECT_EQ(-EBUSY, p->Gain(&fence)); | 
 | 230 |  | 
 | 231 |   // Acquire in posted state should succeed. | 
 | 232 |   EXPECT_LE(0, c->Acquire(&fence, &context)); | 
 | 233 |  | 
 | 234 |   // Acquire, post, and gain in acquired state should fail. | 
 | 235 |   EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context)); | 
 | 236 |   EXPECT_EQ(-EBUSY, p->Post(LocalHandle(), kContext)); | 
 | 237 |   EXPECT_EQ(-EBUSY, p->Gain(&fence)); | 
 | 238 |  | 
 | 239 |   // Release in acquired state should succeed. | 
 | 240 |   EXPECT_EQ(0, c->Release(LocalHandle())); | 
| Jiwen 'Steve' Cai | 30be111 | 2017-11-08 17:12:20 -0800 | [diff] [blame] | 241 |   EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs))); | 
| Corey Tabaka | d53870c | 2017-07-06 18:04:27 -0700 | [diff] [blame] | 242 |  | 
 | 243 |   // Release, acquire, and post in released state should fail. | 
 | 244 |   EXPECT_EQ(-EBUSY, c->Release(LocalHandle())); | 
 | 245 |   EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context)); | 
 | 246 |   EXPECT_EQ(-EBUSY, p->Post(LocalHandle(), kContext)); | 
 | 247 |  | 
 | 248 |   // Gain in released state should succeed. | 
 | 249 |   EXPECT_EQ(0, p->Gain(&fence)); | 
 | 250 |  | 
 | 251 |   // Acquire, release, and gain in gained state should fail. | 
 | 252 |   EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context)); | 
 | 253 |   EXPECT_EQ(-EBUSY, c->Release(LocalHandle())); | 
 | 254 |   EXPECT_EQ(-EALREADY, p->Gain(&fence)); | 
 | 255 | } | 
 | 256 |  | 
| Jiwen 'Steve' Cai | 9e7f303 | 2017-10-20 18:39:47 -0700 | [diff] [blame] | 257 | TEST_F(LibBufferHubTest, TestAsyncStateTransitions) { | 
 | 258 |   std::unique_ptr<BufferProducer> p = BufferProducer::Create( | 
 | 259 |       kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); | 
 | 260 |   ASSERT_TRUE(p.get() != nullptr); | 
 | 261 |   std::unique_ptr<BufferConsumer> c = | 
 | 262 |       BufferConsumer::Import(p->CreateConsumer()); | 
 | 263 |   ASSERT_TRUE(c.get() != nullptr); | 
 | 264 |  | 
 | 265 |   DvrNativeBufferMetadata metadata; | 
 | 266 |   LocalHandle invalid_fence; | 
 | 267 |  | 
 | 268 |   // The producer buffer starts in gained state. | 
 | 269 |  | 
 | 270 |   // Acquire, release, and gain in gained state should fail. | 
 | 271 |   EXPECT_EQ(-EBUSY, c->AcquireAsync(&metadata, &invalid_fence)); | 
 | 272 |   EXPECT_FALSE(invalid_fence.IsValid()); | 
 | 273 |   EXPECT_EQ(-EBUSY, c->ReleaseAsync(&metadata, invalid_fence)); | 
 | 274 |   EXPECT_EQ(-EALREADY, p->GainAsync(&metadata, &invalid_fence)); | 
 | 275 |   EXPECT_FALSE(invalid_fence.IsValid()); | 
 | 276 |  | 
 | 277 |   // Post in gained state should succeed. | 
 | 278 |   EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence)); | 
 | 279 |   EXPECT_EQ(p->buffer_state(), c->buffer_state()); | 
 | 280 |   EXPECT_TRUE(IsBufferPosted(p->buffer_state())); | 
 | 281 |  | 
 | 282 |   // Post, release, and gain in posted state should fail. | 
 | 283 |   EXPECT_EQ(-EBUSY, p->PostAsync(&metadata, invalid_fence)); | 
 | 284 |   EXPECT_EQ(-EBUSY, c->ReleaseAsync(&metadata, invalid_fence)); | 
 | 285 |   EXPECT_EQ(-EBUSY, p->GainAsync(&metadata, &invalid_fence)); | 
 | 286 |   EXPECT_FALSE(invalid_fence.IsValid()); | 
 | 287 |  | 
 | 288 |   // Acquire in posted state should succeed. | 
| Jiwen 'Steve' Cai | 30be111 | 2017-11-08 17:12:20 -0800 | [diff] [blame] | 289 |   EXPECT_LT(0, RETRY_EINTR(c->Poll(kPollTimeoutMs))); | 
| Jiwen 'Steve' Cai | 9e7f303 | 2017-10-20 18:39:47 -0700 | [diff] [blame] | 290 |   EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence)); | 
 | 291 |   EXPECT_FALSE(invalid_fence.IsValid()); | 
 | 292 |   EXPECT_EQ(p->buffer_state(), c->buffer_state()); | 
 | 293 |   EXPECT_TRUE(IsBufferAcquired(p->buffer_state())); | 
 | 294 |  | 
 | 295 |   // Acquire, post, and gain in acquired state should fail. | 
 | 296 |   EXPECT_EQ(-EBUSY, c->AcquireAsync(&metadata, &invalid_fence)); | 
 | 297 |   EXPECT_FALSE(invalid_fence.IsValid()); | 
 | 298 |   EXPECT_EQ(-EBUSY, p->PostAsync(&metadata, invalid_fence)); | 
 | 299 |   EXPECT_EQ(-EBUSY, p->GainAsync(&metadata, &invalid_fence)); | 
 | 300 |   EXPECT_FALSE(invalid_fence.IsValid()); | 
 | 301 |  | 
 | 302 |   // Release in acquired state should succeed. | 
 | 303 |   EXPECT_EQ(0, c->ReleaseAsync(&metadata, invalid_fence)); | 
| Jiwen 'Steve' Cai | 30be111 | 2017-11-08 17:12:20 -0800 | [diff] [blame] | 304 |   EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs))); | 
| Jiwen 'Steve' Cai | 9e7f303 | 2017-10-20 18:39:47 -0700 | [diff] [blame] | 305 |   EXPECT_EQ(p->buffer_state(), c->buffer_state()); | 
 | 306 |   EXPECT_TRUE(IsBufferReleased(p->buffer_state())); | 
 | 307 |  | 
 | 308 |   // Release, acquire, and post in released state should fail. | 
 | 309 |   EXPECT_EQ(-EBUSY, c->ReleaseAsync(&metadata, invalid_fence)); | 
 | 310 |   EXPECT_EQ(-EBUSY, c->AcquireAsync(&metadata, &invalid_fence)); | 
 | 311 |   EXPECT_FALSE(invalid_fence.IsValid()); | 
 | 312 |   EXPECT_EQ(-EBUSY, p->PostAsync(&metadata, invalid_fence)); | 
 | 313 |  | 
 | 314 |   // Gain in released state should succeed. | 
 | 315 |   EXPECT_EQ(0, p->GainAsync(&metadata, &invalid_fence)); | 
 | 316 |   EXPECT_FALSE(invalid_fence.IsValid()); | 
 | 317 |   EXPECT_EQ(p->buffer_state(), c->buffer_state()); | 
 | 318 |   EXPECT_TRUE(IsBufferGained(p->buffer_state())); | 
 | 319 |  | 
 | 320 |   // Acquire, release, and gain in gained state should fail. | 
 | 321 |   EXPECT_EQ(-EBUSY, c->AcquireAsync(&metadata, &invalid_fence)); | 
 | 322 |   EXPECT_FALSE(invalid_fence.IsValid()); | 
 | 323 |   EXPECT_EQ(-EBUSY, c->ReleaseAsync(&metadata, invalid_fence)); | 
 | 324 |   EXPECT_EQ(-EALREADY, p->GainAsync(&metadata, &invalid_fence)); | 
 | 325 |   EXPECT_FALSE(invalid_fence.IsValid()); | 
 | 326 | } | 
 | 327 |  | 
 | 328 | TEST_F(LibBufferHubTest, TestZeroConsumer) { | 
 | 329 |   std::unique_ptr<BufferProducer> p = BufferProducer::Create( | 
 | 330 |       kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); | 
 | 331 |   ASSERT_TRUE(p.get() != nullptr); | 
 | 332 |  | 
 | 333 |   DvrNativeBufferMetadata metadata; | 
 | 334 |   LocalHandle invalid_fence; | 
 | 335 |  | 
 | 336 |   // Newly created. | 
 | 337 |   EXPECT_TRUE(IsBufferGained(p->buffer_state())); | 
 | 338 |   EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence)); | 
 | 339 |   EXPECT_TRUE(IsBufferPosted(p->buffer_state())); | 
 | 340 |  | 
 | 341 |   // The buffer should stay in posted stay until a consumer picks it up. | 
| Jiwen 'Steve' Cai | 30be111 | 2017-11-08 17:12:20 -0800 | [diff] [blame] | 342 |   EXPECT_GE(0, RETRY_EINTR(p->Poll(kPollTimeoutMs))); | 
| Jiwen 'Steve' Cai | 9e7f303 | 2017-10-20 18:39:47 -0700 | [diff] [blame] | 343 |  | 
 | 344 |   // A new consumer should still be able to acquire the buffer immediately. | 
 | 345 |   std::unique_ptr<BufferConsumer> c = | 
 | 346 |       BufferConsumer::Import(p->CreateConsumer()); | 
 | 347 |   ASSERT_TRUE(c.get() != nullptr); | 
 | 348 |   EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence)); | 
 | 349 |   EXPECT_TRUE(IsBufferAcquired(c->buffer_state())); | 
 | 350 | } | 
 | 351 |  | 
 | 352 | TEST_F(LibBufferHubTest, TestMaxConsumers) { | 
 | 353 |   std::unique_ptr<BufferProducer> p = BufferProducer::Create( | 
 | 354 |       kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); | 
 | 355 |   ASSERT_TRUE(p.get() != nullptr); | 
 | 356 |  | 
 | 357 |   std::array<std::unique_ptr<BufferConsumer>, kMaxConsumerCount> cs; | 
 | 358 |   for (size_t i = 0; i < kMaxConsumerCount; i++) { | 
 | 359 |     cs[i] = BufferConsumer::Import(p->CreateConsumer()); | 
 | 360 |     ASSERT_TRUE(cs[i].get() != nullptr); | 
 | 361 |     EXPECT_TRUE(IsBufferGained(cs[i]->buffer_state())); | 
 | 362 |   } | 
 | 363 |  | 
 | 364 |   DvrNativeBufferMetadata metadata; | 
 | 365 |   LocalHandle invalid_fence; | 
 | 366 |  | 
 | 367 |   // Post the producer should trigger all consumers to be available. | 
 | 368 |   EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence)); | 
 | 369 |   EXPECT_TRUE(IsBufferPosted(p->buffer_state())); | 
 | 370 |   for (size_t i = 0; i < kMaxConsumerCount; i++) { | 
 | 371 |     EXPECT_TRUE(IsBufferPosted(cs[i]->buffer_state(), | 
 | 372 |                                cs[i]->buffer_state_bit())); | 
| Jiwen 'Steve' Cai | 30be111 | 2017-11-08 17:12:20 -0800 | [diff] [blame] | 373 |     EXPECT_LT(0, RETRY_EINTR(cs[i]->Poll(kPollTimeoutMs))); | 
| Jiwen 'Steve' Cai | 9e7f303 | 2017-10-20 18:39:47 -0700 | [diff] [blame] | 374 |     EXPECT_EQ(0, cs[i]->AcquireAsync(&metadata, &invalid_fence)); | 
 | 375 |     EXPECT_TRUE(IsBufferAcquired(p->buffer_state())); | 
 | 376 |   } | 
 | 377 |  | 
 | 378 |   // All consumers have to release before the buffer is considered to be | 
 | 379 |   // released. | 
 | 380 |   for (size_t i = 0; i < kMaxConsumerCount; i++) { | 
 | 381 |     EXPECT_FALSE(IsBufferReleased(p->buffer_state())); | 
 | 382 |     EXPECT_EQ(0, cs[i]->ReleaseAsync(&metadata, invalid_fence)); | 
 | 383 |   } | 
 | 384 |  | 
| Jiwen 'Steve' Cai | 30be111 | 2017-11-08 17:12:20 -0800 | [diff] [blame] | 385 |   EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs))); | 
| Jiwen 'Steve' Cai | 9e7f303 | 2017-10-20 18:39:47 -0700 | [diff] [blame] | 386 |   EXPECT_TRUE(IsBufferReleased(p->buffer_state())); | 
 | 387 |  | 
 | 388 |   // Buffer state cross all clients must be consistent. | 
 | 389 |   for (size_t i = 0; i < kMaxConsumerCount; i++) { | 
 | 390 |     EXPECT_EQ(p->buffer_state(), cs[i]->buffer_state()); | 
 | 391 |   } | 
 | 392 | } | 
 | 393 |  | 
 | 394 | TEST_F(LibBufferHubTest, TestCreateConsumerWhenBufferGained) { | 
 | 395 |   std::unique_ptr<BufferProducer> p = BufferProducer::Create( | 
 | 396 |       kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); | 
 | 397 |   ASSERT_TRUE(p.get() != nullptr); | 
 | 398 |   EXPECT_TRUE(IsBufferGained(p->buffer_state())); | 
 | 399 |  | 
 | 400 |   std::unique_ptr<BufferConsumer> c = | 
 | 401 |       BufferConsumer::Import(p->CreateConsumer()); | 
 | 402 |   ASSERT_TRUE(c.get() != nullptr); | 
 | 403 |   EXPECT_TRUE(IsBufferGained(c->buffer_state())); | 
 | 404 |  | 
 | 405 |   DvrNativeBufferMetadata metadata; | 
 | 406 |   LocalHandle invalid_fence; | 
 | 407 |  | 
 | 408 |   // Post the gained buffer should signal already created consumer. | 
 | 409 |   EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence)); | 
 | 410 |   EXPECT_TRUE(IsBufferPosted(p->buffer_state())); | 
| Jiwen 'Steve' Cai | 30be111 | 2017-11-08 17:12:20 -0800 | [diff] [blame] | 411 |   EXPECT_LT(0, RETRY_EINTR(c->Poll(kPollTimeoutMs))); | 
| Jiwen 'Steve' Cai | 9e7f303 | 2017-10-20 18:39:47 -0700 | [diff] [blame] | 412 |   EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence)); | 
 | 413 |   EXPECT_TRUE(IsBufferAcquired(c->buffer_state())); | 
 | 414 | } | 
 | 415 |  | 
 | 416 | TEST_F(LibBufferHubTest, TestCreateConsumerWhenBufferPosted) { | 
 | 417 |   std::unique_ptr<BufferProducer> p = BufferProducer::Create( | 
 | 418 |       kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); | 
 | 419 |   ASSERT_TRUE(p.get() != nullptr); | 
 | 420 |   EXPECT_TRUE(IsBufferGained(p->buffer_state())); | 
 | 421 |  | 
 | 422 |   DvrNativeBufferMetadata metadata; | 
 | 423 |   LocalHandle invalid_fence; | 
 | 424 |  | 
 | 425 |   // Post the gained buffer before any consumer gets created. | 
 | 426 |   EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence)); | 
 | 427 |   EXPECT_TRUE(IsBufferPosted(p->buffer_state())); | 
 | 428 |  | 
 | 429 |   // Newly created consumer should be automatically sigalled. | 
 | 430 |   std::unique_ptr<BufferConsumer> c = | 
 | 431 |       BufferConsumer::Import(p->CreateConsumer()); | 
 | 432 |   ASSERT_TRUE(c.get() != nullptr); | 
 | 433 |   EXPECT_TRUE(IsBufferPosted(c->buffer_state())); | 
 | 434 |   EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence)); | 
 | 435 |   EXPECT_TRUE(IsBufferAcquired(c->buffer_state())); | 
 | 436 | } | 
 | 437 |  | 
 | 438 | TEST_F(LibBufferHubTest, TestCreateConsumerWhenBufferReleased) { | 
 | 439 |   std::unique_ptr<BufferProducer> p = BufferProducer::Create( | 
 | 440 |       kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); | 
 | 441 |   ASSERT_TRUE(p.get() != nullptr); | 
 | 442 |  | 
 | 443 |   std::unique_ptr<BufferConsumer> c1 = | 
 | 444 |       BufferConsumer::Import(p->CreateConsumer()); | 
 | 445 |   ASSERT_TRUE(c1.get() != nullptr); | 
 | 446 |  | 
 | 447 |   DvrNativeBufferMetadata metadata; | 
 | 448 |   LocalHandle invalid_fence; | 
 | 449 |  | 
 | 450 |   // Post, acquire, and release the buffer.. | 
 | 451 |   EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence)); | 
| Jiwen 'Steve' Cai | 30be111 | 2017-11-08 17:12:20 -0800 | [diff] [blame] | 452 |   EXPECT_LT(0, RETRY_EINTR(c1->Poll(kPollTimeoutMs))); | 
| Jiwen 'Steve' Cai | 9e7f303 | 2017-10-20 18:39:47 -0700 | [diff] [blame] | 453 |   EXPECT_EQ(0, c1->AcquireAsync(&metadata, &invalid_fence)); | 
 | 454 |   EXPECT_EQ(0, c1->ReleaseAsync(&metadata, invalid_fence)); | 
 | 455 |  | 
| Jiwen 'Steve' Cai | 2d89e6b | 2017-12-06 16:32:22 -0800 | [diff] [blame] | 456 |   // Note that the next PDX call is on the producer channel, which may be | 
 | 457 |   // executed before Release impulse gets executed by bufferhubd. Thus, here we | 
 | 458 |   // need to wait until the releasd is confirmed before creating another | 
 | 459 |   // consumer. | 
 | 460 |   EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs))); | 
 | 461 |   EXPECT_TRUE(IsBufferReleased(p->buffer_state())); | 
 | 462 |  | 
| Jiwen 'Steve' Cai | 9e7f303 | 2017-10-20 18:39:47 -0700 | [diff] [blame] | 463 |   // Create another consumer immediately after the release, should not make the | 
| Jiwen 'Steve' Cai | 2d89e6b | 2017-12-06 16:32:22 -0800 | [diff] [blame] | 464 |   // buffer un-released. | 
| Jiwen 'Steve' Cai | 9e7f303 | 2017-10-20 18:39:47 -0700 | [diff] [blame] | 465 |   std::unique_ptr<BufferConsumer> c2 = | 
 | 466 |       BufferConsumer::Import(p->CreateConsumer()); | 
 | 467 |   ASSERT_TRUE(c2.get() != nullptr); | 
 | 468 |  | 
| Jiwen 'Steve' Cai | 9e7f303 | 2017-10-20 18:39:47 -0700 | [diff] [blame] | 469 |   EXPECT_TRUE(IsBufferReleased(p->buffer_state())); | 
 | 470 |   EXPECT_EQ(0, p->GainAsync(&metadata, &invalid_fence)); | 
 | 471 |   EXPECT_TRUE(IsBufferGained(p->buffer_state())); | 
 | 472 | } | 
 | 473 |  | 
| Alex Vakulenko | e4eec20 | 2017-01-27 14:41:04 -0800 | [diff] [blame] | 474 | TEST_F(LibBufferHubTest, TestWithCustomMetadata) { | 
 | 475 |   struct Metadata { | 
 | 476 |     int64_t field1; | 
 | 477 |     int64_t field2; | 
 | 478 |   }; | 
 | 479 |   std::unique_ptr<BufferProducer> p = BufferProducer::Create( | 
 | 480 |       kWidth, kHeight, kFormat, kUsage, sizeof(Metadata)); | 
 | 481 |   ASSERT_TRUE(p.get() != nullptr); | 
 | 482 |   std::unique_ptr<BufferConsumer> c = | 
 | 483 |       BufferConsumer::Import(p->CreateConsumer()); | 
 | 484 |   ASSERT_TRUE(c.get() != nullptr); | 
 | 485 |  | 
 | 486 |   Metadata m = {1, 3}; | 
 | 487 |   EXPECT_EQ(0, p->Post(LocalHandle(), m)); | 
| Jiwen 'Steve' Cai | 30be111 | 2017-11-08 17:12:20 -0800 | [diff] [blame] | 488 |   EXPECT_LE(0, RETRY_EINTR(c->Poll(kPollTimeoutMs))); | 
| Alex Vakulenko | e4eec20 | 2017-01-27 14:41:04 -0800 | [diff] [blame] | 489 |  | 
 | 490 |   LocalHandle fence; | 
 | 491 |   Metadata m2 = {}; | 
 | 492 |   EXPECT_EQ(0, c->Acquire(&fence, &m2)); | 
 | 493 |   EXPECT_EQ(m.field1, m2.field1); | 
 | 494 |   EXPECT_EQ(m.field2, m2.field2); | 
 | 495 |  | 
 | 496 |   EXPECT_EQ(0, c->Release(LocalHandle())); | 
| Alex Vakulenko | 4fe6058 | 2017-02-02 11:35:59 -0800 | [diff] [blame] | 497 |   EXPECT_LT(0, RETRY_EINTR(p->Poll(0))); | 
| Alex Vakulenko | e4eec20 | 2017-01-27 14:41:04 -0800 | [diff] [blame] | 498 | } | 
 | 499 |  | 
 | 500 | TEST_F(LibBufferHubTest, TestPostWithWrongMetaSize) { | 
 | 501 |   struct Metadata { | 
 | 502 |     int64_t field1; | 
 | 503 |     int64_t field2; | 
 | 504 |   }; | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 505 |   struct OverSizedMetadata { | 
 | 506 |     int64_t field1; | 
 | 507 |     int64_t field2; | 
 | 508 |     int64_t field3; | 
 | 509 |   }; | 
| Alex Vakulenko | e4eec20 | 2017-01-27 14:41:04 -0800 | [diff] [blame] | 510 |   std::unique_ptr<BufferProducer> p = BufferProducer::Create( | 
 | 511 |       kWidth, kHeight, kFormat, kUsage, sizeof(Metadata)); | 
 | 512 |   ASSERT_TRUE(p.get() != nullptr); | 
 | 513 |   std::unique_ptr<BufferConsumer> c = | 
 | 514 |       BufferConsumer::Import(p->CreateConsumer()); | 
 | 515 |   ASSERT_TRUE(c.get() != nullptr); | 
 | 516 |  | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 517 |   // It is illegal to post metadata larger than originally requested during | 
 | 518 |   // buffer allocation. | 
 | 519 |   OverSizedMetadata evil_meta = {}; | 
 | 520 |   EXPECT_NE(0, p->Post(LocalHandle(), evil_meta)); | 
| Jiwen 'Steve' Cai | 30be111 | 2017-11-08 17:12:20 -0800 | [diff] [blame] | 521 |   EXPECT_GE(0, RETRY_EINTR(c->Poll(kPollTimeoutMs))); | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 522 |  | 
 | 523 |   // It is ok to post metadata smaller than originally requested during | 
 | 524 |   // buffer allocation. | 
 | 525 |   int64_t sequence = 42; | 
 | 526 |   EXPECT_EQ(0, p->Post(LocalHandle(), sequence)); | 
| Alex Vakulenko | e4eec20 | 2017-01-27 14:41:04 -0800 | [diff] [blame] | 527 | } | 
 | 528 |  | 
 | 529 | TEST_F(LibBufferHubTest, TestAcquireWithWrongMetaSize) { | 
 | 530 |   struct Metadata { | 
 | 531 |     int64_t field1; | 
 | 532 |     int64_t field2; | 
 | 533 |   }; | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 534 |   struct OverSizedMetadata { | 
 | 535 |     int64_t field1; | 
 | 536 |     int64_t field2; | 
 | 537 |     int64_t field3; | 
 | 538 |   }; | 
| Alex Vakulenko | e4eec20 | 2017-01-27 14:41:04 -0800 | [diff] [blame] | 539 |   std::unique_ptr<BufferProducer> p = BufferProducer::Create( | 
 | 540 |       kWidth, kHeight, kFormat, kUsage, sizeof(Metadata)); | 
 | 541 |   ASSERT_TRUE(p.get() != nullptr); | 
 | 542 |   std::unique_ptr<BufferConsumer> c = | 
 | 543 |       BufferConsumer::Import(p->CreateConsumer()); | 
 | 544 |   ASSERT_TRUE(c.get() != nullptr); | 
 | 545 |  | 
 | 546 |   Metadata m = {1, 3}; | 
 | 547 |   EXPECT_EQ(0, p->Post(LocalHandle(), m)); | 
 | 548 |  | 
 | 549 |   LocalHandle fence; | 
 | 550 |   int64_t sequence; | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 551 |   OverSizedMetadata e; | 
 | 552 |  | 
 | 553 |   // It is illegal to acquire metadata larger than originally requested during | 
 | 554 |   // buffer allocation. | 
 | 555 |   EXPECT_NE(0, c->Acquire(&fence, &e)); | 
 | 556 |  | 
 | 557 |   // It is ok to acquire metadata smaller than originally requested during | 
 | 558 |   // buffer allocation. | 
 | 559 |   EXPECT_EQ(0, c->Acquire(&fence, &sequence)); | 
 | 560 |   EXPECT_EQ(m.field1, sequence); | 
| Alex Vakulenko | e4eec20 | 2017-01-27 14:41:04 -0800 | [diff] [blame] | 561 | } | 
 | 562 |  | 
 | 563 | TEST_F(LibBufferHubTest, TestAcquireWithNoMeta) { | 
 | 564 |   std::unique_ptr<BufferProducer> p = BufferProducer::Create( | 
 | 565 |       kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); | 
 | 566 |   ASSERT_TRUE(p.get() != nullptr); | 
 | 567 |   std::unique_ptr<BufferConsumer> c = | 
 | 568 |       BufferConsumer::Import(p->CreateConsumer()); | 
 | 569 |   ASSERT_TRUE(c.get() != nullptr); | 
 | 570 |  | 
 | 571 |   int64_t sequence = 3; | 
 | 572 |   EXPECT_EQ(0, p->Post(LocalHandle(), sequence)); | 
 | 573 |  | 
 | 574 |   LocalHandle fence; | 
 | 575 |   EXPECT_EQ(0, c->Acquire(&fence)); | 
 | 576 | } | 
 | 577 |  | 
 | 578 | TEST_F(LibBufferHubTest, TestWithNoMeta) { | 
 | 579 |   std::unique_ptr<BufferProducer> p = | 
 | 580 |       BufferProducer::Create(kWidth, kHeight, kFormat, kUsage); | 
 | 581 |   ASSERT_TRUE(p.get() != nullptr); | 
 | 582 |   std::unique_ptr<BufferConsumer> c = | 
 | 583 |       BufferConsumer::Import(p->CreateConsumer()); | 
 | 584 |   ASSERT_TRUE(c.get() != nullptr); | 
 | 585 |  | 
 | 586 |   LocalHandle fence; | 
 | 587 |  | 
 | 588 |   EXPECT_EQ(0, p->Post<void>(LocalHandle())); | 
 | 589 |   EXPECT_EQ(0, c->Acquire(&fence)); | 
 | 590 | } | 
 | 591 |  | 
 | 592 | TEST_F(LibBufferHubTest, TestFailureToPostMetaFromABufferWithoutMeta) { | 
 | 593 |   std::unique_ptr<BufferProducer> p = | 
 | 594 |       BufferProducer::Create(kWidth, kHeight, kFormat, kUsage); | 
 | 595 |   ASSERT_TRUE(p.get() != nullptr); | 
 | 596 |   std::unique_ptr<BufferConsumer> c = | 
 | 597 |       BufferConsumer::Import(p->CreateConsumer()); | 
 | 598 |   ASSERT_TRUE(c.get() != nullptr); | 
 | 599 |  | 
 | 600 |   int64_t sequence = 3; | 
 | 601 |   EXPECT_NE(0, p->Post(LocalHandle(), sequence)); | 
 | 602 | } | 
 | 603 |  | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 604 | namespace { | 
 | 605 |  | 
 | 606 | int PollFd(int fd, int timeout_ms) { | 
 | 607 |   pollfd p = {fd, POLLIN, 0}; | 
 | 608 |   return poll(&p, 1, timeout_ms); | 
 | 609 | } | 
 | 610 |  | 
 | 611 | }  // namespace | 
 | 612 |  | 
 | 613 | TEST_F(LibBufferHubTest, TestAcquireFence) { | 
 | 614 |   std::unique_ptr<BufferProducer> p = BufferProducer::Create( | 
 | 615 |       kWidth, kHeight, kFormat, kUsage, /*metadata_size=*/0); | 
 | 616 |   ASSERT_TRUE(p.get() != nullptr); | 
 | 617 |   std::unique_ptr<BufferConsumer> c = | 
 | 618 |       BufferConsumer::Import(p->CreateConsumer()); | 
 | 619 |   ASSERT_TRUE(c.get() != nullptr); | 
 | 620 |  | 
 | 621 |   DvrNativeBufferMetadata meta; | 
 | 622 |   LocalHandle f1(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); | 
 | 623 |  | 
 | 624 |   // Post with unsignaled fence. | 
 | 625 |   EXPECT_EQ(0, p->PostAsync(&meta, f1)); | 
 | 626 |  | 
 | 627 |   // Should acquire a valid fence. | 
 | 628 |   LocalHandle f2; | 
| Jiwen 'Steve' Cai | 30be111 | 2017-11-08 17:12:20 -0800 | [diff] [blame] | 629 |   EXPECT_LT(0, RETRY_EINTR(c->Poll(kPollTimeoutMs))); | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 630 |   EXPECT_EQ(0, c->AcquireAsync(&meta, &f2)); | 
 | 631 |   EXPECT_TRUE(f2.IsValid()); | 
 | 632 |   // The original fence and acquired fence should have different fd number. | 
 | 633 |   EXPECT_NE(f1.Get(), f2.Get()); | 
 | 634 |   EXPECT_GE(0, PollFd(f2.Get(), 0)); | 
 | 635 |  | 
 | 636 |   // Signal the original fence will trigger the new fence. | 
 | 637 |   eventfd_write(f1.Get(), 1); | 
 | 638 |   // Now the original FD has been signaled. | 
| Jiwen 'Steve' Cai | 30be111 | 2017-11-08 17:12:20 -0800 | [diff] [blame] | 639 |   EXPECT_LT(0, PollFd(f2.Get(), kPollTimeoutMs)); | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 640 |  | 
 | 641 |   // Release the consumer with an invalid fence. | 
 | 642 |   EXPECT_EQ(0, c->ReleaseAsync(&meta, LocalHandle())); | 
 | 643 |  | 
 | 644 |   // Should gain an invalid fence. | 
 | 645 |   LocalHandle f3; | 
| Jiwen 'Steve' Cai | 30be111 | 2017-11-08 17:12:20 -0800 | [diff] [blame] | 646 |   EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs))); | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 647 |   EXPECT_EQ(0, p->GainAsync(&meta, &f3)); | 
 | 648 |   EXPECT_FALSE(f3.IsValid()); | 
 | 649 |  | 
 | 650 |   // Post with a signaled fence. | 
 | 651 |   EXPECT_EQ(0, p->PostAsync(&meta, f1)); | 
 | 652 |  | 
 | 653 |   // Should acquire a valid fence and it's already signalled. | 
 | 654 |   LocalHandle f4; | 
| Jiwen 'Steve' Cai | 30be111 | 2017-11-08 17:12:20 -0800 | [diff] [blame] | 655 |   EXPECT_LT(0, RETRY_EINTR(c->Poll(kPollTimeoutMs))); | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 656 |   EXPECT_EQ(0, c->AcquireAsync(&meta, &f4)); | 
 | 657 |   EXPECT_TRUE(f4.IsValid()); | 
| Jiwen 'Steve' Cai | 30be111 | 2017-11-08 17:12:20 -0800 | [diff] [blame] | 658 |   EXPECT_LT(0, PollFd(f4.Get(), kPollTimeoutMs)); | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 659 |  | 
 | 660 |   // Release with an unsignalled fence and signal it immediately after release | 
 | 661 |   // without producer gainning. | 
 | 662 |   LocalHandle f5(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); | 
 | 663 |   EXPECT_EQ(0, c->ReleaseAsync(&meta, f5)); | 
 | 664 |   eventfd_write(f5.Get(), 1); | 
 | 665 |  | 
 | 666 |   // Should gain a valid fence, which is already signaled. | 
 | 667 |   LocalHandle f6; | 
| Jiwen 'Steve' Cai | 30be111 | 2017-11-08 17:12:20 -0800 | [diff] [blame] | 668 |   EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs))); | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 669 |   EXPECT_EQ(0, p->GainAsync(&meta, &f6)); | 
 | 670 |   EXPECT_TRUE(f6.IsValid()); | 
| Jiwen 'Steve' Cai | 30be111 | 2017-11-08 17:12:20 -0800 | [diff] [blame] | 671 |   EXPECT_LT(0, PollFd(f6.Get(), kPollTimeoutMs)); | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 672 | } | 
 | 673 |  | 
 | 674 | TEST_F(LibBufferHubTest, TestOrphanedAcquire) { | 
 | 675 |   std::unique_ptr<BufferProducer> p = BufferProducer::Create( | 
 | 676 |       kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); | 
 | 677 |   ASSERT_TRUE(p.get() != nullptr); | 
 | 678 |   std::unique_ptr<BufferConsumer> c1 = | 
 | 679 |       BufferConsumer::Import(p->CreateConsumer()); | 
 | 680 |   ASSERT_TRUE(c1.get() != nullptr); | 
 | 681 |   const uint64_t consumer_state_bit1 = c1->buffer_state_bit(); | 
 | 682 |  | 
 | 683 |   DvrNativeBufferMetadata meta; | 
 | 684 |   EXPECT_EQ(0, p->PostAsync(&meta, LocalHandle())); | 
 | 685 |  | 
 | 686 |   LocalHandle fence; | 
| Jiwen 'Steve' Cai | 30be111 | 2017-11-08 17:12:20 -0800 | [diff] [blame] | 687 |   EXPECT_LT(0, RETRY_EINTR(c1->Poll(kPollTimeoutMs))); | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 688 |   EXPECT_LE(0, c1->AcquireAsync(&meta, &fence)); | 
 | 689 |   // Destroy the consumer now will make it orphaned and the buffer is still | 
 | 690 |   // acquired. | 
 | 691 |   c1 = nullptr; | 
| Jiwen 'Steve' Cai | 30be111 | 2017-11-08 17:12:20 -0800 | [diff] [blame] | 692 |   EXPECT_GE(0, RETRY_EINTR(p->Poll(kPollTimeoutMs))); | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 693 |  | 
 | 694 |   std::unique_ptr<BufferConsumer> c2 = | 
 | 695 |       BufferConsumer::Import(p->CreateConsumer()); | 
 | 696 |   ASSERT_TRUE(c2.get() != nullptr); | 
 | 697 |   const uint64_t consumer_state_bit2 = c2->buffer_state_bit(); | 
 | 698 |   EXPECT_NE(consumer_state_bit1, consumer_state_bit2); | 
 | 699 |  | 
 | 700 |   // The new consumer is available for acquire. | 
| Jiwen 'Steve' Cai | 30be111 | 2017-11-08 17:12:20 -0800 | [diff] [blame] | 701 |   EXPECT_LT(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs))); | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 702 |   EXPECT_LE(0, c2->AcquireAsync(&meta, &fence)); | 
 | 703 |   // Releasing the consumer makes the buffer gainable. | 
 | 704 |   EXPECT_EQ(0, c2->ReleaseAsync(&meta, LocalHandle())); | 
 | 705 |  | 
 | 706 |   // The buffer is now available for the producer to gain. | 
| Jiwen 'Steve' Cai | 30be111 | 2017-11-08 17:12:20 -0800 | [diff] [blame] | 707 |   EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs))); | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 708 |  | 
 | 709 |   // But if another consumer is created in released state. | 
 | 710 |   std::unique_ptr<BufferConsumer> c3 = | 
 | 711 |       BufferConsumer::Import(p->CreateConsumer()); | 
 | 712 |   ASSERT_TRUE(c3.get() != nullptr); | 
 | 713 |   const uint64_t consumer_state_bit3 = c3->buffer_state_bit(); | 
 | 714 |   EXPECT_NE(consumer_state_bit2, consumer_state_bit3); | 
 | 715 |   // The consumer buffer is not acquirable. | 
| Jiwen 'Steve' Cai | 30be111 | 2017-11-08 17:12:20 -0800 | [diff] [blame] | 716 |   EXPECT_GE(0, RETRY_EINTR(c3->Poll(kPollTimeoutMs))); | 
| Corey Tabaka | 52ea25c | 2017-09-13 18:02:48 -0700 | [diff] [blame] | 717 |   EXPECT_EQ(-EBUSY, c3->AcquireAsync(&meta, &fence)); | 
 | 718 |  | 
 | 719 |   // Producer should be able to gain no matter what. | 
 | 720 |   EXPECT_EQ(0, p->GainAsync(&meta, &fence)); | 
 | 721 | } | 
| Jiwen 'Steve' Cai | 23c1a73 | 2018-03-12 12:16:47 -0700 | [diff] [blame] | 722 |  | 
 | 723 | TEST_F(LibBufferHubTest, TestDetachBufferFromProducer) { | 
 | 724 |   std::unique_ptr<BufferProducer> p = BufferProducer::Create( | 
 | 725 |       kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); | 
 | 726 |   std::unique_ptr<BufferConsumer> c = | 
 | 727 |       BufferConsumer::Import(p->CreateConsumer()); | 
 | 728 |   ASSERT_TRUE(p.get() != nullptr); | 
 | 729 |   ASSERT_TRUE(c.get() != nullptr); | 
 | 730 |  | 
 | 731 |   DvrNativeBufferMetadata metadata; | 
 | 732 |   LocalHandle invalid_fence; | 
 | 733 |  | 
 | 734 |   // Detach in posted state should fail. | 
 | 735 |   EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence)); | 
 | 736 |   EXPECT_GT(RETRY_EINTR(c->Poll(kPollTimeoutMs)), 0); | 
 | 737 |   auto s1 = p->Detach(); | 
 | 738 |   EXPECT_FALSE(s1); | 
 | 739 |  | 
 | 740 |   // Detach in acquired state should fail. | 
 | 741 |   EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence)); | 
 | 742 |   s1 = p->Detach(); | 
 | 743 |   EXPECT_FALSE(s1); | 
 | 744 |  | 
 | 745 |   // Detach in released state should fail. | 
 | 746 |   EXPECT_EQ(0, c->ReleaseAsync(&metadata, invalid_fence)); | 
 | 747 |   EXPECT_GT(RETRY_EINTR(p->Poll(kPollTimeoutMs)), 0); | 
 | 748 |   s1 = p->Detach(); | 
 | 749 |   EXPECT_FALSE(s1); | 
 | 750 |  | 
 | 751 |   // Detach in gained state should succeed. | 
 | 752 |   EXPECT_EQ(0, p->GainAsync(&metadata, &invalid_fence)); | 
 | 753 |   s1 = p->Detach(); | 
 | 754 |   EXPECT_TRUE(s1); | 
 | 755 |  | 
 | 756 |   LocalChannelHandle detached_buffer = s1.take(); | 
 | 757 |   EXPECT_TRUE(detached_buffer.valid()); | 
 | 758 |  | 
 | 759 |   // Both producer and consumer should have hangup. | 
 | 760 |   EXPECT_GT(RETRY_EINTR(p->Poll(kPollTimeoutMs)), 0); | 
 | 761 |   auto s2 = p->GetEventMask(POLLHUP); | 
 | 762 |   EXPECT_TRUE(s2); | 
 | 763 |   EXPECT_EQ(s2.get(), POLLHUP); | 
 | 764 |  | 
 | 765 |   EXPECT_GT(RETRY_EINTR(c->Poll(kPollTimeoutMs)), 0); | 
 | 766 |   s2 = p->GetEventMask(POLLHUP); | 
 | 767 |   EXPECT_TRUE(s2); | 
 | 768 |   EXPECT_EQ(s2.get(), POLLHUP); | 
 | 769 |  | 
 | 770 |   auto s3 = p->CreateConsumer(); | 
 | 771 |   EXPECT_FALSE(s3); | 
| Jiwen 'Steve' Cai | fe924f3 | 2018-03-27 13:29:13 -0700 | [diff] [blame] | 772 |   // Note that here the expected error code is EOPNOTSUPP as the socket towards | 
 | 773 |   // ProducerChannel has been teared down. | 
| Jiwen 'Steve' Cai | 23c1a73 | 2018-03-12 12:16:47 -0700 | [diff] [blame] | 774 |   EXPECT_EQ(s3.error(), EOPNOTSUPP); | 
 | 775 |  | 
 | 776 |   s3 = c->CreateConsumer(); | 
 | 777 |   EXPECT_FALSE(s3); | 
| Jiwen 'Steve' Cai | fe924f3 | 2018-03-27 13:29:13 -0700 | [diff] [blame] | 778 |   // Note that here the expected error code is EPIPE returned from | 
 | 779 |   // ConsumerChannel::HandleMessage as the socket is still open but the producer | 
 | 780 |   // is gone. | 
 | 781 |   EXPECT_EQ(s3.error(), EPIPE); | 
| Jiwen 'Steve' Cai | 23c1a73 | 2018-03-12 12:16:47 -0700 | [diff] [blame] | 782 | } |