• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ScopedHandleBase()77   ScopedHandleBase() {}
ScopedHandleBase(HandleType handle)78   explicit ScopedHandleBase(HandleType handle) : handle_(handle) {}
~ScopedHandleBase()79   ~ScopedHandleBase() { CloseIfNecessary(); }
80 
81   template <class CompatibleHandleType>
ScopedHandleBase(ScopedHandleBase<CompatibleHandleType> other)82   explicit ScopedHandleBase(ScopedHandleBase<CompatibleHandleType> other)
83       : handle_(other.release()) {}
84 
85   // Move-only constructor and operator=.
ScopedHandleBase(ScopedHandleBase && other)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 
get()95   const HandleType& get() const { return handle_; }
96   const HandleType* operator->() const { return &handle_; }
97 
98   template <typename PassedHandleType>
From(ScopedHandleBase<PassedHandleType> other)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 
swap(ScopedHandleBase & other)108   void swap(ScopedHandleBase& other) { handle_.swap(other.handle_); }
109 
release()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 
is_valid()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:
CloseIfNecessary()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>
MakeScopedHandle(HandleType handle)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:
Handle()150   Handle() : value_(kInvalidHandleValue) {}
Handle(MojoHandle value)151   explicit Handle(MojoHandle value) : value_(value) {}
~Handle()152   ~Handle() {}
153 
swap(Handle & other)154   void swap(Handle& other) {
155     MojoHandle temp = value_;
156     value_ = other.value_;
157     other.value_ = temp;
158   }
159 
is_valid()160   bool is_valid() const { return value_ != kInvalidHandleValue; }
161 
value()162   const MojoHandle& value() const { return value_; }
mutable_value()163   MojoHandle* mutable_value() { return &value_; }
set_value(MojoHandle value)164   void set_value(MojoHandle value) { value_ = value; }
165 
Close()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 
Wait(Handle handle,MojoHandleSignals signals,MojoDeadline deadline,MojoHandleSignalsState * signals_state)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:
WaitManyResult(MojoResult mojo_wait_many_result)199   explicit WaitManyResult(MojoResult mojo_wait_many_result)
200       : result(mojo_wait_many_result), index(kInvalidWaitManyIndexValue) {}
201 
WaitManyResult(MojoResult mojo_wait_many_result,uint32_t result_index)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.
IsIndexValid()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.
AreSignalsStatesValid()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>
WaitMany(const HandleVectorType & handles,const FlagsVectorType & signals,MojoDeadline deadline,SignalsStateVectorType * signals_states)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>
WaitMany(const HandleVectorType & handles,const FlagsVectorType & signals,MojoDeadline deadline,decltype (nullptr)signals_states)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>
Close(ScopedHandleBase<HandleType>)288 inline void Close(ScopedHandleBase<HandleType> /*handle*/) {
289 }
290 
291 // Most users should typically use |Close()| (above) instead.
CloseRaw(Handle handle)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