blob: 283835089deab45b32f0d33b2ca4aaacd9b1586f [file] [log] [blame]
Greg Hartman40b88f52017-06-22 15:34:11 -07001#pragma once
2
3/*
4 * Copyright (C) 2017 The Android Open Source Project
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19// Object that represents a region on the Host
20
Greg Hartman40b88f52017-06-22 15:34:11 -070021#include <stdlib.h>
22#include <sys/mman.h>
Greg Hartmanaca3bc72017-07-17 16:03:45 -070023#include <atomic>
24#include <cstdint>
Greg Hartman40b88f52017-06-22 15:34:11 -070025
Jorge E. Moreira351f7832017-10-14 13:14:07 -070026#include <functional>
Jorge E. Moreira4b9bbb12017-12-28 15:49:06 -080027#include <map>
Greg Hartmanffe99fa2017-07-14 14:46:19 -070028#include <thread>
29
Greg Hartman40b88f52017-06-22 15:34:11 -070030#include "common/libs/fs/shared_fd.h"
Greg Hartman4dd9c422017-07-19 18:14:59 -070031#include "common/libs/glog/logging.h"
Greg Hartmanfd32a452017-11-05 08:11:13 -080032#include "common/vsoc/lib/lock_guard.h"
Greg Hartmane08d8b22017-08-08 16:44:29 -070033#include "common/vsoc/lib/region_control.h"
Greg Hartmanfd32a452017-11-05 08:11:13 -080034#include "common/vsoc/lib/region_signaling_interface.h"
Greg Hartmanffe99fa2017-07-14 14:46:19 -070035#include "common/vsoc/shm/base.h"
Greg Hartman40b88f52017-06-22 15:34:11 -070036#include "uapi/vsoc_shm.h"
37
38namespace vsoc {
39
Jorge E. Moreirac615b452017-08-07 17:22:44 -070040class RegionView;
Greg Hartmanffe99fa2017-07-14 14:46:19 -070041
Greg Hartmane08d8b22017-08-08 16:44:29 -070042/**
43 * Represents a task that is tied to a RegionView.
44 *
45 * This is currently used for the task that forwards futexes across the
46 * shared memory window.
47 */
Greg Hartmanffe99fa2017-07-14 14:46:19 -070048class RegionWorker {
49 public:
Jorge E. Moreirac615b452017-08-07 17:22:44 -070050 explicit RegionWorker(RegionView* region);
Greg Hartmanffe99fa2017-07-14 14:46:19 -070051 ~RegionWorker();
52 void Work();
53
54 protected:
Jorge E. Moreirac615b452017-08-07 17:22:44 -070055 RegionView* region_;
Greg Hartmanffe99fa2017-07-14 14:46:19 -070056 std::thread thread_;
57 volatile bool stopping_{};
58};
59
Greg Hartman40b88f52017-06-22 15:34:11 -070060/**
Greg Hartmane08d8b22017-08-08 16:44:29 -070061 * Base class to access a mapped region in VSoC shared memory.
62 * This class holds the methods that depends on the region's memory having an
63 * address. The RegionControl class holds the methods that can be invoked
64 * without mapping the region.
Greg Hartman40b88f52017-06-22 15:34:11 -070065 */
Ping-Hao Wu9eed50a2017-10-17 16:57:27 -070066class RegionView : public RegionSignalingInterface {
Greg Hartman40b88f52017-06-22 15:34:11 -070067 public:
Jorge E. Moreirac615b452017-08-07 17:22:44 -070068 virtual ~RegionView();
Greg Hartman40b88f52017-06-22 15:34:11 -070069
Greg Hartman6da43022017-12-05 11:16:02 -080070#if defined(CUTTLEFISH_HOST)
71 bool Open(const char* region_name, const char* domain);
72#else
73 bool Open(const char* region_name);
74#endif
Greg Hartman40b88f52017-06-22 15:34:11 -070075
Greg Hartmanffe99fa2017-07-14 14:46:19 -070076 // Returns a pointer to the table that will be scanned for signals
Greg Hartmane08d8b22017-08-08 16:44:29 -070077 const vsoc_signal_table_layout& incoming_signal_table();
Greg Hartmanffe99fa2017-07-14 14:46:19 -070078
79 // Returns a pointer to the table that will be used to post signals
Greg Hartmane08d8b22017-08-08 16:44:29 -070080 const vsoc_signal_table_layout& outgoing_signal_table();
Greg Hartmanffe99fa2017-07-14 14:46:19 -070081
Greg Hartmane08d8b22017-08-08 16:44:29 -070082 // Returns true iff an interrupt is queued in the signal table
83 bool HasIncomingInterrupt() {
Greg Hartman3ea6c0a2017-08-01 19:03:19 -070084 return *region_offset_to_pointer<std::atomic<uint32_t>>(
Greg Hartmane08d8b22017-08-08 16:44:29 -070085 incoming_signal_table().interrupt_signalled_offset);
Greg Hartman3ea6c0a2017-08-01 19:03:19 -070086 }
87
Greg Hartmane08d8b22017-08-08 16:44:29 -070088 // Wake any threads waiting for an interrupt. This is generally used during
89 // shutdown.
90 void InterruptSelf() { control_->InterruptSelf(); }
Greg Hartmanffe99fa2017-07-14 14:46:19 -070091
Greg Hartmane08d8b22017-08-08 16:44:29 -070092 // Interrupt our peer if an interrupt is not already on the way.
93 // Returns true if the interrupt was sent, false if an interrupt was already
94 // pending.
95 bool MaybeInterruptPeer();
Greg Hartmanffe99fa2017-07-14 14:46:19 -070096
97 // Scan in the incoming signal table, issuing futex calls for any posted
98 // signals and then reposting them to the peer if they were round-trip
99 // signals.
100 //
Jorge E. Moreira351f7832017-10-14 13:14:07 -0700101 // signal_handler: An action to perform on every offset signalled by our
102 // peer, usually a FUTEX_WAKE call, but can be customized for other
103 // purposes.
Greg Hartman02490212017-12-13 19:49:10 -0800104 void ProcessSignalsFromPeer(
105 std::function<void(std::atomic<uint32_t>*)> signal_handler);
Greg Hartmanffe99fa2017-07-14 14:46:19 -0700106
107 // Post a signal to the guest, the host, or both.
108 // See futex(2) FUTEX_WAKE for details.
109 //
110 // sides_to_signal: controls where the signal is sent
111 //
112 // signal_addr: the memory location to signal. Must be within the region.
Greg Hartman02490212017-12-13 19:49:10 -0800113 void SendSignal(layout::Sides sides_to_signal,
114 std::atomic<uint32_t>* signal_addr);
Greg Hartmanffe99fa2017-07-14 14:46:19 -0700115
116 // Post a signal to our peer for a specific memeory location.
117 // See futex(2) FUTEX_WAKE for details.
118 //
119 // signal_addr: the memory location to signal. Must be within the region.
120 //
121 // round_trip: true if there may be waiters on both sides of the shared
122 // memory.
Greg Hartman02490212017-12-13 19:49:10 -0800123 void SendSignalToPeer(std::atomic<uint32_t>* signal_addr, bool round_trip);
Greg Hartmanffe99fa2017-07-14 14:46:19 -0700124
Greg Hartmane08d8b22017-08-08 16:44:29 -0700125 // Waits until an interrupt appears on this region, then clears the
126 // interrupted flag and returns.
127 void WaitForInterrupt();
128
Greg Hartmanffe99fa2017-07-14 14:46:19 -0700129 // This implements the following:
130 // if (*signal_addr == last_observed_value)
131 // wait_for_signal_at(signal_addr);
132 //
133 // Note: the caller still needs to check the value at signal_addr because
134 // this function may return early for reasons that are implementation-defined.
135 // See futex(2) FUTEX_WAIT for details.
136 //
137 // signal_addr: the memory that will be signaled. Must be within the region.
138 //
139 // last_observed_value: the value that motivated the calling code to wait.
Greg Hartman02490212017-12-13 19:49:10 -0800140 void WaitForSignal(std::atomic<uint32_t>* signal_addr,
141 uint32_t last_observed_value);
Greg Hartmanffe99fa2017-07-14 14:46:19 -0700142
143 // Starts the signal table scanner. This must be invoked by subclasses, which
144 // must store the returned unique_ptr as a class member.
145 std::unique_ptr<RegionWorker> StartWorker();
146
Greg Hartman86b114a2017-11-03 21:04:14 -0700147 // Returns a pointer to the start of region data that is cast to the given
Greg Hartman64545962017-12-13 19:37:03 -0800148 // type. Initializers that run in the launcher use this to get a typed view
149 // of the region. Most other cases should be handled via TypedRegionView.
Greg Hartman86b114a2017-11-03 21:04:14 -0700150 template <typename LayoutType>
151 LayoutType* GetLayoutPointer() {
152 return this->region_offset_to_pointer<LayoutType>(
153 control_->region_desc().offset_of_region_data);
154 }
155
Greg Hartmanfd32a452017-11-05 08:11:13 -0800156 // Helper functions for lock guards. This approach has two advantages:
157 //
158 // o Callers don't have to be refactored when lock types change
159 // o The region pointer can be provided automatically
160 template <typename T>
161 LockGuard<T> make_lock_guard(T* lock) {
162 return LockGuard<T>(lock);
163 }
164
165 LockGuard<::vsoc::layout::GuestAndHostLock> make_lock_guard(
166 ::vsoc::layout::GuestAndHostLock* l) {
167 return LockGuard<::vsoc::layout::GuestAndHostLock>(l, this);
168 }
169
Greg Hartman40b88f52017-06-22 15:34:11 -0700170 protected:
Greg Hartmanaca3bc72017-07-17 16:03:45 -0700171 template <typename T>
Jorge E. Moreira3781d342017-07-26 15:06:26 -0700172 T* region_offset_to_pointer(vsoc_reg_off_t offset) {
Greg Hartmane08d8b22017-08-08 16:44:29 -0700173 if (offset > control_->region_size()) {
Greg Hartman4dd9c422017-07-19 18:14:59 -0700174 LOG(FATAL) << __FUNCTION__ << ": " << offset << " not in region @"
175 << region_base_;
176 }
Greg Hartmanaca3bc72017-07-17 16:03:45 -0700177 return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(region_base_) +
Greg Hartman4dd9c422017-07-19 18:14:59 -0700178 offset);
Greg Hartman40b88f52017-06-22 15:34:11 -0700179 }
180
Greg Hartmanaca3bc72017-07-17 16:03:45 -0700181 template <typename T>
Greg Hartmane08d8b22017-08-08 16:44:29 -0700182 const T& region_offset_to_reference(vsoc_reg_off_t offset) const {
183 if (offset > control_->region_size()) {
184 LOG(FATAL) << __FUNCTION__ << ": " << offset << " not in region @"
185 << region_base_;
186 }
187 return *reinterpret_cast<const T*>(
188 reinterpret_cast<uintptr_t>(region_base_) + offset);
189 }
190
191 // Calculates an offset based on a pointer in the region. Crashes if the
192 // pointer isn't in the region.
193 // This is mostly for the RegionView's internal plumbing. Use TypedRegionView
194 // and RegionLayout to avoid this in most cases.
195 template <typename T>
Jorge E. Moreira3781d342017-07-26 15:06:26 -0700196 vsoc_reg_off_t pointer_to_region_offset(T* ptr) {
197 vsoc_reg_off_t rval = reinterpret_cast<uintptr_t>(ptr) -
Greg Hartmane08d8b22017-08-08 16:44:29 -0700198 reinterpret_cast<uintptr_t>(region_base_);
199 if (rval > control_->region_size()) {
Greg Hartman4dd9c422017-07-19 18:14:59 -0700200 LOG(FATAL) << __FUNCTION__ << ": " << ptr << " not in region @"
201 << region_base_;
202 }
203 return rval;
Greg Hartman40b88f52017-06-22 15:34:11 -0700204 }
205
Greg Hartmane08d8b22017-08-08 16:44:29 -0700206 std::shared_ptr<RegionControl> control_;
Greg Hartmanaca3bc72017-07-17 16:03:45 -0700207 void* region_base_{};
Greg Hartman40b88f52017-06-22 15:34:11 -0700208};
209
Greg Hartmanaca3bc72017-07-17 16:03:45 -0700210} // namespace vsoc