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 <mojo/result.h> | |
10 #include <mojo/system/handle.h> | |
11 #include <stdint.h> | |
12 | |
13 #include <limits> | |
14 | |
15 #include "mojo/public/cpp/system/macros.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 (declared in various | |
53 // mojo/public/c/include/mojo/system/*.h -- see those file for details on | |
54 // individual 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 ScopedHandleBase() {} | |
76 explicit ScopedHandleBase(HandleType handle) : handle_(handle) {} | |
77 ~ScopedHandleBase() { CloseIfNecessary(); } | |
78 | |
79 template <class CompatibleHandleType> | |
80 explicit ScopedHandleBase(ScopedHandleBase<CompatibleHandleType> other) | |
81 : handle_(other.release()) {} | |
82 | |
83 // Move-only constructor and operator=. | |
84 ScopedHandleBase(ScopedHandleBase&& other) : handle_(other.release()) {} | |
85 ScopedHandleBase& operator=(ScopedHandleBase&& other) { | |
86 if (&other != this) { | |
87 CloseIfNecessary(); | |
88 handle_ = other.release(); | |
89 } | |
90 return *this; | |
91 } | |
92 | |
93 const HandleType& get() const { return handle_; } | |
94 | |
95 template <typename PassedHandleType> | |
96 static ScopedHandleBase<HandleType> From( | |
97 ScopedHandleBase<PassedHandleType> other) { | |
98 static_assert( | |
99 sizeof(static_cast<PassedHandleType*>(static_cast<HandleType*>(0))), | |
100 "HandleType is not a subtype of PassedHandleType"); | |
101 return ScopedHandleBase<HandleType>( | |
102 static_cast<HandleType>(other.release().value())); | |
103 } | |
104 | |
105 void swap(ScopedHandleBase& other) { handle_.swap(other.handle_); } | |
106 | |
107 HandleType release() MOJO_WARN_UNUSED_RESULT { | |
108 HandleType rv; | |
109 rv.swap(handle_); | |
110 return rv; | |
111 } | |
112 | |
113 void reset(HandleType handle = HandleType()) { | |
114 CloseIfNecessary(); | |
115 handle_ = handle; | |
116 } | |
117 | |
118 bool is_valid() const { return handle_.is_valid(); } | |
119 | |
120 private: | |
121 void CloseIfNecessary() { | |
122 if (!handle_.is_valid()) | |
123 return; | |
124 MojoResult result = MojoClose(handle_.value()); | |
125 MOJO_ALLOW_UNUSED_LOCAL(result); | |
126 assert(result == MOJO_RESULT_OK); | |
127 } | |
128 | |
129 HandleType handle_; | |
130 | |
131 MOJO_MOVE_ONLY_TYPE(ScopedHandleBase); | |
132 }; | |
133 | |
134 template <typename HandleType> | |
135 inline ScopedHandleBase<HandleType> MakeScopedHandle(HandleType handle) { | |
136 return ScopedHandleBase<HandleType>(handle); | |
137 } | |
138 | |
139 // Handle ---------------------------------------------------------------------- | |
140 | |
141 const MojoHandle kInvalidHandleValue = MOJO_HANDLE_INVALID; | |
142 | |
143 // Wrapper base class for |MojoHandle|. | |
144 class Handle { | |
145 public: | |
146 Handle() : value_(kInvalidHandleValue) {} | |
147 explicit Handle(MojoHandle value) : value_(value) {} | |
148 ~Handle() {} | |
149 | |
150 void swap(Handle& other) { | |
151 MojoHandle temp = value_; | |
152 value_ = other.value_; | |
153 other.value_ = temp; | |
154 } | |
155 | |
156 bool is_valid() const { return value_ != kInvalidHandleValue; } | |
157 | |
158 const MojoHandle& value() const { return value_; } | |
159 MojoHandle* mutable_value() { return &value_; } | |
160 void set_value(MojoHandle value) { value_ = value; } | |
161 | |
162 private: | |
163 MojoHandle value_; | |
164 | |
165 // Copying and assignment allowed. | |
166 }; | |
167 | |
168 // Should have zero overhead. | |
169 static_assert(sizeof(Handle) == sizeof(MojoHandle), "Bad size for C++ Handle"); | |
170 | |
171 // The scoper should also impose no more overhead. | |
172 typedef ScopedHandleBase<Handle> ScopedHandle; | |
173 static_assert(sizeof(ScopedHandle) == sizeof(Handle), | |
174 "Bad size for C++ ScopedHandle"); | |
175 | |
176 // |Close()| takes ownership of the handle, since it'll invalidate it. | |
177 // Note: There's nothing to do, since the argument will be destroyed when it | |
178 // goes out of scope. | |
179 template <class HandleType> | |
180 inline void Close(ScopedHandleBase<HandleType> /*handle*/) {} | |
181 | |
182 // Most users should typically use |Close()| (above) instead. | |
183 inline MojoResult CloseRaw(Handle handle) { | |
184 return MojoClose(handle.value()); | |
185 } | |
186 | |
187 // Strict weak ordering, so that |Handle|s can be used as keys in |std::map|s, | |
188 inline bool operator<(const Handle a, const Handle b) { | |
189 return a.value() < b.value(); | |
190 } | |
191 | |
192 // Rights and duplication/replacement ------------------------------------------ | |
193 | |
194 // |handle| must be valid. | |
195 inline MojoHandleRights GetRights(Handle handle) { | |
196 assert(handle.is_valid()); | |
197 MojoHandleRights rights = MOJO_HANDLE_RIGHT_NONE; | |
198 MojoResult result = MojoGetRights(handle.value(), &rights); | |
199 MOJO_ALLOW_UNUSED_LOCAL(result); | |
200 assert(result == MOJO_RESULT_OK); | |
201 return rights; | |
202 } | |
203 | |
204 // |HandleType| should be some subclass of |Handle|; this is templated so that | |
205 // it will work with multiple handle types. |*handle| must be valid. Returns | |
206 // true on success or false on failure (in which case |*handle| is reset). | |
207 template <class HandleType> | |
208 inline bool ReplaceHandleWithReducedRights(ScopedHandleBase<HandleType>* handle, | |
209 MojoHandleRights rights_to_remove) { | |
210 assert(handle); | |
211 assert(handle->is_valid()); | |
212 HandleType raw_handle = handle->release(); | |
213 HandleType new_raw_handle; | |
214 if (MojoReplaceHandleWithReducedRights(raw_handle.value(), rights_to_remove, | |
215 new_raw_handle.mutable_value()) != | |
216 MOJO_RESULT_OK) { | |
217 assert(false); // This really shouldn't happen. | |
218 CloseRaw(raw_handle); | |
219 return false; | |
220 } | |
221 // Otherwise, |raw_handle| is invalidated. | |
222 handle->reset(new_raw_handle); | |
223 return true; | |
224 } | |
225 | |
226 template <class HandleType> | |
227 inline ScopedHandleBase<HandleType> DuplicateHandleWithReducedRights( | |
228 HandleType handle, | |
229 MojoHandleRights rights_to_remove) { | |
230 assert(handle.is_valid()); | |
231 HandleType new_handle; | |
232 MojoResult result = MojoDuplicateHandleWithReducedRights( | |
233 handle.value(), rights_to_remove, new_handle.mutable_value()); | |
234 MOJO_ALLOW_UNUSED_LOCAL(result); | |
235 assert(result == MOJO_RESULT_OK); | |
236 return MakeScopedHandle(new_handle); | |
237 } | |
238 | |
239 template <class HandleType> | |
240 inline ScopedHandleBase<HandleType> DuplicateHandle(HandleType handle) { | |
241 HandleType new_handle; | |
242 MojoResult result = | |
243 MojoDuplicateHandle(handle.value(), new_handle.mutable_value()); | |
244 MOJO_ALLOW_UNUSED_LOCAL(result); | |
245 assert(result == MOJO_RESULT_OK); | |
246 return MakeScopedHandle(new_handle); | |
247 } | |
248 | |
249 } // namespace mojo | |
250 | |
251 #endif // MOJO_PUBLIC_CPP_SYSTEM_HANDLE_H_ | |
OLD | NEW |