Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(335)

Side by Side Diff: mojo/public/cpp/system/README.md

Issue 2783223004: Adds lots of Mojo documentation (Closed)
Patch Set: Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 # ![Mojo Graphic](https://goo.gl/6CdlbH) Mojo C++ System API
2 This document is a subset of the [Mojo documentation](/mojo).
3
4 [TOC]
5
6 ## Overview
7 The Mojo C++ System API provides a convenient set of helper classes and
8 functions for working with Mojo primitives. Unlike the low-level
9 [C API](/mojo/public/c/system) (upon which this is built) this library takes
10 advantage of C++ language features and common STL and `//base` types to provide
11 a slightly more idiomatic interface to the Mojo system layer, making it
12 generally easier to use.
13
14 This document provides a brief guide to API usage with example code snippets.
15 For a detailed API references please consult the headers in
16 [//mojo/public/cpp/system](https://cs.chromium.org/chromium/src/mojo/public/cpp/ system/).
17
18 Note that all API symbols referenced in this document are implicitly in the
19 top-level `mojo` namespace.
20
21 ## Scoped, Typed Handles
22
23 All types of Mojo handles in the C API are simply opaque, integral `MojoHandle`
24 values. The C++ API has more strongly typed wrappers defined for different
25 handle types: `MessagePipeHandle`, `SharedBufferHandle`,
26 `DataPipeConsumerHandle`, `DataPipeProducerHandle`, and `WatcherHandle`.
27
28 Each of these also has a corresponding, move-only, scoped type for safer usage:
29 `ScopedMessagePipeHandle`, `ScopedSharedBufferHandle`, and so on. When a scoped
30 handle type is destroyed, its handle is automatically closed via `MojoClose`.
31 When working with raw handles you should **always** prefer to use one of the
32 scoped types for ownership.
33
34 Similar to `std::unique_ptr`, scoped handle types expose a `get()` method to get
35 at the underlying unscoped handle type as well as the `->` operator to
36 dereference the scoper and make calls directly on the underlying handle type.
37
38 ## Message Pipes
39
40 There are two ways to create a new message pipe using the C++ API. You may
41 construct a `MessagePipe` object:
42
43 ``` cpp
44 mojo::MessagePipe pipe;
45
46 // NOTE: Because pipes are bi-directional there is no implicit semantic
47 // difference between |handle0| or |handle1| here. They're just two ends of a
48 // pipe. The choice to treat one as a "client" and one as a "server" is entirely
49 // a the API user's decision.
50 mojo::ScopedMessagePipeHandle client = std::move(pipe.handle0);
51 mojo::ScopedMessagePipeHandle server = std::move(pipe.handle1);
52 ```
53
54 or you may call `CreateMessagePipe`:
55
56 ``` cpp
57 mojo::ScopedMessagePipeHandle client;
58 mojo::ScopedMessagePipeHandle server;
59 mojo::CreateMessagePipe(nullptr, &client, &server);
60 ```
61
62 There are also some helper functions for constructing message objects and
63 reading/writing them on pipes using the library's more strongly-typed C++
64 handles:
65
66 ``` cpp
67 mojo::ScopedMessageHandle message;
68 mojo::AllocMessage(6, nullptr, 0, MOJO_ALLOC_MESSAGE_FLAG_NONE, &message);
69
70 void *buffer;
71 mojo::GetMessageBuffer(message.get(), &buffer);
72
73 const std::string kMessage = "hello";
74 std::copy(kMessage.begin(), kMessage.end(), static_cast<char*>(buffer));
75
76 mojo::WriteMessageNew(client.get(), std::move(message),
77 MOJO_WRITE_MESSAGE_FLAG_NONE);
78
79 // Some time later...
80
81 mojo::ScopedMessageHandle received_message;
82 uint32_t num_bytes;
83 mojo::ReadMessageNew(server.get(), &received_message, &num_bytes, nullptr,
84 nullptr, MOJO_READ_MESSAGE_FLAG_NONE);
85 ```
86
87 See [message_pipe.h](https://cs.chromium.org/chromium/src/mojo/public/cpp/system /message_pipe.h)
88 for detailed C++ message pipe API documentation.
89
90 ## Data Pipes
91
92 Similar to [Message Pipes](#Message-Pipes), the C++ library has some simple
93 helpers for more strongly-typed data pipe usage:
94
95 ``` cpp
96 mojo::DataPipe pipe;
97 mojo::ScopedDataPipeProducerHandle producer = std::move(pipe.producer);
98 mojo::ScopedDataPipeConsumerHandle consumer = std::move(pipe.consumer);
99
100 // Or alternatively:
101 mojo::ScopedDataPipeProducerHandle producer;
102 mojo::ScopedDataPipeConsumerHandle consumer;
103 mojo::CreateDataPipe(null, &producer, &consumer);
104 ```
105
106 // Reads from a data pipe. See |MojoReadData()| for complete documentation.
107 inline MojoResult ReadDataRaw(DataPipeConsumerHandle data_pipe_consumer,
108 void* elements,
109 uint32_t* num_bytes,
110 MojoReadDataFlags flags) {
111 return MojoReadData(data_pipe_consumer.value(), elements, num_bytes, flags);
112 }
113
114 // Begins a two-phase read
115 C++ helpers which correspond directly to the
116 [Data Pipe C API](/mojo/public/c/system#Data-Pipes) for immediate and two-phase
117 I/O are provided as well. For example:
118
119 ``` cpp
120 uint32_t num_bytes = 7;
121 mojo::WriteDataRaw(producer.get(), "hihihi",
122 &num_bytes, MOJO_WRITE_DATA_FLAG_NONE);
123
124 // Some time later...
125
126 char buffer[64];
127 uint32_t num_bytes = 64;
128 mojo::ReadDataRaw(consumer.get(), buffer, &num_bytes, MOJO_READ_DATA_FLAG_NONE);
129 ```
130
131 See [data_pipe.h](https://cs.chromium.org/chromium/src/mojo/public/cpp/system/da ta_pipe.h)
132 for detailed C++ data pipe API documentation.
133
134 ## Shared Buffers
135
136 A new shared buffers can be allocated like so:
137
138 ``` cpp
139 mojo::ScopedSharedBufferHandle buffer =
140 mojo::ScopedSharedBufferHandle::Create(4096);
141 ```
142
143 This new handle can be cloned arbitrarily many times by using the underlying
144 handle's `Clone` method:
145
146 ``` cpp
147 mojo::ScopedSharedBufferHandle another_handle = buffer->Clone();
148 mojo::ScopedSharedBufferHandle read_only_handle =
149 buffer->Clone(mojo::SharedBufferHandle::AccessMode::READ_ONLY);
150 ```
151
152 And finally the library also provides a scoper for mapping the shared buffer's
153 memory:
154
155 ``` cpp
156 mojo::ScopedSharedBufferMapping mapping = buffer->Map(64);
157 static_cast<int*>(mapping.get()) = 42;
158
159 mojo::ScopedSharedBufferMapping another_mapping = buffer->MapAtOffset(64, 4);
160 static_cast<int*>(mapping.get()) = 43;
161 ```
162
163 When `mapping` and `another_mapping` are destroyed, they automatically unmap
164 their respective memory regions.
165
166 See [buffer.h](https://cs.chromium.org/chromium/src/mojo/public/cpp/system/buffe r.h)
167 for detailed C++ shared buffer API documentation.
168
169 ## Native Platform Handles (File Descriptors, Windows Handles, *etc.*)
170
171 The C++ library provides several helpers for wrapping system handle types.
172 These are specifically useful when working with a few `//base` types, namely
173 `base::PlatformFile` and `base::SharedMemoryHandle`. See
174 [platform_handle.h](https://cs.chromium.org/chromium/src/mojo/public/cpp/system/ platform_handle.h)
175 for detailed C++ platform handle API documentation.
176
177 ## Signals & Watchers
178
179 For an introduction to the concepts of handle signals and watchers, check out
180 the C API's documentation on [Signals & Watchers](/mojo/public/c/system#Signals- Watchers).
181
182 ### Querying Signals
183
184 Any C++ handle type's last known signaling state can be queried by calling the
185 `QuerySignalsState` method on the handle:
186
187 ``` cpp
188 mojo::MessagePipe message_pipe;
189 mojo::DataPipe data_pipe;
190 mojo::HandleSignalsState a = message_pipe.handle0->QuerySignalsState();
191 mojo::HandleSignalsState b = data_pipe.consumer->QuerySignalsState();
192 ```
193
194 The `HandleSignalsState` is a thin wrapper interface around the C API's
195 `MojoHandleSignalsState` structure with convenient accessors for testing
196 the signal bitmasks. Whereas when using the C API you might write:
197
198 ``` c
199 struct MojoHandleSignalsState state;
200 MojoQueryHandleSignalsState(handle0, &state);
201 if (state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE) {
202 // ...
203 }
204 ```
205
206 the C++ API equivalent would be:
207
208 ``` cpp
209 if (message_pipe.handle0->QuerySignalsState().readable()) {
210 // ...
211 }
212 ```
213
214 ### Watching Handles
215
216 The [`mojo::SimpleWatcher`](https://cs.chromium.org/chromium/src/mojo/public/cpp /system/simple_watcher.h)
217 class serves as a convenient helper for using the [low-level watcher API](/mojo/ public/c/system#Signals-Watchers)
218 to watch a handle for signaling state changes. A `SimpleWatcher` is bound to a
219 single thread and always dispatches its notifications on a
220 `base::SingleThreadTaskRunner`.
221
222 `SimpleWatcher` has two possible modes of operation, selected at construction
223 time by the `mojo::SimpleWatcher::ArmingPolicy` enum:
224
225 * `MANUAL` mode requires the user to manually call `Arm` and/or `ArmOrNotify`
226 before any notifications will fire regarding the state of the watched handle.
227 Every time the notification callback is run, the `SimpleWatcher` must be
228 rearmed again before the next one can fire. See
229 [Arming a Watcher](/mojo/public/c/system#Arming-a-Watcher) and the
230 documentation in `SimpleWatcher`'s header.
231
232 * `AUTOMATIC` mode ensures that the `SimpleWatcher` always either is armed or
233 has a pending notification task queued for execution.
234
235 `AUTOMATIC` mode is more convenient but can result in redundant notification
236 tasks, especially if the provided callback does not make a strong effort to
237 return the watched handle to an uninteresting signaling state (by *e.g.*,
238 reading all its available messages when notified of readability.)
239
240 Example usage:
241
242 ``` cpp
243 class PipeReader {
244 public:
245 PipeReader(mojo::ScopedMessagePipeHandle pipe)
246 : pipe_(std::move(pipe)),
247 watcher_(mojo::SimpleWatcher::ArmingPolicy::AUTOMATIC) {
248 // NOTE: base::Unretained is safe because the callback can never be run
249 // after SimpleWatcher destruction.
250 watcher_.Watch(pipe_.get(), MOJO_HANDLE_SIGNAL_READABLE,
251 base::Bind(&PipeReader::OnReadable, base::Unretained(this)));
252 }
253
254 ~PipeReader() {}
255
256 private:
257 void OnReadable(MojoResult result) {
258 while (result == MOJO_RESULT_OK) {
259 mojo::ScopedMessageHandle message;
260 uint32_t num_bytes;
261 result = mojo::ReadMessageNew(pipe_.get(), &message, &num_bytes, nullptr,
262 nullptr, MOJO_READ_MESSAGE_FLAG_NONE);
263 DCHECK_EQ(result, MOJO_RESULT_OK);
264 messages_.emplace_back(std::move(message));
265 }
266 }
267
268 mojo::ScopedMessagePipeHandle pipe_;
269 mojo::SimpleWatcher watcher_;
270 std::vector<mojo::ScopedMessageHandle> messages_;
271 };
272
273 mojo::MessagePipe pipe;
274 PipeReader reader(std::move(pipe.handle0));
275
276 // Written messages will asynchronously end up in |reader.messages_|.
277 WriteABunchOfStuff(pipe.handle1.get());
278 ```
279
280 ## Synchronous Waiting
281
282 The C++ System API defines some utilities to block a calling thread while
283 waiting for one or more handles to change signaling state in an interesting way.
284 These threads combine usage of the [low-level Watcher API](/mojo/public/c/system #Signals-Watchers)
285 with common synchronization primitives (namely `base::WaitableEvent`.)
286
287 While these API features should be used sparingly, they are sometimes necessary.
288
289 See the documentation in
290 [wait.h](https://cs.chromium.org/chromium/src/mojo/public/cpp/system/wait.h)
291 and [wait_set.h](https://cs.chromium.org/chromium/src/mojo/public/cpp/system/wai t_set.h)
292 for a more detailed API reference.
293
294 ### Waiting On a Single Handle
295
296 The `mojo::Wait` function simply blocks the calling thread until a given signal
297 mask is either partially satisfied or fully unsatisfiable on a given handle.
298
299 ``` cpp
300 mojo::MessagePipe pipe;
301 mojo::WriteMessageRaw(pipe.handle0.get(), "hey", 3, nullptr, nullptr,
302 MOJO_WRITE_MESSAGE_FLAG_NONE);
303 MojoResult result = mojo::Wait(pipe.handle1.get(), MOJO_HANDLE_SIGNAL_READABLE);
304 DCHECK_EQ(result, MOJO_RESULT_OK);
305
306 // Guaranteed to succeed because we know |handle1| is readable now.
307 mojo::ScopedMessageHandle message;
308 uint32_t num_bytes;
309 mojo::ReadMessageNew(pipe.handle1.get(), &num_bytes, nullptr, nullptr,
310 MOJO_READ_MESSAGE_FLAG_NONE);
311 ```
312
313 `mojo::Wait` is most typically useful in limited testing scenarios.
314
315 ### Waiting On Multiple Handles
316
317 `mojo::WaitMany` provides a simple API to wait on multiple handles
318 simultaneously, returning when any handle's given signal mask is either
319 partially satisfied or fully unsatisfiable.
320
321 ``` cpp
322 mojo::MessagePipe a, b;
323 GoDoSomethingWithPipes(std:move(a.handle1), std::move(b.handle1));
324
325 mojo::MessagePipeHandle handles[2] = {a.handle0.get(), b.handle0.get()};
326 MojoHandleSignals signals[2] = {MOJO_HANDLE_SIGNAL_READABLE,
327 MOJO_HANDLE_SIGNAL_READABLE};
328 size_t ready_index;
329 MojoResult result = mojo::WaitMany(handles, signals, 2, &ready_index);
330 if (ready_index == 0) {
331 // a.handle0 was ready.
332 } else {
333 // b.handle0 was ready.
334 }
335 ```
336
337 Similar to `mojo::Wait`, `mojo::WaitMany` is primarily useful in testing. When
338 waiting on multiple handles in production code, you should almost always instead
339 use a more efficient and more flexible `mojo::WaitSet` as described in the next
340 section.
341
342 ### Waiting On Handles and Events Simultaneously
343
344 Typically when waiting on one or more handles to signal, the set of handles and
345 conditions being waited upon do not change much between consecutive blocking
346 waits. It's also often useful to be able to interrupt the blocking operation
347 as efficiently as possible.
348
349 [`mojo::WaitSet`](https://cs.chromium.org/chromium/src/mojo/public/cpp/system/wa it_set.h)
350 is designed with these conditions in mind. A `WaitSet` maintains a persistent
351 set of (not-owned) Mojo handles and `base::WaitableEvent`s, which may be
352 explicitly added to or removed from the set at any time.
353
354 The `WaitSet` may be waited upon repeatedly, each time blocking the calling
355 thread until either one of the handles attains an interesting signaling state or
356 one of the events is signaled. For example let's suppose we want to wait up to 5
357 seconds for either one of two handles to become readable:
358
359 ``` cpp
360 base::WaitableEvent timeout_event(
361 base::WaitableEvent::ResetPolicy::MANUAL,
362 base::WaitableEvent::InitialState::NOT_SIGNALED);
363 mojo::MessagePipe a, b;
364
365 GoDoStuffWithPipes(std::move(a.handle1), std::move(b.handle1));
366
367 mojo::WaitSet wait_set;
368 wait_set.AddHandle(a.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE);
369 wait_set.AddHandle(b.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE);
370 wait_set.AddEvent(&timeout_event);
371
372 // Ensure the Wait() lasts no more than 5 seconds.
373 bg_thread->task_runner()->PostDelayedTask(
374 FROM_HERE,
375 base::Bind([](base::WaitableEvent* e) { e->Signal(); }, &timeout_event);
376 base::TimeDelta::FromSeconds(5));
377
378 base::WaitableEvent* ready_event = nullptr;
379 size_t num_ready_handles = 1;
380 mojo::Handle ready_handle;
381 MojoResult ready_result;
382 wait_set.Wait(&ready_event, &num_ready_handles, &ready_handle, &ready_result);
383
384 // The apex of thread-safety.
385 bg_thread->Stop();
386
387 if (ready_event) {
388 // The event signaled...
389 }
390
391 if (num_ready_handles > 0) {
392 // At least one of the handles signaled...
393 // NOTE: This and the above condition are not mutually exclusive. If handle
394 // signaling races with timeout, both things might be true.
395 }
396 ```
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698