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