Merge "One queue state per direction." into gce-dev
diff --git a/common/vsoc/lib/circqueue_impl.h b/common/vsoc/lib/circqueue_impl.h
index f228cbb..8b0fa90 100644
--- a/common/vsoc/lib/circqueue_impl.h
+++ b/common/vsoc/lib/circqueue_impl.h
@@ -124,9 +124,7 @@
this->CopyOutRange(t, buffer_out);
this->r_released_ = t.end_idx;
this->lock_.Unlock();
- layout::Sides side;
- side.value_ = layout::Sides::Both;
- r->SendSignal(side, &this->r_released_);
+ r->SendSignal(layout::Sides::Both, &this->r_released_);
return t.end_idx - t.start_idx;
}
@@ -146,9 +144,7 @@
// published.
this->w_pub_ = range.end_idx;
this->lock_.Unlock();
- layout::Sides side;
- side.value_ = layout::Sides::Both;
- r->SendSignal(side, &this->w_pub_);
+ r->SendSignal(layout::Sides::Both, &this->w_pub_);
return bytes;
}
@@ -175,9 +171,7 @@
this->CopyOutRange(t, buffer_out);
this->r_released_ += this->CalculateBufferedSize(packet_size);
this->lock_.Unlock();
- layout::Sides side;
- side.value_ = layout::Sides::Both;
- r->SendSignal(side, &this->r_released_);
+ r->SendSignal(layout::Sides::Both, &this->r_released_);
return packet_size;
}
@@ -232,9 +226,7 @@
this->w_pub_ = range.end_idx;
this->lock_.Unlock();
- layout::Sides side;
- side.value_ = layout::Sides::Both;
- r->SendSignal(side, &this->w_pub_);
+ r->SendSignal(layout::Sides::Both, &this->w_pub_);
return bytes;
}
diff --git a/common/vsoc/lib/e2e_test_region_view.h b/common/vsoc/lib/e2e_test_region_view.h
index 1ea6aef..70a3db6 100644
--- a/common/vsoc/lib/e2e_test_region_view.h
+++ b/common/vsoc/lib/e2e_test_region_view.h
@@ -27,6 +27,38 @@
E2ERegionView<Layout>,
Layout> {
public:
+
+ uint32_t read_guest_self_register() const {
+ return this->data().guest_self_register;
+ }
+
+ void write_guest_self_register(uint32_t val) {
+ this->data()->guest_self_register = val;
+ }
+
+ void signal_guest_self_register() {
+ this->SendSignal(layout::Sides::OurSide,
+ &this->data()->guest_self_register);
+ }
+
+ int wait_guest_self_register(uint32_t expected_value) {
+ return this->WaitForSignal(
+ &this->data()->guest_self_register, expected_value);
+ }
+
+ void signal_guest_to_host_register() {
+ this->SendSignal(layout::Sides::OurSide,
+ &this->data()->guest_to_host_signal);
+ }
+
+ uint32_t guest_to_host_signal_offset() const {
+ return this->pointer_to_region_offset(&this->data().guest_to_host_signal);
+ }
+
+ uint32_t host_to_guest_signal_offset() const {
+ return this->pointer_to_region_offset(&this->data().host_to_guest_signal);
+ }
+
const char* guest_string(size_t index) const {
return const_cast<const char*>(this->data().data[index].guest_writable);
}
diff --git a/common/vsoc/lib/lock_common.cpp b/common/vsoc/lib/lock_common.cpp
index 7825011..c100574 100644
--- a/common/vsoc/lib/lock_common.cpp
+++ b/common/vsoc/lib/lock_common.cpp
@@ -121,9 +121,16 @@
LOG(FATAL) << "Lock owner of " << this << " changed from " << tid << " to "
<< expected_state << " during unlock";
}
- Sides rval;
- rval.value_ = expected_state & (GuestWaitingFlag | HostWaitingFlag) >> 30;
- return rval;
+ switch (expected_state & (GuestWaitingFlag | HostWaitingFlag)) {
+ case 0:
+ return Sides::NoSides;
+ case GuestWaitingFlag:
+ return Sides::Guest;
+ case HostWaitingFlag:
+ return Sides::Host;
+ default:
+ return Sides::Both;
+ }
}
bool vsoc::layout::WaitingLockBase::RecoverSingleSided() {
diff --git a/common/vsoc/lib/mock_region_view.h b/common/vsoc/lib/mock_region_view.h
index b6bcc45..f9c3006 100644
--- a/common/vsoc/lib/mock_region_view.h
+++ b/common/vsoc/lib/mock_region_view.h
@@ -59,13 +59,13 @@
nullptr, nullptr, 0);
}
- virtual void WaitForSignal(std::atomic<uint32_t>* uaddr,
+ virtual int WaitForSignal(std::atomic<uint32_t>* uaddr,
uint32_t expected_value) {
{
std::lock_guard<std::mutex> guard(mutex_);
if (tid_to_addr_.find(std::this_thread::get_id()) != tid_to_addr_.end()) {
// Same thread tries to wait
- return;
+ return 0;
}
tid_to_addr_.emplace(std::this_thread::get_id(), uaddr);
map_changed_.notify_one();
@@ -77,6 +77,7 @@
std::lock_guard<std::mutex> guard(mutex_);
tid_to_addr_.erase(std::this_thread::get_id());
}
+ return 0;
}
// Mock methods from TypedRegionView
diff --git a/common/vsoc/lib/region_control.h b/common/vsoc/lib/region_control.h
index fd9377e..7762603 100644
--- a/common/vsoc/lib/region_control.h
+++ b/common/vsoc/lib/region_control.h
@@ -65,10 +65,10 @@
// failure. FdScopedPermission is not supported on the host, so -1 is
// always returned there.
virtual int CreateFdScopedPermission(const char* managed_region_name,
- vsoc_reg_off_t owner_offset,
+ uint32_t owner_offset,
uint32_t owned_value,
- vsoc_reg_off_t begin_offset,
- vsoc_reg_off_t end_offset) = 0;
+ uint32_t begin_offset,
+ uint32_t end_offset) = 0;
// Interrupt our peer, causing it to scan the outgoing_signal_table
virtual bool InterruptPeer() = 0;
@@ -82,6 +82,27 @@
// Wait for an interrupt from our peer
virtual void WaitForInterrupt() = 0;
+ // Signals local waiters at the given region offset.
+ // Defined only on the guest.
+ // Return value is negative on error.
+ virtual int SignalSelf(uint32_t offset) = 0;
+
+ // Waits for a signal at the given region offset.
+ // Defined only on the guest.
+ // Return value is negative on error. The number of false wakes is returned
+ // on success.
+ virtual int WaitForSignal(uint32_t offset, uint32_t expected_value) = 0;
+
+ template <typename T>
+ T* region_offset_to_pointer(uint32_t offset) {
+ if (offset > region_size()) {
+ LOG(FATAL) << __FUNCTION__ << ": " << offset << " not in region @"
+ << region_base_;
+ }
+ return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(region_base_) +
+ offset);
+ }
+
protected:
RegionControl() {}
void* region_base_{};
diff --git a/common/vsoc/lib/region_signaling_interface.h b/common/vsoc/lib/region_signaling_interface.h
index a853b7a..c1399e1 100644
--- a/common/vsoc/lib/region_signaling_interface.h
+++ b/common/vsoc/lib/region_signaling_interface.h
@@ -50,7 +50,14 @@
// signal_addr: the memory that will be signaled. Must be within the region.
//
// last_observed_value: the value that motivated the calling code to wait.
- virtual void WaitForSignal(std::atomic<uint32_t>* signal_addr,
+ //
+ // The return values are:
+ // -1 on failure
+ // 0 indicates success with no tuning information
+ // >0 indicates success. The number indicates how many times the thread
+ // woke before it could return.
+ // Large values indicate that the regions should be tuned.
+ virtual int WaitForSignal(std::atomic<uint32_t>* signal_addr,
uint32_t last_observed_value) = 0;
};
diff --git a/common/vsoc/lib/region_view.cpp b/common/vsoc/lib/region_view.cpp
index 4f222f1..b86defd 100644
--- a/common/vsoc/lib/region_view.cpp
+++ b/common/vsoc/lib/region_view.cpp
@@ -1,8 +1,6 @@
#include "common/vsoc/lib/region_view.h"
-#include <linux/futex.h>
#include <sys/mman.h>
-#include <sys/syscall.h>
#include "common/libs/glog/logging.h"
@@ -13,8 +11,11 @@
using vsoc::layout::Sides;
-vsoc::RegionWorker::RegionWorker(RegionView* region)
- : region_(region), thread_(&vsoc::RegionWorker::Work, this) {}
+vsoc::RegionWorker::RegionWorker(RegionView* region,
+ std::shared_ptr<RegionControl> control)
+ : control_(control),
+ region_(region),
+ thread_(&vsoc::RegionWorker::Work, this) {}
void vsoc::RegionWorker::Work() {
while (!stopping_) {
@@ -22,9 +23,9 @@
if (stopping_) {
return;
}
- region_->ProcessSignalsFromPeer([](std::atomic<uint32_t>* uaddr) {
- syscall(SYS_futex, uaddr, FUTEX_WAKE, -1, nullptr, nullptr, 0);
- });
+ region_->ProcessSignalsFromPeer([this](uint32_t offset) {
+ control_->SignalSelf(offset);
+ });
}
}
@@ -83,22 +84,21 @@
}
void vsoc::RegionView::ProcessSignalsFromPeer(
- std::function<void(std::atomic<uint32_t>*)> signal_handler) {
+ std::function<void(uint32_t)> signal_handler) {
const vsoc_signal_table_layout& table = incoming_signal_table();
const size_t num_offsets = (1 << table.num_nodes_lg2);
std::atomic<uint32_t>* offsets =
region_offset_to_pointer<std::atomic<uint32_t>>(
table.futex_uaddr_table_offset);
for (size_t i = 0; i < num_offsets; ++i) {
- uint32_t offset = offsets[i].exchange(0);
- if (offset) {
- bool round_trip = offset & UADDR_OFFSET_ROUND_TRIP_FLAG;
- std::atomic<uint32_t>* uaddr =
- region_offset_to_pointer<std::atomic<uint32_t>>(offset &
- UADDR_OFFSET_MASK);
- signal_handler(uaddr);
+ uint32_t raw_offset = offsets[i].exchange(0);
+ if (raw_offset) {
+ bool round_trip = raw_offset & UADDR_OFFSET_ROUND_TRIP_FLAG;
+ uint32_t offset = raw_offset & UADDR_OFFSET_MASK;
+ signal_handler(offset);
if (round_trip) {
- SendSignalToPeer(uaddr, false);
+ SendSignalToPeer(
+ region_offset_to_pointer<std::atomic<uint32_t>>(offset), false);
}
}
}
@@ -106,18 +106,17 @@
void vsoc::RegionView::SendSignal(Sides sides_to_signal,
std::atomic<uint32_t>* uaddr) {
- if (sides_to_signal.value_ & Sides::Peer) {
+ if (sides_to_signal & Sides::Peer) {
// If we should also be signalling our side set the round trip flag on
// the futex signal.
- bool round_trip = sides_to_signal.value_ & Sides::OurSide;
+ bool round_trip = sides_to_signal & Sides::OurSide;
SendSignalToPeer(uaddr, round_trip);
// Return without signaling our waiters to give the other side a chance
// to run.
return;
}
- if (sides_to_signal.value_ & Sides::OurSide) {
- syscall(SYS_futex, reinterpret_cast<int32_t*>(uaddr), FUTEX_WAKE, -1,
- nullptr, nullptr, 0);
+ if (sides_to_signal & Sides::OurSide) {
+ control_->SignalSelf(pointer_to_region_offset(uaddr));
}
}
@@ -180,10 +179,12 @@
}
std::unique_ptr<vsoc::RegionWorker> vsoc::RegionView::StartWorker() {
- return std::unique_ptr<vsoc::RegionWorker>(new vsoc::RegionWorker(this));
+ return std::unique_ptr<vsoc::RegionWorker>(new vsoc::RegionWorker(
+ this, control_));
}
-void vsoc::RegionView::WaitForSignal(std::atomic<uint32_t>* uaddr,
+int vsoc::RegionView::WaitForSignal(std::atomic<uint32_t>* uaddr,
uint32_t expected_value) {
- syscall(SYS_futex, uaddr, FUTEX_WAIT, expected_value, nullptr, nullptr, 0);
+ return control_->WaitForSignal(pointer_to_region_offset(uaddr),
+ expected_value);
}
diff --git a/common/vsoc/lib/region_view.h b/common/vsoc/lib/region_view.h
index 2838350..2f07f71 100644
--- a/common/vsoc/lib/region_view.h
+++ b/common/vsoc/lib/region_view.h
@@ -37,6 +37,7 @@
namespace vsoc {
+class RegionControl;
class RegionView;
/**
@@ -47,11 +48,12 @@
*/
class RegionWorker {
public:
- explicit RegionWorker(RegionView* region);
+ RegionWorker(RegionView* region, std::shared_ptr<RegionControl> control);
~RegionWorker();
void Work();
protected:
+ std::shared_ptr<RegionControl> control_;
RegionView* region_;
std::thread thread_;
volatile bool stopping_{};
@@ -102,7 +104,7 @@
// peer, usually a FUTEX_WAKE call, but can be customized for other
// purposes.
void ProcessSignalsFromPeer(
- std::function<void(std::atomic<uint32_t>*)> signal_handler);
+ std::function<void(uint32_t)> signal_handler);
// Post a signal to the guest, the host, or both.
// See futex(2) FUTEX_WAKE for details.
@@ -137,8 +139,11 @@
// signal_addr: the memory that will be signaled. Must be within the region.
//
// last_observed_value: the value that motivated the calling code to wait.
- void WaitForSignal(std::atomic<uint32_t>* signal_addr,
- uint32_t last_observed_value);
+ //
+ // The return value is -1 on error. On the guest positive values give the
+ // number of false wakes.
+ int WaitForSignal(std::atomic<uint32_t>* signal_addr,
+ uint32_t last_observed_value) override;
// Starts the signal table scanner. This must be invoked by subclasses, which
// must store the returned unique_ptr as a class member.
@@ -169,17 +174,12 @@
protected:
template <typename T>
- T* region_offset_to_pointer(vsoc_reg_off_t offset) {
- if (offset > control_->region_size()) {
- LOG(FATAL) << __FUNCTION__ << ": " << offset << " not in region @"
- << region_base_;
- }
- return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(region_base_) +
- offset);
+ T* region_offset_to_pointer(uint32_t offset) {
+ return control_->region_offset_to_pointer<T>(offset);
}
template <typename T>
- const T& region_offset_to_reference(vsoc_reg_off_t offset) const {
+ const T& region_offset_to_reference(uint32_t offset) const {
if (offset > control_->region_size()) {
LOG(FATAL) << __FUNCTION__ << ": " << offset << " not in region @"
<< region_base_;
@@ -193,8 +193,8 @@
// This is mostly for the RegionView's internal plumbing. Use TypedRegionView
// and RegionLayout to avoid this in most cases.
template <typename T>
- vsoc_reg_off_t pointer_to_region_offset(T* ptr) {
- vsoc_reg_off_t rval = reinterpret_cast<uintptr_t>(ptr) -
+ uint32_t pointer_to_region_offset(T* ptr) const {
+ uint32_t rval = reinterpret_cast<uintptr_t>(ptr) -
reinterpret_cast<uintptr_t>(region_base_);
if (rval > control_->region_size()) {
LOG(FATAL) << __FUNCTION__ << ": " << ptr << " not in region @"
diff --git a/common/vsoc/lib/screen_region_view.cpp b/common/vsoc/lib/screen_region_view.cpp
index a028dff..2a22335 100644
--- a/common/vsoc/lib/screen_region_view.cpp
+++ b/common/vsoc/lib/screen_region_view.cpp
@@ -66,9 +66,7 @@
// Signaling while holding the lock may cause the just-awaken listener to
// block immediately trying to acquire the lock.
// The former is less costly and slightly less likely to happen.
- layout::Sides side;
- side.value_ = layout::Sides::Both;
- SendSignal(side, &data()->seq_num);
+ SendSignal(layout::Sides::Both, &data()->seq_num);
}
int ScreenRegionView::WaitForNewFrameSince(uint32_t* last_seq_num,
diff --git a/common/vsoc/shm/base.h b/common/vsoc/shm/base.h
index abac492..2525696 100644
--- a/common/vsoc/shm/base.h
+++ b/common/vsoc/shm/base.h
@@ -58,20 +58,18 @@
*
* These are carefully formatted to make Guest and Host a bitfield.
*/
-struct Sides {
- static const uint32_t NoSides = 0;
- static const uint32_t Guest = 1;
- static const uint32_t Host = 2;
- static const uint32_t Both = 3;
+enum Sides : uint32_t {
+ NoSides = 0,
+ Guest = 1,
+ Host = 2,
+ Both = 3,
#ifdef CUTTLEFISH_HOST
- static const uint32_t OurSide = Host;
- static const uint32_t Peer = Guest;
+ OurSide = Host,
+ Peer = Guest
#else
- static const uint32_t OurSide = Guest;
- static const uint32_t Peer = Host;
+ OurSide = Guest,
+ Peer = Host
#endif
-
- uint32_t value_;
};
ASSERT_SHM_COMPATIBLE(Sides, multi_region);
diff --git a/common/vsoc/shm/e2e_test_region_layout.h b/common/vsoc/shm/e2e_test_region_layout.h
index 7227726..3c5950e 100644
--- a/common/vsoc/shm/e2e_test_region_layout.h
+++ b/common/vsoc/shm/e2e_test_region_layout.h
@@ -120,6 +120,7 @@
// These fields are used to test the signaling mechanism.
std::atomic<uint32_t> host_to_guest_signal;
std::atomic<uint32_t> guest_to_host_signal;
+ std::atomic<uint32_t> guest_self_register;
// There rest of the region will be filled by guest_host_strings.
// We actually use more than one of these, but we can't know how many
// until we examine the region.
diff --git a/common/vsoc/shm/version.h b/common/vsoc/shm/version.h
index 12fefd8..e1c715b 100644
--- a/common/vsoc/shm/version.h
+++ b/common/vsoc/shm/version.h
@@ -160,15 +160,15 @@
// Changes to these structures will affect only the e2e_test_region
namespace e2e_test {
namespace {
-const uint32_t version = 1;
+const uint32_t version = 2;
}
static const std::size_t E2EManagerTestRegionLayout_size = 16;
static const std::size_t E2EMemoryFill_size = 64;
-static const std::size_t E2EPrimaryTestRegionLayout_size = 80;
-static const std::size_t E2ESecondaryTestRegionLayout_size = 80;
-static const std::size_t E2ETestRegionLayout_size = 80;
+static const std::size_t E2EPrimaryTestRegionLayout_size = 84;
+static const std::size_t E2ESecondaryTestRegionLayout_size = 84;
+static const std::size_t E2ETestRegionLayout_size = 84;
static const std::size_t E2ETestStageRegister_size = 4;
-static const std::size_t E2EUnfindableRegionLayout_size = 80;
+static const std::size_t E2EUnfindableRegionLayout_size = 84;
static const std::size_t E2EManagedTestRegionLayout_size = 4;
} // namespace e2e_test
diff --git a/guest/vsoc/lib/Android.mk b/guest/vsoc/lib/Android.mk
index 2072415..ad27f69 100644
--- a/guest/vsoc/lib/Android.mk
+++ b/guest/vsoc/lib/Android.mk
@@ -15,6 +15,30 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
+LOCAL_MODULE := vsoc_driver_test
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := vsoc_driver_test.cpp
+
+LOCAL_C_INCLUDES := \
+ device/google/cuttlefish_common \
+ device/google/cuttlefish_kernel
+
+LOCAL_CFLAGS += -DGTEST_OS_LINUX_ANDROID -DGTEST_HAS_STD_STRING -Werror -Wall
+
+LOCAL_STATIC_LIBRARIES := \
+ libgtest
+
+LOCAL_SHARED_LIBRARIES := \
+ vsoc_lib \
+ cuttlefish_auto_resources \
+ libcuttlefish_fs \
+ libbase
+
+LOCAL_MULTILIB := first
+LOCAL_VENDOR_MODULE := true
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
LOCAL_MODULE := vsoc_guest_region_e2e_test
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := guest_region_e2e_test.cpp
diff --git a/guest/vsoc/lib/gralloc_region_view.cpp b/guest/vsoc/lib/gralloc_region_view.cpp
index 9ae2c31..2c42f57 100644
--- a/guest/vsoc/lib/gralloc_region_view.cpp
+++ b/guest/vsoc/lib/gralloc_region_view.cpp
@@ -51,7 +51,7 @@
LOG_FATAL("Unable to open managed region");
return false;
}
- offset_of_buffer_memory_ = gralloc_align<vsoc_reg_off_t>(
+ offset_of_buffer_memory_ = gralloc_align<uint32_t>(
managed_region->region_desc().offset_of_region_data);
total_buffer_memory_ =
managed_region->region_size() - offset_of_buffer_memory_;
diff --git a/guest/vsoc/lib/gralloc_region_view.h b/guest/vsoc/lib/gralloc_region_view.h
index a32cff7..ef5553f 100644
--- a/guest/vsoc/lib/gralloc_region_view.h
+++ b/guest/vsoc/lib/gralloc_region_view.h
@@ -44,7 +44,7 @@
bool Open();
- vsoc_reg_off_t offset_of_buffer_memory_{};
+ uint32_t offset_of_buffer_memory_{};
uint32_t total_buffer_memory_{};
};
diff --git a/guest/vsoc/lib/guest_lock.cpp b/guest/vsoc/lib/guest_lock.cpp
index 98940cb..247b48b 100644
--- a/guest/vsoc/lib/guest_lock.cpp
+++ b/guest/vsoc/lib/guest_lock.cpp
@@ -36,7 +36,7 @@
void GuestLock::Unlock() {
Sides sides_to_signal = UnlockCommon(gettid());
- if (sides_to_signal.value_ != Sides::NoSides) {
+ if (sides_to_signal != Sides::NoSides) {
SingleSidedSignal::Signal(&lock_uint32_);
}
}
diff --git a/guest/vsoc/lib/guest_region_e2e_test.cpp b/guest/vsoc/lib/guest_region_e2e_test.cpp
index 344a743..8e3181e 100644
--- a/guest/vsoc/lib/guest_region_e2e_test.cpp
+++ b/guest/vsoc/lib/guest_region_e2e_test.cpp
@@ -112,27 +112,27 @@
// Test signals
EXPECT_FALSE(secondary->HasIncomingInterrupt());
LOG(INFO) << "Verified no early second signal";
- vsoc::layout::Sides side;
- side.value_ = vsoc::layout::Sides::Peer;
- primary->SendSignal(side, &primary->data()->guest_to_host_signal);
+ primary->SendSignal(vsoc::layout::Sides::Peer,
+ &primary->data()->guest_to_host_signal);
LOG(INFO) << "Signal sent. Waiting for first signal from peer";
primary->WaitForInterrupt();
int count = 0; // counts the number of signals received.
primary->ProcessSignalsFromPeer(
- [&primary, &count](std::atomic<uint32_t>* uaddr) {
+ [&primary, &count](uint32_t offset) {
++count;
- EXPECT_TRUE(uaddr == &primary->data()->host_to_guest_signal);
+ EXPECT_TRUE(offset == primary->host_to_guest_signal_offset());
});
EXPECT_TRUE(count == 1);
LOG(INFO) << "Signal received on primary region";
- secondary->SendSignal(side, &secondary->data()->guest_to_host_signal);
+ secondary->SendSignal(vsoc::layout::Sides::Peer,
+ &secondary->data()->guest_to_host_signal);
LOG(INFO) << "Signal sent. Waiting for second signal from peer";
secondary->WaitForInterrupt();
count = 0;
secondary->ProcessSignalsFromPeer(
- [&secondary, &count](std::atomic<uint32_t>* uaddr) {
+ [&secondary, &count](uint32_t offset) {
++count;
- EXPECT_TRUE(uaddr == &secondary->data()->host_to_guest_signal);
+ EXPECT_TRUE(offset == secondary->host_to_guest_signal_offset());
});
EXPECT_TRUE(count == 1);
LOG(INFO) << "Signal received on secondary region";
diff --git a/guest/vsoc/lib/manager_region_view.h b/guest/vsoc/lib/manager_region_view.h
index dc77c06..c2a873d 100644
--- a/guest/vsoc/lib/manager_region_view.h
+++ b/guest/vsoc/lib/manager_region_view.h
@@ -46,8 +46,8 @@
* one returns -EBUSY, returns a different negative number otherwise.
*/
int CreateFdScopedPermission(uint32_t* owner_ptr, uint32_t owned_val,
- vsoc_reg_off_t begin_offset,
- vsoc_reg_off_t end_offset) {
+ uint32_t begin_offset,
+ uint32_t end_offset) {
return this->control_->CreateFdScopedPermission(
Layout::ManagedRegion::region_name,
this->pointer_to_region_offset(owner_ptr), owned_val, begin_offset,
diff --git a/guest/vsoc/lib/region_control.cpp b/guest/vsoc/lib/region_control.cpp
index 8c6864c..1fcbd13 100644
--- a/guest/vsoc/lib/region_control.cpp
+++ b/guest/vsoc/lib/region_control.cpp
@@ -43,12 +43,14 @@
virtual void InterruptSelf() override;
virtual void WaitForInterrupt() override;
virtual void* Map() override;
+ virtual int SignalSelf(uint32_t offset) override;
+ virtual int WaitForSignal(uint32_t offset, uint32_t expected_value) override;
protected:
int CreateFdScopedPermission(const char* managed_region_name,
- vsoc_reg_off_t owner_offset, uint32_t owned_val,
- vsoc_reg_off_t begin_offset,
- vsoc_reg_off_t end_offset) override;
+ uint32_t owner_offset, uint32_t owned_val,
+ uint32_t begin_offset,
+ uint32_t end_offset) override;
cvd::SharedFD region_fd_;
};
@@ -72,10 +74,36 @@
region_fd_->Ioctl(VSOC_WAIT_FOR_INCOMING_INTERRUPT, 0);
}
+int GuestRegionControl::SignalSelf(uint32_t offset) {
+ return region_fd_->Ioctl(VSOC_COND_WAKE, reinterpret_cast<void*>(offset));
+}
+
+int GuestRegionControl::WaitForSignal(uint32_t offset,
+ uint32_t expected_value) {
+ struct vsoc_cond_wait wait;
+ wait.offset = offset;
+ wait.value = expected_value;
+ wait.wake_time_sec = 0;
+ wait.wake_time_nsec = 0;
+ wait.wait_type = VSOC_WAIT_IF_EQUAL;
+ wait.wakes = 1000;
+ wait.reserved_1 = 0;
+ int rval = region_fd_->Ioctl(VSOC_COND_WAIT, &wait);
+ if (rval == -1) {
+ return rval;
+ }
+ // Clamp the number of wakes if it overflows an integer.
+ rval = wait.wakes;
+ if (rval >= 0) {
+ return rval;
+ }
+ return INT_MAX;
+}
+
int GuestRegionControl::CreateFdScopedPermission(
- const char* managed_region_name, vsoc_reg_off_t owner_offset,
- uint32_t owned_value, vsoc_reg_off_t begin_offset,
- vsoc_reg_off_t end_offset) {
+ const char* managed_region_name, uint32_t owner_offset,
+ uint32_t owned_value, uint32_t begin_offset,
+ uint32_t end_offset) {
if (!region_fd_->IsOpen()) {
LOG(FATAL) << "Can't create permission before opening controller region";
return -EINVAL;
diff --git a/guest/vsoc/lib/vsoc_driver_test.cpp b/guest/vsoc/lib/vsoc_driver_test.cpp
new file mode 100644
index 0000000..ff20ecb
--- /dev/null
+++ b/guest/vsoc/lib/vsoc_driver_test.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 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.
+ */
+
+/*
+ * Stand-alone tests for the ioctls in the vsoc driver.
+ */
+
+#include "uapi/vsoc_shm.h"
+#include <atomic>
+#include <stdint.h>
+#include "common/vsoc/lib/e2e_test_region_view.h"
+#include "guest/vsoc/lib/manager_region_view.h"
+
+#include <android-base/logging.h>
+#include <gtest/gtest.h>
+
+void BasicWaitForSignal(vsoc::E2EPrimaryRegionView* region,
+ uint32_t expected_start,
+ uint32_t expected_finish) {
+ ASSERT_EQ(expected_start, region->read_guest_self_register());
+ int rval = region->wait_guest_self_register(expected_start);
+ EXPECT_LE(0, rval);
+ EXPECT_GT(5, rval);
+ EXPECT_EQ(expected_finish, region->read_guest_self_register());
+}
+
+TEST(FutexTest, BasicFutexTests) {
+ constexpr uint32_t INITIAL_SIGNAL = 0;
+ constexpr uint32_t SILENT_UPDATE_SIGNAL = 1;
+ constexpr uint32_t WAKE_SIGNAL = 2;
+ auto region = vsoc::E2EPrimaryRegionView::GetInstance();
+ ASSERT_TRUE(region != NULL);
+ LOG(INFO) << "Regions are open";
+ region->write_guest_self_register(INITIAL_SIGNAL);
+ std::thread waiter(BasicWaitForSignal, region, INITIAL_SIGNAL, WAKE_SIGNAL);
+ sleep(1);
+ LOG(INFO) << "Still waiting. Trying to wake wrong address";
+ region->signal_guest_to_host_register();
+ sleep(1);
+ LOG(INFO) << "Still waiting. Trying to wake without update";
+ region->signal_guest_self_register();
+ sleep(1);
+ LOG(INFO) << "Still waiting. Trying to wake without signal";
+ region->write_guest_self_register(SILENT_UPDATE_SIGNAL);
+ sleep(1);
+ LOG(INFO) << "Still waiting. Trying to wake with signal";
+ region->write_guest_self_register(WAKE_SIGNAL);
+ region->signal_guest_self_register();
+ waiter.join();
+ LOG(INFO) << "Wake worked";
+ LOG(INFO) << "PASS: BasicPeerTests";
+}
+
+int main(int argc, char* argv[]) {
+ android::base::InitLogging(argv);
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/host/libs/ivserver/hald_client.cc b/host/libs/ivserver/hald_client.cc
index 6f2f6b8..4b71be4 100644
--- a/host/libs/ivserver/hald_client.cc
+++ b/host/libs/ivserver/hald_client.cc
@@ -67,7 +67,7 @@
}
if (region_name_len <= 0 ||
- region_name_len > VSoCSharedMemory::kMaxRegionNameLength) {
+ region_name_len > VSOC_DEVICE_NAME_SZ) {
LOG(ERROR) << "Invalid region length received: " << region_name_len;
return false;
}
diff --git a/host/libs/ivserver/hald_client_test.cc b/host/libs/ivserver/hald_client_test.cc
index a8c5bbb..6ddf91b 100644
--- a/host/libs/ivserver/hald_client_test.cc
+++ b/host/libs/ivserver/hald_client_test.cc
@@ -100,7 +100,7 @@
}
TEST_F(HaldClientTest, HandshakeTerminatedByInvalidRegionSize) {
- uint16_t sizes[] = {0, VSoCSharedMemory::kMaxRegionNameLength + 1, 0xffff};
+ uint16_t sizes[] = {0, VSOC_DEVICE_NAME_SZ + 1, 0xffff};
for (uint16_t size : sizes) {
std::thread thread([this, size]() {
diff --git a/host/libs/ivserver/vsocsharedmem.h b/host/libs/ivserver/vsocsharedmem.h
index 1edab05..f732f6b 100644
--- a/host/libs/ivserver/vsocsharedmem.h
+++ b/host/libs/ivserver/vsocsharedmem.h
@@ -35,9 +35,6 @@
cvd::SharedFD guest_fd;
};
- // Max name length of a memory region.
- static constexpr int32_t kMaxRegionNameLength = sizeof(vsoc_device_name);
-
VSoCSharedMemory() = default;
virtual ~VSoCSharedMemory() = default;
diff --git a/host/vsoc/lib/gralloc_buffer_region_view.cpp b/host/vsoc/lib/gralloc_buffer_region_view.cpp
index ffb130e..db302cb 100644
--- a/host/vsoc/lib/gralloc_buffer_region_view.cpp
+++ b/host/vsoc/lib/gralloc_buffer_region_view.cpp
@@ -22,7 +22,7 @@
using vsoc::gralloc::GrallocBufferRegionView;
-uint8_t* GrallocBufferRegionView::OffsetToBufferPtr(vsoc_reg_off_t offset) {
+uint8_t* GrallocBufferRegionView::OffsetToBufferPtr(uint32_t offset) {
if (offset <= control_->region_desc().offset_of_region_data ||
offset >= control_->region_size()) {
LOG(FATAL)
diff --git a/host/vsoc/lib/gralloc_buffer_region_view.h b/host/vsoc/lib/gralloc_buffer_region_view.h
index f76b243..b132a0e 100644
--- a/host/vsoc/lib/gralloc_buffer_region_view.h
+++ b/host/vsoc/lib/gralloc_buffer_region_view.h
@@ -40,7 +40,7 @@
GrallocBufferRegionView(const GrallocBufferRegionView&) = delete;
GrallocBufferRegionView& operator=(const GrallocBufferRegionView&) = delete;
- uint8_t* OffsetToBufferPtr(vsoc_reg_off_t offset);
+ uint8_t* OffsetToBufferPtr(uint32_t offset);
};
} // namespace gralloc
diff --git a/host/vsoc/lib/host_lock.cpp b/host/vsoc/lib/host_lock.cpp
index 2d610f1..895a429 100644
--- a/host/vsoc/lib/host_lock.cpp
+++ b/host/vsoc/lib/host_lock.cpp
@@ -38,7 +38,7 @@
void HostLock::Unlock() {
Sides sides_to_signal = UnlockCommon(gettid());
- if (sides_to_signal.value_ != Sides::NoSides) {
+ if (sides_to_signal != Sides::NoSides) {
SingleSidedSignal::Signal(&lock_uint32_);
}
}
diff --git a/host/vsoc/lib/host_region_e2e_test.cpp b/host/vsoc/lib/host_region_e2e_test.cpp
index 13f453b..cab1bc7 100644
--- a/host/vsoc/lib/host_region_e2e_test.cpp
+++ b/host/vsoc/lib/host_region_e2e_test.cpp
@@ -83,29 +83,29 @@
// Test signals
EXPECT_FALSE(secondary->HasIncomingInterrupt());
LOG(INFO) << "Verified no early second signal";
- vsoc::layout::Sides side;
- side.value_ = vsoc::layout::Sides::Peer;
- primary->SendSignal(side, &primary->data()->host_to_guest_signal);
+ primary->SendSignal(vsoc::layout::Sides::Peer,
+ &primary->data()->host_to_guest_signal);
LOG(INFO) << "Signal sent. Waiting for first signal from peer";
primary->WaitForInterrupt();
int count = 0; // counts the number of signals received.
primary->ProcessSignalsFromPeer(
- [&primary, &count](std::atomic<uint32_t>* uaddr) {
+ [&primary, &count](uint32_t offset) {
++count;
- EXPECT_TRUE(uaddr == &primary->data()->guest_to_host_signal);
+ EXPECT_EQ(primary->guest_to_host_signal_offset(), offset);
});
- EXPECT_TRUE(count == 1);
+ EXPECT_EQ(1, count);
LOG(INFO) << "Signal received on primary region";
- secondary->SendSignal(side, &secondary->data()->host_to_guest_signal);
+ secondary->SendSignal(vsoc::layout::Sides::Peer,
+ &secondary->data()->host_to_guest_signal);
LOG(INFO) << "Signal sent. Waiting for second signal from peer";
secondary->WaitForInterrupt();
count = 0;
secondary->ProcessSignalsFromPeer(
- [secondary, &count](std::atomic<uint32_t>* uaddr) {
+ [secondary, &count](uint32_t offset) {
++count;
- EXPECT_TRUE(uaddr == &secondary->data()->guest_to_host_signal);
+ EXPECT_EQ(secondary->guest_to_host_signal_offset(), offset);
});
- EXPECT_TRUE(count == 1);
+ EXPECT_EQ(1, count);
LOG(INFO) << "Signal received on secondary region";
EXPECT_FALSE(primary->HasIncomingInterrupt());
diff --git a/host/vsoc/lib/region_control.cpp b/host/vsoc/lib/region_control.cpp
index f4f07b5..491f600 100644
--- a/host/vsoc/lib/region_control.cpp
+++ b/host/vsoc/lib/region_control.cpp
@@ -19,6 +19,7 @@
#include <stdio.h>
#include <string.h>
+#include <linux/futex.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/syscall.h>
@@ -51,10 +52,10 @@
shared_memory_fd_{shared_memory_fd} {}
int CreateFdScopedPermission(const char* /*managed_region_name*/,
- vsoc_reg_off_t /*owner_offset*/,
+ uint32_t /*owner_offset*/,
uint32_t /*owned_val*/,
- vsoc_reg_off_t /*begin_offset*/,
- vsoc_reg_off_t /*end_offset*/) override {
+ uint32_t /*begin_offset*/,
+ uint32_t /*end_offset*/) override {
return -1;
}
@@ -119,6 +120,17 @@
return region_base_;
}
+
+ virtual int SignalSelf(uint32_t offset) override {
+ return syscall(SYS_futex, region_offset_to_pointer<int32_t*>(offset),
+ FUTEX_WAKE, -1, nullptr, nullptr, 0);
+ }
+
+ virtual int WaitForSignal(uint32_t offset, uint32_t expected_value) override {
+ return syscall(SYS_futex, region_offset_to_pointer<int32_t*>(offset),
+ FUTEX_WAIT, expected_value, nullptr, nullptr, 0);
+ }
+
protected:
const char* region_name_{};
cvd::SharedFD incoming_interrupt_fd_;
@@ -132,9 +144,9 @@
bool HostRegionControl::InitializeRegion() {
size_t region_name_len = strlen(region_name_);
- if (region_name_len >= sizeof(vsoc_device_name)) {
+ if (region_name_len >= VSOC_DEVICE_NAME_SZ) {
LOG(FATAL) << "Region name length (" << region_name_len << ") not < "
- << sizeof(vsoc_device_name);
+ << VSOC_DEVICE_NAME_SZ;
return false;
}
vsoc_shm_layout_descriptor layout;