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