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 |