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

Side by Side Diff: mojo/public/c/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 is a lightweight API (with an eventually-stable ABI) upon
8 which all higher layers of the Mojo system are built.
9
10 This API exposes the fundamental capabilities to: create, read from, and write
11 to **message pipes**; create, read from, and write to **data pipes**; create
12 **shared buffers** and generate sharable handles to them; wrap platform-specific
13 handle objects (such as **file descriptors**, **Windows handles**, and
14 **Mach ports**) for seamless transit over message pipes; and efficiently watch
15 handles for various types of state transitions.
16
17 This document provides a brief guide to API usage with example code snippets.
18 For a detailed API references please consult the headers in
19 [//mojo/public/c/system](https://cs.chromium.org/chromium/src/mojo/public/c/syst em/).
20
21 ### A Note About Multithreading
22
23 The Mojo C System API is entirely thread-agnostic. This means that all functions
24 may be called from any thread in a process, and there are no restrictions on how
25 many threads can use the same object at the same time.
26
27 Of course this does not mean you can completely ignore potential concurrency
28 issues -- such as a handle being closed on one thread while another thread is
29 trying to perform an operation on the same handle -- but there is nothing
30 fundamentally incorrect about using any given API or handle from multiple
31 threads.
32
33 ### A Note About Synchronization
34
35 Every Mojo API call is non-blocking and synchronously yields some kind of status
36 result code, but the call's side effects -- such as affecting the state of
37 one or more handles in the system -- may or may not occur asynchronously.
38
39 Mojo objects can be observed for interesting state changes in a way that is
40 thread-agnostic and in some ways similar to POSIX signal handlers: *i.e.*
41 user-provided notification handlers may be invoked at any time on arbitrary
42 threads in the process. It is entirely up to the API user to take appropriate
43 measures to synchronize operations against other application state.
44
45 The higher level [system](/mojo#High-Level-System-APIs) and
46 [bindings](/mojo#High-Level-Bindings-APIs) APIs provide helpers to simplify Mojo
47 usage in this regard, at the expense of some flexibility.
48
49 ## Result Codes
50
51 Most API functions return a value of type `MojoResult`. This is an integral
52 result code used to convey some meaningful level of detail about the result of a
53 requested operation.
54
55 See [//mojo/public/c/system/types.h](https://cs.chromium.org/chromium/src/mojo/p ublic/c/system/types.h)
56 for different possible values. See documentation for individual API calls for
57 more specific contextual meaning of various result codes.
58
59 ## Handles
60
61 Every Mojo IPC primitive is identified by a generic, opaque integer handle of
62 type `MojoHandle`. Handles can be acquired by creating new objects using various
63 API calls, or by reading messages which contain attached handles.
64
65 A `MojoHandle` can represent a message pipe endpoint, a data pipe consumer,
66 a data pipe producer, a shared buffer reference, a wrapped native platform
67 handle such as a POSIX file descriptor or a Windows system handle, or a watcher
68 object (see [Signals & Watchers](#Signals-Watchers) below.)
69
70 All types of handles except for watchers (which are an inherently local concept)
71 can be attached to messages and sent over message pipes.
72
73 Any `MojoHandle` may be closed by calling `MojoClose`:
74
75 ``` c
76 MojoHandle x = DoSomethingToGetAValidHandle();
77 MojoResult result = MojoClose(x);
78 ```
79
80 If the handle passed to `MojoClose` was a valid handle, it will be closed and
81 `MojoClose` returns `MOJO_RESULT_OK`. Otherwise it returns
82 `MOJO_RESULT_INVALID_ARGUMENT`.
83
84 Similar to native system handles on various popular platforms, `MojoHandle`
85 values may be reused over time. Thus it is important to avoid logical errors
86 which lead to misplaced handle ownership, double-closes, *etc.*
87
88 ## Message Pipes
89
90 A message pipe is a bidirectional messaging channel which can carry arbitrary
91 unstructured binary messages with zero or more `MojoHandle` attachments to be
92 transferred from one end of a pipe to the other. Message pipes work seamlessly
93 across process boundaries or within a single process.
94
95 The [Embedder Development Kit (EDK)](/mojo/edk/embedder) provides the means to
96 bootstrap one or more primordial cross-process message pipes, and it's up to
97 Mojo embedders to expose this capability in some useful way. Once such a pipe is
98 established, additional handles -- including other message pipe handles -- may
99 be sent to a remote process using that pipe (or in turn, over other pipes sent
100 over that pipe, or pipes sent over *that* pipe, and so on...)
101
102 The public C System API exposes the ability to read and write messages on pipes
103 and to create new message pipes.
104
105 See [//mojo/public/c/system/message_pipe.h](https://cs.chromium.org/chromium/src /mojo/public/c/system/message_pipe.h)
106 for detailed message pipe API documentation.
107
108 ### Creating Message Pipes
109
110 `MojoCreateMessagePipe` can be used to create a new message pipe:
111
112 ``` c
113 MojoHandle a, b;
114 MojoResult result = MojoCreateMessagePipe(NULL, &a, &b);
115 ```
116
117 After this snippet, `result` should be `MOJO_RESULT_OK` (it's really hard for
118 this to fail!), and `a` and `b` will contain valid Mojo handles, one for each
119 end of the new message pipe.
120
121 Any messages written to `a` are eventually readable from `b`, and any messages
122 written to `b` are eventually readable from `a`. If `a` is closed at any point,
123 `b` will eventually become aware of this fact; likewise if `b` is closed, `a`
124 will become aware of that.
125
126 The state of these conditions can be queried and watched asynchronously as
127 described in the [Signals & Watchers](#Signals-Watchers) section below.
128
129 ### Allocating Messages
130
131 In order to avoid redundant internal buffer copies, Mojo would like to allocate
132 your message storage buffers for you. This is easy:
133
134 ``` c
135 MojoMessageHandle message;
136 MojoResult result = MojoAllocMessage(6, NULL, 0, MOJO_ALLOC_MESSAGE_FLAG_NONE,
137 &message);
138 ```
139
140 Note that we have a special `MojoMessageHandle` type for message objects.
141
142 The code above allocates a buffer for a message payload of 6 bytes with no
143 handles attached.
144
145 If we change our mind and decide not to send this message, we can delete it:
146
147 ``` c
148 MojoResult result = MojoFreeMessage(message);
149 ```
150
151 If we instead decide to send our newly allocated message, we first need to fill
152 in the payload data with something interesting. How about a pleasant greeting:
153
154 ``` c
155 void* buffer = NULL;
156 MojoResult result = MojoGetMessageBuffer(message, &buffer);
157 memcpy(buffer, "hello", 6);
158 ```
159
160 Now we can write the message to a pipe. Note that attempting to write a message
161 transfers ownership of the message object (and any attached handles) into the
162 target pipe and there is therefore no need to subsequently call
163 `MojoFreeMessage` on that message.
164
165 ### Writing Messages
166
167 ``` c
168 result = MojoWriteMessageNew(a, message, MOJO_WRITE_MESSAGE_FLAG_NONE);
169 ```
170
171 `MojoWriteMessage` is a *non-blocking* call: it always returns
172 immediately. If its return code is `MOJO_RESULT_OK` the message will eventually
173 find its way to the other end of the pipe -- assuming that end isn't closed
174 first, of course. If the return code is anything else, the message is deleted
175 and not transferred.
176
177 In this case since we know `b` is still open, we also know the message will
178 eventually arrive at `b`. `b` can be queried or watched to become aware of when
179 the message arrives, but we'll ignore that complexity for now. See
180 [Signals & Watchers](#Signals-Watchers) below for more information.
181
182 *** aside
183 **NOTE**: Although this is an implementation detail and not strictly guaranteed by the
184 System API, it is true in the current implementation that the message will
185 arrive at `b` before the above `MojoWriteMessage` call even returns, because `b`
186 is in the same process as `a` and has never been transferred over another pipe.
187 ***
188
189 ### Reading Messages
190
191 We can read a new message object from a pipe:
192
193 ``` c
194 MojoMessageHandle message;
195 uint32_t num_bytes;
196 MojoResult result = MojoReadMessageNew(b, &message, &num_bytes, NULL, NULL,
197 MOJO_READ_MESSAGE_FLAG_NONE);
198 ```
199
200 and map its buffer to retrieve the contents:
201
202 ``` c
203 void* buffer = NULL;
204 MojoResult result = MojoGetMessageBuffer(message, &buffer);
205 printf("Pipe says: %s", (const char*)buffer);
206 ```
207
208 `result` should be `MOJO_RESULT_OK` and this snippet should write `"hello"` to
209 `stdout`.
210
211 If we try were to try reading again now that there are no messages on `b`:
212
213 ``` c
214 MojoMessageHandle message;
215 MojoResult result = MojoReadMessageNew(b, &message, NULL, NULL, NULL,
216 MOJO_READ_MESSAGE_FLAG_NONE);
217 ```
218
219 We'll get a `result` of `MOJO_RESULT_SHOULD_WAIT`, indicating that the pipe is
220 not yet readable.
221
222 ### Messages With Handles
223
224 Probably the most useful feature of Mojo IPC is that message pipes can carry
225 arbitrary Mojo handles, including other message pipes. This is also
226 straightforward.
227
228 Here's an example which creates two pipes, using the first pipe to transfer
229 one end of the second pipe. If you have a good imagination you can pretend the
230 first pipe spans a process boundary, which makes the example more practically
231 interesting:
232
233 ``` c
234 MojoHandle a, b;
235 MojoHandle c, d;
236 MojoMessage message;
237
238 // Allocate a message with an empty payload and handle |c| attached. Note that
239 // this takes ownership of |c|, effectively invalidating its handle value.
240 MojoResult result = MojoAllocMessage(0, &c, 1, MOJO_ALLOC_MESSAGE_FLAG_NONE,
241 message);
242
243 result = MojoWriteMessageNew(a, message, MOJO_WRITE_MESSAGE_FLAG_NONE);
244
245 // Some time later...
246 uint32_t num_bytes;
247 MojoHandle e;
248 uint32_t num_handles = 1;
249 MojoResult result = MojoReadMessageNew(b, &message, &num_bytes, &e,
250 &num_handles,
251 MOJO_READ_MESSAGE_FLAG_NONE);
252 ```
253
254 At this point the handle in `e` is now referencing the same message pipe
255 endpoint which was originally referenced by `c`.
256
257 Note that `num_handles` above is initialized to 1 before we pass its address to
258 `MojoReadMessageNew`. This is to indicate how much `MojoHandle` storage is
259 available at the output buffer we gave it (`&e` above).
260
261 If we didn't know how many handles to expect in an incoming message -- which is
262 often the case -- we can use `MojoReadMessageNew` to query for this information
263 first:
264
265 ``` c
266 MojoMessageHandle message;
267 uint32_t num_bytes = 0;
268 uint32_t num_handles = 0;
269 MojoResult result = MojoReadMessageNew(b, &message, &num_bytes, NULL,
270 &num_handles,
271 MOJO_READ_MESSAGE_FLAG_NONE);
272 ```
273
274 If in this case there were a received message on `b` with some nonzero number
275 of handles, `result` would be `MOJO_RESULT_RESOURCE_EXHAUSTED`, and both
276 `num_bytes` and `num_handles` would be updated to reflect the payload size and
277 number of attached handles on the next available message.
278
279 It's also worth noting that if there did happen to be a message available with
280 no payload and no handles (*i.e.* an empty message), this would actually return
281 `MOJO_RESULT_OK`.
282
283 ## Data Pipes
284
285 Data pipes provide an efficient unidirectional channel for moving large amounts
286 of unframed data between two endpoints. Every data pipe has a fixed
287 **element size** and **capacity**. Reads and writes must be done in sizes that
288 are a multiple of the element size, and writes to the pipe can only be queued
289 up to the pipe's capacity before reads must be done to make more space
290 available.
291
292 Every data pipe has a single **producer** handle used to write data into the
293 pipe and a single **consumer** handle used to read data out of the pipe.
294
295 Finally, data pipes support both immediate I/O -- reading into and writing out
296 from user-supplied buffers -- as well as two-phase I/O, allowing callers to
297 temporarily lock some portion of the data pipe in order to read or write its
298 contents directly.
299
300 See [//mojo/public/c/system/data_pipe.h](https://cs.chromium.org/chromium/src/mo jo/public/c/system/data_pipe.h)
301 for detailed data pipe API documentation.
302
303 ### Creating Data Pipes
304
305 Use `MojoCreateDataPipe` to create a new data pipe. The
306 `MojoCreateDataPipeOptions` structure is used to configure the new pipe, but
307 this can be omitted to assume the default options of a single-byte element size
308 and an implementation-defined default capacity (64 kB at the time of this
309 writing.)
310
311 ``` c
312 MojoHandle producer, consumer;
313 MojoResult result = MojoCreateDataPipe(NULL, &producer, &consumer);
314 ```
315
316 ### Immediate I/O
317
318 Data can be written into or read out of a data pipe using buffers provided by
319 the caller. This is generally more convenient than two-phase I/O but is
320 also less efficient due to extra copying.
321
322 ``` c
323 uint32_t num_bytes = 12;
324 MojoResult result = MojoWriteData(producer, "datadatadata", &num_bytes,
325 MOJO_WRITE_DATA_FLAG_NONE);
326 ```
327
328 The above snippet will attempt to write 12 bytes into the data pipe, which
329 should succeed and return `MOJO_RESULT_OK`. If the available capacity on the
330 pipe was less than the amount requested (the input value of `*num_bytes`) this
331 will copy what it can into the pipe and return the number of bytes written in
332 `*num_bytes`. If no data could be copied this will instead return
333 `MOJO_RESULT_SHOULD_WAIT`.
334
335 Reading from the consumer is a similar operation.
336
337 ``` c
338 char buffer[64];
339 uint32_t num_bytes = 64;
340 MojoResult result = MojoReadData(consumer, buffer, &num_bytes,
341 MOJO_READ_DATA_FLAG_NONE);
342 ```
343
344 This will attempt to read up to 64 bytes, returning the actual number of bytes
345 read in `*num_bytes`.
346
347 `MojoReadData` supports a number of interesting flags to change the behavior:
348 you can peek at the data (copy bytes out without removing them from the pipe),
349 query the number of bytes available without doing any actual reading of the
350 contents, or discard data from the pipe without bothering to copy it anywhere.
351
352 This also supports a `MOJO_READ_DATA_FLAG_ALL_OR_NONE` which ensures that the
353 call succeeds **only** if the exact number of bytes requested could be read.
354 Otherwise such a request will fail with `MOJO_READ_DATA_OUT_OF_RANGE`.
355
356 ### Two-Phase I/O
357
358 Data pipes also support two-phase I/O operations, allowing a caller to
359 temporarily lock a portion of the data pipe's storage for direct memory access.
360
361 ``` c
362 void* buffer;
363 uint32_t num_bytes = 1024;
364 MojoResult result = MojoBeginWriteData(producer, &buffer, &num_bytes,
365 MOJO_WRITE_DATA_FLAG_NONE);
366 ```
367
368 This requests write access to a region of up to 1024 bytes of the data pipe's
369 next available capacity. Upon success, `buffer` will point to the writable
370 storage and `num_bytes` will indicate the size of the buffer there.
371
372 The caller should then write some data into the memory region and release it
373 ASAP, indicating the number of bytes actually written:
374
375 ``` c
376 memcpy(buffer, "hello", 6);
377 MojoResult result = MojoEndWriteData(producer, 6);
378 ```
379
380 Two-phase reads look similar:
381
382 ``` c
383 void* buffer;
384 uint32_t num_bytes = 1024;
385 MojoResult result = MojoBeginReadData(consumer, &buffer, &num_bytes,
386 MOJO_READ_DATA_FLAG_NONE);
387 // result should be MOJO_RESULT_OK, since there is some data available.
388
389 printf("Pipe says: %s", (const char*)buffer); // Should say "hello".
390
391 result = MojoEndReadData(consumer, 1); // Say we only consumed one byte.
392
393 num_bytes = 1024;
394 result = MojoBeginReadData(consumer, &buffer, &num_bytes,
395 MOJO_READ_DATA_FLAG_NONE);
396 printf("Pipe says: %s", (const char*)buffer); // Should say "ello".
397 result = MojoEndReadData(consumer, 5);
398 ```
399
400 ## Shared Buffers
401
402 Shared buffers are chunks of memory which can be mapped simultaneously by
403 multiple processes. Mojo provides a simple API to make these available to
404 applications.
405
406 See [//mojo/public/c/system/buffer.h](https://cs.chromium.org/chromium/src/mojo/ public/c/system/buffer.h)
407 for detailed shared buffer API documentation.
408
409 ### Creating Buffer Handles
410
411 Usage is straightforward. You can create a new buffer:
412
413 ``` c
414 // Allocate a shared buffer of 4 kB.
415 MojoHandle buffer;
416 MojoResult result = MojoCreateSharedBuffer(NULL, 4096, &buffer);
417 ```
418
419 You can also duplicate an existing shared buffer handle:
420
421 ``` c
422 MojoHandle another_name_for_buffer;
423 MojoResult result = MojoDuplicateBufferHandle(buffer, NULL,
424 &another_name_for_buffer);
425 ```
426
427 This is useful if you want to retain a handle to the buffer while also sharing
428 handles with one or more other clients. The allocated buffer remains valid as
429 long as at least one shared buffer handle exists to reference it.
430
431 ### Mapping Buffers
432
433 You can map (and later unmap) a specified range of the buffer to get direct
434 memory access to its contents:
435
436 ``` c
437 void* data;
438 MojoResult result = MojoMapBuffer(buffer, 0, 64, &data,
439 MOJO_MAP_BUFFER_FLAG_NONE);
440
441 *(int*)data = 42;
442 result = MojoUnmapBuffer(data);
443 ```
444
445 A buffer may have any number of active mappings at a time, in any number of
446 processes.
447
448 ### Read-Only Handles
449
450 An option can also be specified on `MojoDuplicateBufferHandle` to ensure
451 that the newly duplicated handle can only be mapped to read-only memory:
452
453 ``` c
454 MojoHandle read_only_buffer;
455 MojoDuplicateBufferHandleOptions options;
456 options.struct_size = sizeof(options);
457 options.flags = MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_READ_ONLY;
458 MojoResult result = MojoDuplicateBufferHandle(buffer, &options,
459 &read_only_buffer);
460
461 // Attempt to map and write to the buffer using the read-only handle:
462 void* data;
463 result = MojoMapBuffer(read_only_buffer, 0, 64, &data,
464 MOJO_MAP_BUFFER_FLAG_NONE);
465 *(int*)data = 42; // CRASH
466 ```
467
468 *** note
469 **NOTE:** One important limitation of the current implementation is that
470 read-only handles can only be produced from a handle that was originally created
471 by `MojoCreateSharedBuffer` (*i.e.*, you cannot create a read-only duplicate
472 from a non-read-only duplicate), and the handle cannot have been transferred
473 over a message pipe first.
474 ***
475
476 ## Native Platform Handles (File Descriptors, Windows Handles, *etc.*)
477
478 Native platform handles to system objects can be wrapped as Mojo handles for
479 seamless transit over message pipes. Mojo currently supports wrapping POSIX
480 file descriptors, Windows handles, and Mach ports.
481
482 See [//mojo/public/c/system/platform_handle.h](https://cs.chromium.org/chromium/ src/mojo/public/c/system/platform_handle.h)
483 for detailed platform handle API documentation.
484
485 ### Wrapping Basic Handle Types
486
487 Wrapping a POSIX file descriptor is simple:
488
489 ``` c
490 MojoPlatformHandle platform_handle;
491 platform_handle.struct_size = sizeof(platform_handle);
492 platform_handle.type = MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR;
493 platform_handle.value = (uint64_t)fd;
494 MojoHandle handle;
495 MojoResult result = MojoWrapPlatformHandle(&platform_handle, &handle);
496 ```
497
498 Note that at this point `handle` effectively owns the file descriptor
499 and if you were to call `MojoClose(handle)`, the file descriptor would be closed
500 too; but we're not going to close it here! We're going to pretend we've sent it
501 over a message pipe, and now we want to unwrap it on the other side:
502
503 ``` c
504 MojoPlatformHandle platform_handle;
505 platform_handle.struct_size = sizeof(platform_handle);
506 MojoResult result = MojoUnwrapPlatformHandle(handle, &platform_handle);
507 int fd = (int)platform_handle.value;
508 ```
509
510 The situation looks nearly identical for wrapping and unwrapping Windows handles
511 and Mach ports.
512
513 ### Wrapping Shared Buffer Handles
514
515 Unlike other handle types, shared buffers have special meaning in Mojo, and it
516 may be desirable to wrap a native platform handle -- along with some extra
517 metadata -- such that be treated like a real Mojo shared buffer handle.
518 Conversely it can also be useful to unpack a Mojo shared buffer handle into
519 a native platform handle which references the buffer object. Both of these
520 things can be done using the `MojoWrapPlatformSharedBuffer` and
521 `MojoUnwrapPlatformSharedBuffer` APIs.
522
523 On Windows, the wrapped platform handle must always be a Windows handle to
524 a file mapping object.
525
526 On OS X, the wrapped platform handle must be a memory-object send right.
527
528 On all other POSIX systems, the wrapped platform handle must be a file
529 descriptor for a shared memory object.
530
531 ## Signals & Watchers
532
533 Message pipe and data pipe (producer and consumer) handles can change state in
534 ways that may be interesting to a Mojo API user. For example, you may wish to
535 know when a message pipe handle has messages available to be read or when its
536 peer has been closed. Such states are reflected by a fixed set of boolean
537 signals on each pipe handle.
538
539 ### Signals
540
541 Every message pipe and data pipe handle maintains a notion of
542 **signaling state** which may be queried at any time. For example:
543
544 ``` c
545 MojoHandle a, b;
546 MojoCreateMessagePipe(NULL, &a, &b);
547
548 MojoHandleSignalsState state;
549 MojoResult result = MojoQueryHandleSignalsState(a, &state);
550 ```
551
552 The `MojoHandleSignalsState` structure exposes two fields: `satisfied_signals`
553 and `satisfiable_signals`. Both of these are bitmasks of the type
554 `MojoHandleSignals` (see [//mojo/public/c/system/types.h](https://cs.chromium.or g/chromium/src/mojo/public/c/system/types.h)
555 for more details.)
556
557 The `satisfied_signals` bitmask indicates signals which were satisfied on the
558 handle at the time of the call, while the `satisfiable_signals` bitmask
559 indicates signals which were still possible to satisfy at the time of the call.
560 It is thus by definition always true that:
561
562 ``` c
563 (satisfied_signals | satisfiable_signals) == satisfiable_signals
564 ```
565
566 In other words a signal obviously cannot be satisfied if it is no longer
567 satisfiable. Furthermore once a signal is unsatisfiable, *i.e.* is no longer
568 set in `sastisfiable_signals`, it can **never** become satisfiable again.
569
570 To illustrate this more clearly, consider the message pipe created above. Both
571 ends of the pipe are still open and neither has been written to yet. Thus both
572 handles start out with the same signaling state:
573
574 | Field | State |
575 |-----------------------|-------|
576 | `satisfied_signals` | `MOJO_HANDLE_SIGNAL_WRITABLE`
577 | `satisfiable_signals` | `MOJO_HANDLE_SIGNAL_READABLE + MOJO_HANDLE_SIGNAL_WRIT ABLE + MOJO_HANDLE_SIGNAL_PEER_CLOSED`
578
579 Writing a message to handle `b` will eventually alter the signaling state of `a`
580 such that `MOJO_HANDLE_SIGNAL_READABLE` also becomes satisfied. If we were to
581 then close `b`, the signaling state of `a` would look like:
582
583 | Field | State |
584 |-----------------------|-------|
585 | `satisfied_signals` | `MOJO_HANDLE_SIGNAL_READABLE + MOJO_HANDLE_SIGNAL_PEER _CLOSED`
586 | `satisfiable_signals` | `MOJO_HANDLE_SIGNAL_READABLE + MOJO_HANDLE_SIGNAL_PEER _CLOSED`
587
588 Note that even though `a`'s peer is known to be closed (hence making `a`
589 permanently unwritable) it remains readable because there's still an unread
590 received message waiting to be read from `a`.
591
592 Finally if we read the last message from `a` its signaling state becomes:
593
594 | Field | State |
595 |-----------------------|-------|
596 | `satisfied_signals` | `MOJO_HANDLE_SIGNAL_PEER_CLOSED`
597 | `satisfiable_signals` | `MOJO_HANDLE_SIGNAL_PEER_CLOSED`
598
599 and we know definitively that `a` can never be read from again.
600
601 ### Watching Signals
602
603 The ability to query a handle's signaling state can be useful, but it's not
604 sufficient to support robust and efficient pipe usage. Mojo watchers empower
605 users with the ability to **watch** a handle's signaling state for interesting
606 changes and automatically invoke a notification handler in response.
607
608 When a watcher is created it must be bound to a function pointer matching
609 the following signature, defined in
610 [//mojo/public/c/system/watcher.h](https://cs.chromium.org/chromium/src/mojo/pub lic/c/system/watcher.h):
611
612 ``` c
613 typedef void (*MojoWatcherNotificationCallback)(
614 uintptr_t context,
615 MojoResult result,
616 MojoHandleSignalsState signals_state,
617 MojoWatcherNotificationFlags flags);
618 ```
619
620 The `context` argument corresponds to a specific handle being watched by the
621 watcher (read more below), and the remaining arguments provide details regarding
622 the specific reason for the notification. It's important to be aware that a
623 watcher's registered handler may be called **at any time** and
624 **on any thread**.
625
626 It's also helpful to understand a bit about the mechanism by which the handler
627 can be invoked. Essentially, any Mojo C System API call may elicit a handle
628 state change of some kind. If such a change is relevant to conditions watched by
629 a watcher, and that watcher is in a state which allows it raise a corresponding
630 notification, its notification handler will be invoked synchronously some time
631 before the outermost System API call on the current thread's stack returns.
632
633 Handle state changes can also occur as a result of incoming IPC from an external
634 process. If a pipe in the current process is connected to an endpoint in another
635 process and the internal Mojo system receives an incoming message bound for the
636 local endpoint, the arrival of that message will trigger a state change on the
637 receiving handle and may thus invoke one or more watchers' notification handlers
638 as a result.
639
640 The `MOJO_WATCHER_NOTIFICATION_FLAG_FROM_SYSTEM` flag on the notification
641 handler's `flags` argument is used to indicate whether the handler was invoked
642 due to such an internal system IPC event (if the flag is set), or if it was
643 invoked synchronously due to some local API call (if the flag is unset.)
644 This distinction can be useful to make in certain cases to *e.g.* avoid
645 accidental reentrancy in user code.
646
647 ### Creating a Watcher
648
649 Creating a watcher is simple:
650
651 ``` c
652
653 void OnNotification(uintptr_t context,
654 MojoResult result,
655 MojoHandleSignalsState signals_state,
656 MojoWatcherNotificationFlags flags) {
657 // ...
658 }
659
660 MojoHandle w;
661 MojoResult result = MojoCreateWatcher(&OnNotification, &w);
662 ```
663
664 Like all other `MojoHandle` types, watchers may be destroyed by closing them
665 with `MojoClose`. Unlike other `MojoHandle` types, watcher handles are **not**
666 transferrable across message pipes.
667
668 In order for a watcher to be useful, it has to watch at least one handle.
669
670 ### Adding a Handle to a Watcher
671
672 Any given watcher can watch any given (message or data pipe) handle for some set
673 of signaling conditions. A handle may be watched simultaneously by multiple
674 watchers, and a single watcher can watch multiple different handles
675 simultaneously.
676
677 ``` c
678 MojoHandle a, b;
679 MojoCreateMessagePipe(NULL, &a, &b);
680
681 // Watch handle |a| for readability.
682 const uintptr_t context = 1234;
683 MojoResult result = MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, context);
684 ```
685
686 We've successfully instructed watcher `w` to begin watching pipe handle `a` for
687 readability. However, our recently created watcher is still in a **disarmed**
688 state, meaning that it will never fire a notification pertaining to this watched
689 signaling condition. It must be **armed** before that can happen.
690
691 ### Arming a Watcher
692
693 In order for a watcher to invoke its notification handler in response to a
694 relevant signaling state change on a watched handle, it must first be armed. A
695 watcher may only be armed if none of its watched handles would elicit a
696 notification immediately once armed.
697
698 In this case `a` is clearly not yet readable, so arming should succeed:
699
700 ``` c
701 MojoResult result = MojoArmWatcher(w, NULL, NULL, NULL, NULL);
702 ```
703
704 Now we can write to `b` to make `a` readable:
705
706 ``` c
707 MojoWriteMessage(b, NULL, 0, NULL, 0, MOJO_WRITE_MESSAGE_NONE);
708 ```
709
710 Eventually -- and in practice possibly before `MojoWriteMessage` even
711 returns -- this will cause `OnNotification` to be invoked on the calling thread
712 with the `context` value (*i.e.* 1234) that was given when the handle was added
713 to the watcher.
714
715 The `result` parameter will be `MOJO_RESULT_OK` to indicate that the watched
716 signaling condition has been *satisfied*. If the watched condition had instead
717 become permanently *unsatisfiable* (*e.g.*, if `b` were instead closed), `result `
718 would instead indicate `MOJO_RESULT_FAILED_PRECONDITION`.
719
720 **NOTE:** Immediately before a watcher decides to invoke its notification
721 handler, it automatically disarms itself to prevent another state change from
722 eliciting another notification. Therefore a watcher must be repeatedly rearmed
723 in order to continue dispatching signaling notifications.
724
725 As noted above, arming a watcher may fail if any of the watched conditions for
726 a handle are already partially satisfied or fully unsatisfiable. In that case
727 the caller may provide buffers for `MojoArmWatcher` to store information about
728 a subset of the relevant watches which caused it to fail:
729
730 ``` c
731 // Provide some storage for information about watches that are already ready.
732 uint32_t num_ready_contexts = 4;
733 uintptr_t ready_contexts[4];
734 MojoResult ready_results[4];
735 struct MojoHandleSignalsStates ready_states[4];
736 MojoResult result = MojoArmWatcher(w, &num_ready_contexts, ready_contexts,
737 ready_results, ready_states);
738 ```
739
740 Because `a` is still readable this operation will fail with
741 `MOJO_RESULT_FAILED_PRECONDITION`. The input value of `num_ready_contexts`
742 informs `MojoArmWatcher` that it may store information regarding up to 4 watches
743 which currently prevent arming. In this case of course there is only one active
744 watch, so upon return we will see:
745
746 * `num_ready_contexts` is `1`.
747 * `ready_contexts[0]` is `1234`.
748 * `ready_results[0]` is `MOJO_RESULT_OK`
749 * `ready_states[0]` is the last known signaling state of handle `a`.
750
751 In other words the stored information mirrors what would have been the
752 notification handler's arguments if the watcher were allowed to arm and thus
753 notify immediately.
754
755 ### Cancelling a Watch
756
757 There are three ways a watch can be cancelled:
758
759 * The watched handle is closed
760 * The watcher handle is closed (in which case all of its watches are cancelled.)
761 * `MojoCancelWatch` is explicitly called for a given `context`.
762
763 In the above example this means any of the following operations will cancel the
764 watch on `a`:
765
766 ``` c
767 // Close the watched handle...
768 MojoClose(a);
769
770 // OR close the watcher handle...
771 MojoClose(w);
772
773 // OR explicitly cancel.
774 MojoResult result = MojoCancelWatch(w, 1234);
775 ```
776
777 In every case the watcher's notification handler is invoked for the cancelled
778 watch(es) regardless of whether or not the watcher is or was armed at the time.
779 The notification handler receives a `result` of `MOJO_RESULT_CANCELLED` for
780 these notifications, and this is guaranteed to be the final notification for any
781 given watch context.
782
783 ### Practical Watch Context Usage
784
785 It is common and probably wise to treat a watch's `context` value as an opaque
786 pointer to some thread-safe state associated in some way with the handle being
787 watched. Here's a small example which uses a single watcher to watch both ends
788 of a message pipe and accumulate a count of messages received at each end.
789
790 ``` c
791 // NOTE: For the sake of simplicity this example code is not in fact
792 // thread-safe. As long as there's only one thread running in the process and
793 // no external process connections, this is fine.
794
795 struct WatchedHandleState {
796 MojoHandle watcher;
797 MojoHandle handle;
798 int message_count;
799 };
800
801 void OnNotification(uintptr_t context,
802 MojoResult result,
803 MojoHandleSignalsState signals_state,
804 MojoWatcherNotificationFlags flags) {
805 struct WatchedHandleState* state = (struct WatchedHandleState*)(context);
806 MojoResult rv;
807
808 if (result == MOJO_RESULT_CANCELLED) {
809 // Cancellation is always the last notification and is guaranteed to
810 // eventually happen for every context, assuming no handles are leaked. We
811 // treat this as an opportunity to free the WatchedHandleState.
812 free(state);
813 return;
814 }
815
816 if (result == MOJO_RESULT_FAILED_PRECONDITION) {
817 // No longer readable, i.e. the other handle must have been closed. Better
818 // cancel. Note that we could also just call MojoClose(state->watcher) here
819 // since we know |context| is its only registered watch.
820 MojoCancelWatch(state->watcher, context);
821 return;
822 }
823
824 // This is the only handle watched by the watcher, so as long as we can't arm
825 // the watcher we know something's up with this handle. Try to read messages
826 // until we can successfully arm again or something goes terribly wrong.
827 while (MojoArmWatcher(state->watcher, NULL, NULL, NULL, NULL) ==
828 MOJO_RESULT_FAILED_PRECONDITION) {
829 rv = MojoReadMessageNew(state->handle, NULL, NULL, NULL,
830 MOJO_READ_MESSAGE_FLAG_MAY_DISCARD);
831 if (rv == MOJO_RESULT_OK) {
832 state->message_count++;
833 } else if (rv == MOJO_RESULT_FAILED_PRECONDITION) {
834 MojoCancelWatch(state->watcher, context);
835 return;
836 }
837 }
838 }
839
840 MojoHandle a, b;
841 MojoCreateMessagePipe(NULL, &a, &b);
842
843 MojoHandle a_watcher, b_watcher;
844 MojoCreateWatcher(&OnNotification, &a_watcher);
845 MojoCreateWatcher(&OnNotification, &b_watcher)
846
847 struct WatchedHandleState* a_state = malloc(sizeof(struct WatchedHandleState));
848 a_state->watcher = a_watcher;
849 a_state->handle = a;
850 a_state->message_count = 0;
851
852 struct WatchedHandleState* b_state = malloc(sizeof(struct WatchedHandleState));
853 b_state->watcher = b_watcher;
854 b_state->handle = b;
855 b_state->message_count = 0;
856
857 MojoWatch(a_watcher, a, MOJO_HANDLE_SIGNAL_READABLE, (uintptr_t)a_state);
858 MojoWatch(b_watcher, b, MOJO_HANDLE_SIGNAL_READABLE, (uintptr_t)b_state);
859
860 MojoArmWatcher(a_watcher, NULL, NULL, NULL, NULL);
861 MojoArmWatcher(b_watcher, NULL, NULL, NULL, NULL);
862 ```
863
864 Now any writes to `a` will increment `message_count` in `b_state`, and any
865 writes to `b` will increment `message_count` in `a_state`.
866
867 If either `a` or `b` is closed, both watches will be cancelled - one because
868 watch cancellation is implicit in handle closure, and the other because its
869 watcher will eventually detect that the handle is no longer readable.
OLDNEW
« ipc/README.md ('K') | « mojo/public/c/README.md ('k') | mojo/public/c/system/buffer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698