Home | History | Annotate | Download | only in system
      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 
     17 namespace 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|.
     72 template <class HandleType>
     73 class 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 
    138 template <typename HandleType>
    139 inline ScopedHandleBase<HandleType> MakeScopedHandle(HandleType handle) {
    140   return ScopedHandleBase<HandleType>(handle);
    141 }
    142 
    143 // Handle ----------------------------------------------------------------------
    144 
    145 const MojoHandle kInvalidHandleValue = MOJO_HANDLE_INVALID;
    146 
    147 // Wrapper base class for |MojoHandle|.
    148 class 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.
    180 static_assert(sizeof(Handle) == sizeof(MojoHandle), "Bad size for C++ Handle");
    181 
    182 // The scoper should also impose no more overhead.
    183 typedef ScopedHandleBase<Handle> ScopedHandle;
    184 static_assert(sizeof(ScopedHandle) == sizeof(Handle),
    185               "Bad size for C++ ScopedHandle");
    186 
    187 inline 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 
    194 const uint32_t kInvalidWaitManyIndexValue = static_cast<uint32_t>(-1);
    195 
    196 // Simplify the interpretation of the output from |MojoWaitMany()|.
    197 class 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).
    227 template <class HandleVectorType,
    228           class FlagsVectorType,
    229           class SignalsStateVectorType>
    230 inline 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.
    260 template <class HandleVectorType, class FlagsVectorType>
    261 inline 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.
    287 template <class HandleType>
    288 inline void Close(ScopedHandleBase<HandleType> /*handle*/) {
    289 }
    290 
    291 // Most users should typically use |Close()| (above) instead.
    292 inline 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,
    297 inline 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.
    302 inline 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