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