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