| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #ifndef MOJO_PUBLIC_CPP_SYSTEM_HANDLE_H_ | |
| 6 #define MOJO_PUBLIC_CPP_SYSTEM_HANDLE_H_ | |
| 7 | |
| 8 #include <assert.h> | |
| 9 #include <limits> | |
| 10 | |
| 11 #include "mojo/public/c/system/functions.h" | |
| 12 #include "mojo/public/c/system/types.h" | |
| 13 #include "mojo/public/cpp/system/macros.h" | |
| 14 | |
| 15 namespace mojo { | |
| 16 | |
| 17 // OVERVIEW | |
| 18 // | |
| 19 // |Handle| and |...Handle|: | |
| 20 // | |
| 21 // |Handle| is a simple, copyable wrapper for the C type |MojoHandle| (which is | |
| 22 // just an integer). Its purpose is to increase type-safety, not provide | |
| 23 // lifetime management. For the same purpose, we have trivial *subclasses* of | |
| 24 // |Handle|, e.g., |MessagePipeHandle| and |DataPipeProducerHandle|. |Handle| | |
| 25 // and its subclasses impose *no* extra overhead over using |MojoHandle|s | |
| 26 // directly. | |
| 27 // | |
| 28 // Note that though we provide constructors for |Handle|/|...Handle| from a | |
| 29 // |MojoHandle|, we do not provide, e.g., a constructor for |MessagePipeHandle| | |
| 30 // from a |Handle|. This is for type safety: If we did, you'd then be able to | |
| 31 // construct a |MessagePipeHandle| from, e.g., a |DataPipeProducerHandle| (since | |
| 32 // it's a |Handle|). | |
| 33 // | |
| 34 // |ScopedHandleBase| and |Scoped...Handle|: | |
| 35 // | |
| 36 // |ScopedHandleBase<HandleType>| is a templated scoped wrapper, for the handle | |
| 37 // types above (in the same sense that a C++11 |unique_ptr<T>| is a scoped | |
| 38 // wrapper for a |T*|). It provides lifetime management, closing its owned | |
| 39 // handle on destruction. It also provides (emulated) move semantics, again | |
| 40 // along the lines of C++11's |unique_ptr| (and exactly like Chromium's | |
| 41 // |scoped_ptr|). | |
| 42 // | |
| 43 // |ScopedHandle| is just (a typedef of) a |ScopedHandleBase<Handle>|. | |
| 44 // Similarly, |ScopedMessagePipeHandle| is just a | |
| 45 // |ScopedHandleBase<MessagePipeHandle>|. Etc. Note that a | |
| 46 // |ScopedMessagePipeHandle| is *not* a (subclass of) |ScopedHandle|. | |
| 47 // | |
| 48 // Wrapper functions: | |
| 49 // | |
| 50 // We provide simple wrappers for the |Mojo...()| functions (in | |
| 51 // mojo/public/c/system/core.h -- see that file for details on individual | |
| 52 // functions). | |
| 53 // | |
| 54 // The general guideline is functions that imply ownership transfer of a handle | |
| 55 // should take (or produce) an appropriate |Scoped...Handle|, while those that | |
| 56 // don't take a |...Handle|. For example, |CreateMessagePipe()| has two | |
| 57 // |ScopedMessagePipe| "out" parameters, whereas |Wait()| and |WaitMany()| take | |
| 58 // |Handle| parameters. Some, have both: e.g., |DuplicatedBuffer()| takes a | |
| 59 // suitable (unscoped) handle (e.g., |SharedBufferHandle|) "in" parameter and | |
| 60 // produces a suitable scoped handle (e.g., |ScopedSharedBufferHandle| a.k.a. | |
| 61 // |ScopedHandleBase<SharedBufferHandle>|) as an "out" parameter. | |
| 62 // | |
| 63 // An exception are some of the |...Raw()| functions. E.g., |CloseRaw()| takes a | |
| 64 // |Handle|, leaving the user to discard the handle. | |
| 65 // | |
| 66 // More significantly, |WriteMessageRaw()| exposes the full API complexity of | |
| 67 // |MojoWriteMessage()| (but doesn't require any extra overhead). It takes a raw | |
| 68 // array of |Handle|s as input, and takes ownership of them (i.e., invalidates | |
| 69 // them) on *success* (but not on failure). There are a number of reasons for | |
| 70 // this. First, C++03 |std::vector|s cannot contain the move-only | |
| 71 // |Scoped...Handle|s. Second, |std::vector|s impose extra overhead | |
| 72 // (necessitating heap-allocation of the buffer). Third, |std::vector|s wouldn't | |
| 73 // provide the desired level of flexibility/safety: a vector of handles would | |
| 74 // have to be all of the same type (probably |Handle|/|ScopedHandle|). Fourth, | |
| 75 // it's expected to not be used directly, but instead be used by generated | |
| 76 // bindings. | |
| 77 // | |
| 78 // Other |...Raw()| functions expose similar rough edges, e.g., dealing with raw | |
| 79 // pointers (and lengths) instead of taking |std::vector|s or similar. | |
| 80 | |
| 81 // ScopedHandleBase ------------------------------------------------------------ | |
| 82 | |
| 83 // Scoper for the actual handle types defined further below. It's move-only, | |
| 84 // like the C++11 |unique_ptr|. | |
| 85 template <class HandleType> | |
| 86 class ScopedHandleBase { | |
| 87 MOJO_MOVE_ONLY_TYPE(ScopedHandleBase) | |
| 88 | |
| 89 public: | |
| 90 ScopedHandleBase() {} | |
| 91 explicit ScopedHandleBase(HandleType handle) : handle_(handle) {} | |
| 92 ~ScopedHandleBase() { CloseIfNecessary(); } | |
| 93 | |
| 94 template <class CompatibleHandleType> | |
| 95 explicit ScopedHandleBase(ScopedHandleBase<CompatibleHandleType> other) | |
| 96 : handle_(other.release()) {} | |
| 97 | |
| 98 // Move-only constructor and operator=. | |
| 99 ScopedHandleBase(ScopedHandleBase&& other) : handle_(other.release()) {} | |
| 100 ScopedHandleBase& operator=(ScopedHandleBase&& other) { | |
| 101 if (&other != this) { | |
| 102 CloseIfNecessary(); | |
| 103 handle_ = other.release(); | |
| 104 } | |
| 105 return *this; | |
| 106 } | |
| 107 | |
| 108 const HandleType& get() const { return handle_; } | |
| 109 | |
| 110 template <typename PassedHandleType> | |
| 111 static ScopedHandleBase<HandleType> From( | |
| 112 ScopedHandleBase<PassedHandleType> other) { | |
| 113 static_assert( | |
| 114 sizeof(static_cast<PassedHandleType*>(static_cast<HandleType*>(0))), | |
| 115 "HandleType is not a subtype of PassedHandleType"); | |
| 116 return ScopedHandleBase<HandleType>( | |
| 117 static_cast<HandleType>(other.release().value())); | |
| 118 } | |
| 119 | |
| 120 void swap(ScopedHandleBase& other) { handle_.swap(other.handle_); } | |
| 121 | |
| 122 HandleType release() MOJO_WARN_UNUSED_RESULT { | |
| 123 HandleType rv; | |
| 124 rv.swap(handle_); | |
| 125 return rv; | |
| 126 } | |
| 127 | |
| 128 void reset(HandleType handle = HandleType()) { | |
| 129 CloseIfNecessary(); | |
| 130 handle_ = handle; | |
| 131 } | |
| 132 | |
| 133 bool is_valid() const { return handle_.is_valid(); } | |
| 134 | |
| 135 private: | |
| 136 void CloseIfNecessary() { | |
| 137 if (!handle_.is_valid()) | |
| 138 return; | |
| 139 MojoResult result = MojoClose(handle_.value()); | |
| 140 MOJO_ALLOW_UNUSED_LOCAL(result); | |
| 141 assert(result == MOJO_RESULT_OK); | |
| 142 } | |
| 143 | |
| 144 HandleType handle_; | |
| 145 }; | |
| 146 | |
| 147 template <typename HandleType> | |
| 148 inline ScopedHandleBase<HandleType> MakeScopedHandle(HandleType handle) { | |
| 149 return ScopedHandleBase<HandleType>(handle); | |
| 150 } | |
| 151 | |
| 152 // Handle ---------------------------------------------------------------------- | |
| 153 | |
| 154 const MojoHandle kInvalidHandleValue = MOJO_HANDLE_INVALID; | |
| 155 | |
| 156 // Wrapper base class for |MojoHandle|. | |
| 157 class Handle { | |
| 158 public: | |
| 159 Handle() : value_(kInvalidHandleValue) {} | |
| 160 explicit Handle(MojoHandle value) : value_(value) {} | |
| 161 ~Handle() {} | |
| 162 | |
| 163 void swap(Handle& other) { | |
| 164 MojoHandle temp = value_; | |
| 165 value_ = other.value_; | |
| 166 other.value_ = temp; | |
| 167 } | |
| 168 | |
| 169 bool is_valid() const { return value_ != kInvalidHandleValue; } | |
| 170 | |
| 171 const MojoHandle& value() const { return value_; } | |
| 172 MojoHandle* mutable_value() { return &value_; } | |
| 173 void set_value(MojoHandle value) { value_ = value; } | |
| 174 | |
| 175 private: | |
| 176 MojoHandle value_; | |
| 177 | |
| 178 // Copying and assignment allowed. | |
| 179 }; | |
| 180 | |
| 181 // Should have zero overhead. | |
| 182 static_assert(sizeof(Handle) == sizeof(MojoHandle), "Bad size for C++ Handle"); | |
| 183 | |
| 184 // The scoper should also impose no more overhead. | |
| 185 typedef ScopedHandleBase<Handle> ScopedHandle; | |
| 186 static_assert(sizeof(ScopedHandle) == sizeof(Handle), | |
| 187 "Bad size for C++ ScopedHandle"); | |
| 188 | |
| 189 inline MojoResult Wait(Handle handle, | |
| 190 MojoHandleSignals signals, | |
| 191 MojoDeadline deadline, | |
| 192 MojoHandleSignalsState* signals_state) { | |
| 193 return MojoWait(handle.value(), signals, deadline, signals_state); | |
| 194 } | |
| 195 | |
| 196 const uint32_t kInvalidWaitManyIndexValue = static_cast<uint32_t>(-1); | |
| 197 | |
| 198 // Simplify the interpretation of the output from |MojoWaitMany()|. | |
| 199 class WaitManyResult { | |
| 200 public: | |
| 201 explicit WaitManyResult(MojoResult mojo_wait_many_result) | |
| 202 : result(mojo_wait_many_result), index(kInvalidWaitManyIndexValue) {} | |
| 203 | |
| 204 WaitManyResult(MojoResult mojo_wait_many_result, uint32_t result_index) | |
| 205 : result(mojo_wait_many_result), index(result_index) {} | |
| 206 | |
| 207 // A valid handle index is always returned if |WaitMany()| succeeds, but may | |
| 208 // or may not be returned if |WaitMany()| returns an error. Use this helper | |
| 209 // function to check if |index| is a valid index into the handle array. | |
| 210 bool IsIndexValid() const { return index != kInvalidWaitManyIndexValue; } | |
| 211 | |
| 212 // The |signals_states| array is always returned by |WaitMany()| on success, | |
| 213 // but may or may not be returned if |WaitMany()| returns an error. Use this | |
| 214 // helper function to check if |signals_states| holds valid data. | |
| 215 bool AreSignalsStatesValid() const { | |
| 216 return result != MOJO_RESULT_INVALID_ARGUMENT && | |
| 217 result != MOJO_RESULT_RESOURCE_EXHAUSTED; | |
| 218 } | |
| 219 | |
| 220 MojoResult result; | |
| 221 uint32_t index; | |
| 222 }; | |
| 223 | |
| 224 // |HandleVectorType| and |FlagsVectorType| should be similar enough to | |
| 225 // |std::vector<Handle>| and |std::vector<MojoHandleSignals>|, respectively: | |
| 226 // - They should have a (const) |size()| method that returns an unsigned type. | |
| 227 // - They must provide contiguous storage, with access via (const) reference to | |
| 228 // that storage provided by a (const) |operator[]()| (by reference). | |
| 229 template <class HandleVectorType, | |
| 230 class FlagsVectorType, | |
| 231 class SignalsStateVectorType> | |
| 232 inline WaitManyResult WaitMany(const HandleVectorType& handles, | |
| 233 const FlagsVectorType& signals, | |
| 234 MojoDeadline deadline, | |
| 235 SignalsStateVectorType* signals_states) { | |
| 236 if (signals.size() != handles.size() || | |
| 237 (signals_states && signals_states->size() != signals.size())) | |
| 238 return WaitManyResult(MOJO_RESULT_INVALID_ARGUMENT); | |
| 239 if (handles.size() >= kInvalidWaitManyIndexValue) | |
| 240 return WaitManyResult(MOJO_RESULT_RESOURCE_EXHAUSTED); | |
| 241 | |
| 242 if (handles.size() == 0) { | |
| 243 return WaitManyResult( | |
| 244 MojoWaitMany(nullptr, nullptr, 0, deadline, nullptr, nullptr)); | |
| 245 } | |
| 246 | |
| 247 uint32_t result_index = kInvalidWaitManyIndexValue; | |
| 248 const Handle& first_handle = handles[0]; | |
| 249 const MojoHandleSignals& first_signals = signals[0]; | |
| 250 MojoHandleSignalsState* first_state = | |
| 251 signals_states ? &(*signals_states)[0] : nullptr; | |
| 252 MojoResult result = | |
| 253 MojoWaitMany(reinterpret_cast<const MojoHandle*>(&first_handle), | |
| 254 &first_signals, static_cast<uint32_t>(handles.size()), | |
| 255 deadline, &result_index, first_state); | |
| 256 return WaitManyResult(result, result_index); | |
| 257 } | |
| 258 | |
| 259 // C++ 4.10, regarding pointer conversion, says that an integral null pointer | |
| 260 // constant can be converted to |std::nullptr_t| (which is a typedef for | |
| 261 // |decltype(nullptr)|). The opposite direction is not allowed. | |
| 262 template <class HandleVectorType, class FlagsVectorType> | |
| 263 inline WaitManyResult WaitMany(const HandleVectorType& handles, | |
| 264 const FlagsVectorType& signals, | |
| 265 MojoDeadline deadline, | |
| 266 decltype(nullptr) signals_states) { | |
| 267 if (signals.size() != handles.size()) | |
| 268 return WaitManyResult(MOJO_RESULT_INVALID_ARGUMENT); | |
| 269 if (handles.size() >= kInvalidWaitManyIndexValue) | |
| 270 return WaitManyResult(MOJO_RESULT_RESOURCE_EXHAUSTED); | |
| 271 | |
| 272 if (handles.size() == 0) { | |
| 273 return WaitManyResult( | |
| 274 MojoWaitMany(nullptr, nullptr, 0, deadline, nullptr, nullptr)); | |
| 275 } | |
| 276 | |
| 277 uint32_t result_index = kInvalidWaitManyIndexValue; | |
| 278 const Handle& first_handle = handles[0]; | |
| 279 const MojoHandleSignals& first_signals = signals[0]; | |
| 280 MojoResult result = MojoWaitMany( | |
| 281 reinterpret_cast<const MojoHandle*>(&first_handle), &first_signals, | |
| 282 static_cast<uint32_t>(handles.size()), deadline, &result_index, nullptr); | |
| 283 return WaitManyResult(result, result_index); | |
| 284 } | |
| 285 | |
| 286 // |Close()| takes ownership of the handle, since it'll invalidate it. | |
| 287 // Note: There's nothing to do, since the argument will be destroyed when it | |
| 288 // goes out of scope. | |
| 289 template <class HandleType> | |
| 290 inline void Close(ScopedHandleBase<HandleType> /*handle*/) { | |
| 291 } | |
| 292 | |
| 293 // Most users should typically use |Close()| (above) instead. | |
| 294 inline MojoResult CloseRaw(Handle handle) { | |
| 295 return MojoClose(handle.value()); | |
| 296 } | |
| 297 | |
| 298 // Strict weak ordering, so that |Handle|s can be used as keys in |std::map|s, | |
| 299 inline bool operator<(const Handle a, const Handle b) { | |
| 300 return a.value() < b.value(); | |
| 301 } | |
| 302 | |
| 303 } // namespace mojo | |
| 304 | |
| 305 #endif // MOJO_PUBLIC_CPP_SYSTEM_HANDLE_H_ | |
| OLD | NEW |