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