From ddb0ab8c61ca87dc2ddb8dc577cc5f7a7769ffc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Thu, 9 Nov 2023 11:12:03 -0800 Subject: [PATCH] BpfRingBuf.h - implement wait() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: TreeHugger, atest BpfRingbufTest Signed-off-by: Maciej Żenczykowski Change-Id: I2696077caf4de27dd64e4af1c45a13844ed186c9 --- .../native/bpf_headers/BpfRingbufTest.cpp | 16 ++++++++++++++++ .../native/bpf_headers/include/bpf/BpfRingbuf.h | 17 +++++++++++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/staticlibs/native/bpf_headers/BpfRingbufTest.cpp b/staticlibs/native/bpf_headers/BpfRingbufTest.cpp index e4de812804..e81fb9261c 100644 --- a/staticlibs/native/bpf_headers/BpfRingbufTest.cpp +++ b/staticlibs/native/bpf_headers/BpfRingbufTest.cpp @@ -74,11 +74,27 @@ class BpfRingbufTest : public ::testing::Test { ASSERT_RESULT_OK(result); EXPECT_TRUE(result.value()->isEmpty()); + struct timespec t1, t2; + EXPECT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &t1)); + EXPECT_FALSE(result.value()->wait(1000 /*ms*/)); // false because wait should timeout + EXPECT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &t2)); + long long time1 = t1.tv_sec * 1000000000LL + t1.tv_nsec; + long long time2 = t2.tv_sec * 1000000000LL + t2.tv_nsec; + EXPECT_GE(time2 - time1, 1000000000 /*ns*/); // 1000 ms as ns + for (int i = 0; i < n; i++) { RunProgram(); } EXPECT_FALSE(result.value()->isEmpty()); + + EXPECT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &t1)); + EXPECT_TRUE(result.value()->wait()); + EXPECT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &t2)); + time1 = t1.tv_sec * 1000000000LL + t1.tv_nsec; + time2 = t2.tv_sec * 1000000000LL + t2.tv_nsec; + EXPECT_LE(time2 - time1, 1000000 /*ns*/); // in x86 CF testing < 5000 ns + EXPECT_THAT(result.value()->ConsumeAll(callback), HasValue(n)); EXPECT_TRUE(result.value()->isEmpty()); EXPECT_EQ(output, TEST_RINGBUF_MAGIC_NUM); diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfRingbuf.h b/staticlibs/native/bpf_headers/include/bpf/BpfRingbuf.h index 9aff79081f..d7163588fc 100644 --- a/staticlibs/native/bpf_headers/include/bpf/BpfRingbuf.h +++ b/staticlibs/native/bpf_headers/include/bpf/BpfRingbuf.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -41,6 +42,9 @@ class BpfRingbufBase { bool isEmpty(void); + // returns !isEmpty() for convenience + bool wait(int timeout_ms = -1); + protected: // Non-initializing constructor, used by Create. BpfRingbufBase(size_t value_size) : mValueSize(value_size) {} @@ -200,12 +204,21 @@ inline base::Result BpfRingbufBase::Init(const char* path) { } inline bool BpfRingbufBase::isEmpty(void) { - uint32_t prod_pos = mProducerPos->load(std::memory_order_acquire); - // Only userspace writes to mConsumerPos, so no need to use std::memory_order_acquire + uint32_t prod_pos = mProducerPos->load(std::memory_order_relaxed); uint64_t cons_pos = mConsumerPos->load(std::memory_order_relaxed); return (cons_pos & 0xFFFFFFFF) == prod_pos; } +inline bool BpfRingbufBase::wait(int timeout_ms) { + // possible optimization: if (!isEmpty()) return true; + struct pollfd pfd = { // 1-element array + .fd = mRingFd.get(), + .events = POLLIN, + }; + (void)poll(&pfd, 1, timeout_ms); // 'best effort' poll + return !isEmpty(); +} + inline base::Result BpfRingbufBase::ConsumeAll( const std::function& callback) { int64_t count = 0;