• Home
Name Date Size #Lines LOC

..--

tests/03-May-2024-839594

BUILD.gnD03-May-2024638 3932

README.mdD03-May-202434.9 KiB931709

buffer.hD03-May-20249.5 KiB23972

core.hD03-May-2024869 2514

data_pipe.hD03-May-202418.2 KiB426109

functions.hD03-May-20242.9 KiB7820

invitation.hD03-May-202420.9 KiB457119

macros.hD03-May-20242.1 KiB5931

message_pipe.hD03-May-202425.5 KiB602163

platform_handle.hD03-May-202413.8 KiB32395

quota.hD03-May-20244.7 KiB12744

system_export.hD03-May-2024812 3420

thunks.ccD03-May-202418.9 KiB487400

thunks.hD03-May-202410.1 KiB233186

trap.hD03-May-202413.1 KiB323107

types.hD03-May-202410.4 KiB22896

README.md

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