BpfRingBuf.h - implement wait()
Test: TreeHugger, atest BpfRingbufTest
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: I2696077caf4de27dd64e4af1c45a13844ed186c9
diff --git a/staticlibs/native/bpf_headers/BpfRingbufTest.cpp b/staticlibs/native/bpf_headers/BpfRingbufTest.cpp
index e4de812..e81fb92 100644
--- a/staticlibs/native/bpf_headers/BpfRingbufTest.cpp
+++ b/staticlibs/native/bpf_headers/BpfRingbufTest.cpp
@@ -74,11 +74,27 @@
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 9aff790..d716358 100644
--- a/staticlibs/native/bpf_headers/include/bpf/BpfRingbuf.h
+++ b/staticlibs/native/bpf_headers/include/bpf/BpfRingbuf.h
@@ -19,6 +19,7 @@
#include <android-base/result.h>
#include <android-base/unique_fd.h>
#include <linux/bpf.h>
+#include <poll.h>
#include <sys/mman.h>
#include <utils/Log.h>
@@ -41,6 +42,9 @@
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 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<int> BpfRingbufBase::ConsumeAll(
const std::function<void(const void*)>& callback) {
int64_t count = 0;