Merge 'upstream/main' into 'main'
Change-Id: I447cdfb9a7257636b9df46f45125028621cbe3b6
Reviewed-on: https://fuchsia-review.googlesource.com/c/third_party/android.googlesource.com/platform/system/libfmq/+/1059082
Reviewed-by: Benjamin Lerman <qsr@google.com>
diff --git a/EventFlag.cpp b/EventFlag.cpp
index 8cf2760..eb8fe34 100644
--- a/EventFlag.cpp
+++ b/EventFlag.cpp
@@ -16,10 +16,8 @@
#define LOG_TAG "FMQ_EventFlags"
-#include <linux/futex.h>
#include <string.h>
#include <sys/mman.h>
-#include <sys/syscall.h>
#include <unistd.h>
#include <limits>
@@ -29,9 +27,37 @@
#include <utils/Log.h>
#include <utils/SystemClock.h>
+#if defined(__Fuchsia__)
+#include "vendor/google/starnix/android/remote_binder/lutex.h"
+#else
+#include <linux/futex.h>
+#include <sys/syscall.h>
+#endif
+
namespace android {
namespace hardware {
+namespace {
+long futex_wake(void* futex_address, uint32_t count, uint32_t bitmask) {
+#if defined(__Fuchsia__)
+ return starnix::lutex_wake(futex_address, count, bitmask);
+#else
+ return syscall(__NR_futex, futex_address, FUTEX_WAKE_BITSET, kIntMax, NULL,
+ NULL, bitmask);
+#endif
+}
+
+long futex_wait(void* futex_address, uint32_t value, uint32_t bitmask,
+ const struct timespec* timeout) {
+#if defined(__Fuchsia__)
+ return starnix::lutex_wait(futex_address, value, bitmask, timeout);
+#else
+ return syscall(__NR_futex, futex_address, FUTEX_WAIT_BITSET, value, timeout,
+ NULL, bitmask);
+#endif
+}
+}
+
status_t EventFlag::createEventFlag(std::atomic<uint32_t>* fwAddr,
EventFlag** flag) {
if (flag == nullptr) {
@@ -86,7 +112,7 @@
*/
constexpr size_t kIntMax = std::numeric_limits<int>::max();
if ((~old & bitmask) != 0) {
- int ret = syscall(__NR_futex, mEfWordPtr, FUTEX_WAKE_BITSET, kIntMax, NULL, NULL, bitmask);
+ int ret = futex_wake(mEfWordPtr, kIntMax, bitmask);
if (ret == -1) {
status = -errno;
ALOGE("Error in event flag wake attempt: %s\n", strerror(errno));
@@ -131,10 +157,9 @@
struct timespec waitTimeAbsolute;
addNanosecondsToCurrentTime(timeoutNanoSeconds, &waitTimeAbsolute);
- ret = syscall(__NR_futex, mEfWordPtr, FUTEX_WAIT_BITSET,
- efWord, &waitTimeAbsolute, NULL, bitmask);
+ ret = futex_wait(mEfWordPtr, efWord, bitmask, &waitTimeAbsolute);
} else {
- ret = syscall(__NR_futex, mEfWordPtr, FUTEX_WAIT_BITSET, efWord, NULL, NULL, bitmask);
+ ret = futex_wait(mEfWordPtr, efWord, bitmask, NULL);
}
if (ret == -1) {
status = -errno;
diff --git a/include/fmq/MessageQueueBase.h b/include/fmq/MessageQueueBase.h
index 41befee..72bdeb1 100644
--- a/include/fmq/MessageQueueBase.h
+++ b/include/fmq/MessageQueueBase.h
@@ -26,6 +26,10 @@
#include <atomic>
#include <new>
+#if defined(__Fuchsia__)
+#include "vendor/google/starnix/android/remote_binder/lutex.h"
+#endif
+
using android::hardware::kSynchronizedReadWrite;
using android::hardware::kUnsynchronizedWrite;
using android::hardware::MQFlavor;
@@ -1468,7 +1472,13 @@
hardware::details::logError(std::string("mmap failed: ") + std::to_string(errno));
return nullptr;
}
- return reinterpret_cast<uint8_t*>(address) + (grantors[grantorIdx].offset - mapOffset);
+ void* result = reinterpret_cast<uint8_t*>(address) + (grantors[grantorIdx].offset - mapOffset);
+#if defined(__Fuchsia__)
+ if (grantorIdx == hardware::details::EVFLAGWORDPOS) {
+ starnix::register_lutex(handle->data[fdIndex], grantors[grantorIdx].offset, result);
+ }
+#endif
+ return result;
}
template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
@@ -1483,7 +1493,14 @@
int mapLength = grantors[grantorIdx].offset - mapOffset + grantors[grantorIdx].extent;
void* baseAddress =
reinterpret_cast<uint8_t*>(address) - (grantors[grantorIdx].offset - mapOffset);
- if (baseAddress) munmap(baseAddress, mapLength);
+ if (baseAddress) {
+#if defined(__Fuchsia__)
+ if (grantorIdx == hardware::details::EVFLAGWORDPOS) {
+ starnix::unregister_lutex(address);
+ }
+#endif
+ munmap(baseAddress, mapLength);
+ }
}
} // namespace android
diff --git a/tests/fmq_unit_tests.cpp b/tests/fmq_unit_tests.cpp
index 7abe74d..e1c962e 100644
--- a/tests/fmq_unit_tests.cpp
+++ b/tests/fmq_unit_tests.cpp
@@ -20,7 +20,6 @@
#include <fmq/ConvertMQDescriptors.h>
#include <fmq/EventFlag.h>
#include <fmq/MessageQueue.h>
-#include <gtest/gtest-death-test.h>
#include <gtest/gtest.h>
#include <sys/resource.h>
#include <atomic>
@@ -29,6 +28,10 @@
#include <sstream>
#include <thread>
+#if defined(__Fuchsia__)
+#include "vendor/google/starnix/android/remote_binder/lutex.h"
+#endif
+
using aidl::android::hardware::common::fmq::SynchronizedReadWrite;
using aidl::android::hardware::common::fmq::UnsynchronizedWrite;
using android::hardware::kSynchronizedReadWrite;
@@ -157,6 +160,39 @@
TYPED_TEST_CASE(BlockingReadWrites, SyncTypes);
+class RegisteredFutex {
+ public:
+#if defined(__Fuchsia__)
+ RegisteredFutex() {
+ android::base::unique_fd fd(::ashmem_create_region(
+ "RegisteredFutex", PAGE_SIZE));
+ mapping = mmap(0, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd.get(), 0);
+ if (mapping != MAP_FAILED) {
+ starnix::register_lutex(fd.get(), 0, mapping);
+ }
+ }
+
+ ~RegisteredFutex() {
+ starnix::unregister_lutex(mapping);
+ munmap(mapping, PAGE_SIZE);
+ }
+#else
+ RegisteredFutex() {
+ mapping = &value;
+ }
+#endif
+
+ std::atomic<uint32_t>* GetAtomic() {
+ return static_cast<std::atomic<uint32_t>*>(mapping);
+ }
+
+ private:
+#if !defined(__Fuchsia__)
+ std::atomic<uint32_t> value;
+#endif
+ void* mapping = nullptr;
+};
+
template <typename T>
class BlockingReadWrites : public TestBase<T> {
protected:
@@ -179,14 +215,16 @@
ASSERT_TRUE(mQueue->isValid());
mNumMessagesMax = mQueue->getQuantumCount();
ASSERT_EQ(kNumElementsInQueue, mNumMessagesMax);
+ mFw = mRegisteredFutex.GetAtomic();
/*
* Initialize the EventFlag word to indicate Queue is not full.
*/
- std::atomic_init(&mFw, static_cast<uint32_t>(kFmqNotFull));
+ std::atomic_init(mFw, static_cast<uint32_t>(kFmqNotFull));
}
typename T::MQType* mQueue;
- std::atomic<uint32_t> mFw;
+ RegisteredFutex mRegisteredFutex;
+ std::atomic<uint32_t>* mFw;
size_t mNumMessagesMax = 0;
};
@@ -619,7 +657,7 @@
uint8_t data[dataLen] = {0};
android::hardware::EventFlag* efGroup = nullptr;
- android::status_t status = android::hardware::EventFlag::createEventFlag(&this->mFw, &efGroup);
+ android::status_t status = android::hardware::EventFlag::createEventFlag(this->mFw, &efGroup);
ASSERT_EQ(android::NO_ERROR, status);
ASSERT_NE(nullptr, efGroup);
@@ -628,7 +666,7 @@
* Start a thread that will try to read and block on kFmqNotEmpty.
*/
std::thread Reader(BlockingReadWrites<TypeParam>::ReaderThreadBlocking, this->mQueue,
- &this->mFw);
+ this->mFw);
struct timespec waitTime = {0, 100 * 1000000};
ASSERT_EQ(0, nanosleep(&waitTime, NULL));
@@ -656,7 +694,7 @@
uint8_t data[dataLen] = {0};
android::hardware::EventFlag* efGroup = nullptr;
- android::status_t status = android::hardware::EventFlag::createEventFlag(&this->mFw, &efGroup);
+ android::status_t status = android::hardware::EventFlag::createEventFlag(this->mFw, &efGroup);
ASSERT_EQ(android::NO_ERROR, status);
ASSERT_NE(nullptr, efGroup);
@@ -666,7 +704,7 @@
* call wake() on kFmqNotFull when the read is successful.
*/
std::thread Reader(BlockingReadWrites<TypeParam>::ReaderThreadBlocking2, this->mQueue,
- &this->mFw);
+ this->mFw);
bool ret = this->mQueue->writeBlocking(data, dataLen, static_cast<uint32_t>(kFmqNotFull),
static_cast<uint32_t>(kFmqNotEmpty),
5000000000 /* timeOutNanos */, efGroup);
@@ -682,7 +720,7 @@
*/
TYPED_TEST(BlockingReadWrites, BlockingTimeOutTest) {
android::hardware::EventFlag* efGroup = nullptr;
- android::status_t status = android::hardware::EventFlag::createEventFlag(&this->mFw, &efGroup);
+ android::status_t status = android::hardware::EventFlag::createEventFlag(this->mFw, &efGroup);
ASSERT_EQ(android::NO_ERROR, status);
ASSERT_NE(nullptr, efGroup);