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;