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