blob: 2be3d45d5c90753e13b9b0234e66f3915ff1f24a [file] [log] [blame] [view]
# zx_channel_call
## SUMMARY
<!-- Contents of this heading updated by update-docs-from-fidl, do not edit. -->
Send a message to a channel and await a reply.
## DECLARATION
<!-- Contents of this heading updated by update-docs-from-fidl, do not edit. -->
```c
#include <zircon/syscalls.h>
zx_status_t zx_channel_call(zx_handle_t handle,
uint32_t options,
zx_time_t deadline,
const zx_channel_call_args_t* args,
uint32_t* actual_bytes,
uint32_t* actual_handles);
```
## DESCRIPTION
`zx_channel_call()` is like a combined [`zx_channel_write()`], [`zx_object_wait_one()`],
and [`zx_channel_read()`], with the addition of a feature where a transaction id at
the front of the message payload *bytes* is used to match reply messages with send
messages, enabling multiple calling threads to share a channel without any additional
userspace bookkeeping.
The write and read phases of this operation behave like [`zx_channel_write()`] and
[`zx_channel_read()`] with the difference that their parameters are provided via the
`zx_channel_call_args_t` structure.
The first four bytes of the written and read back messages are treated as a
transaction ID of type `zx_txid_t`. The kernel generates a txid for the
written message, replacing that part of the message as read from userspace.
The kernel generated txid will be between 0x80000000 and 0xFFFFFFFF, and will
not collide with any txid from any other `zx_channel_call()` in progress against
this channel endpoint. If the written message has a length of fewer than four
bytes, an error is reported.
When the outbound message is written, simultaneously an interest is registered
for inbound messages of the matching txid.
*deadline* may be automatically adjusted according to the job's [timer slack]
policy.
While the slack-adjusted *deadline* has not passed, if an inbound message
arrives with a matching txid, instead of being added to the tail of the general
inbound message queue, it is delivered directly to the thread waiting in
`zx_channel_call()`.
If such a reply arrives after the slack-adjusted *deadline* has passed, it will
arrive in the general inbound message queue, cause **ZX_CHANNEL_READABLE** to be
signaled, etc.
Inbound messages that are too large to fit in *rd_num_bytes* and *rd_num_handles*
are discarded and **ZX_ERR_BUFFER_TOO_SMALL** is returned in that case.
As with [`zx_channel_write()`], the handles in *handles* are always consumed by
`zx_channel_call()` and no longer exist in the calling process.
### ZX_CHANNEL_WRITE_USE_IOVEC option
When the **ZX_CHANNEL_WRITE_USE_IOVEC** option is specified, `wr_bytes` is
interpreted as an array of `zx_channel_iovec_t`, specifying slices of bytes to
sequentially copy to the message in order. `num_wr_bytes` specifies the number
of `zx_channel_iovec_t` array elements in `wr_bytes`.
```c
typedef struct zx_channel_iovec {
const void* buffer; // User-space bytes.
uint32_t capacity; // Number of bytes.
uint32_t reserved; // Reserved.
} zx_channel_iovec_t;
```
There can be at most **ZX_CHANNEL_MAX_MSG_IOVEC** or `8192`
`zx_channel_iovec_t` elements of the `wr_bytes` array with the sum of
`capacity` across all `zx_channel_iovec_t` not exceeding
**ZX_CHANNEL_MAX_MSG_BYTES** or `65536` bytes. `buffer` need not be aligned and
it may only be `NULL` if `capacity` is zero. `reserved` must be set to zero.
Either all `zx_channel_iovec_t` are copied and the message is sent, or none
are copied and the message is not sent. Usage for sending handles is unchanged.
## RIGHTS
<!-- Contents of this heading updated by update-docs-from-fidl, do not edit. -->
*handle* must be of type **ZX_OBJ_TYPE_CHANNEL** and have **ZX_RIGHT_READ** and have **ZX_RIGHT_WRITE**.
All wr_handles of *args* must have **ZX_RIGHT_TRANSFER**.
## RETURN VALUE
`zx_channel_call()` returns **ZX_OK** on success and the number of bytes and
count of handles in the reply message are returned via *actual_bytes* and
*actual_handles*, respectively.
## ERRORS
**ZX_ERR_BAD_HANDLE** *handle* is not a valid handle, any element in
*handles* is not a valid handle, or there are duplicates among the handles
in the *handles* array.
**ZX_ERR_WRONG_TYPE** *handle* is not a channel handle.
**ZX_ERR_INVALID_ARGS** any of the provided pointers are invalid or null,
or *wr_num_bytes* is less than four, or *options* is nonzero.
If the **ZX_CHANNEL_WRITE_USE_IOVEC** option is specified,
**ZX_ERR_INVALID_ARGS** will be produced if the *buffer* field contains an
invalid pointer or if the reserved field is non-zero.
**ZX_ERR_ACCESS_DENIED** *handle* does not have **ZX_RIGHT_WRITE** or
any element in *handles* does not have **ZX_RIGHT_TRANSFER**.
**ZX_ERR_PEER_CLOSED** The other side of the channel was closed or became
closed while waiting for the reply.
**ZX_ERR_CANCELED** *handle* was closed while waiting for a reply. TODO(fxbug.dev/34013):
Transferring a channel with pending calls currently leads to undefined behavior. With
the current implementation, transferring such a channel does not interrupt the
pending calls, as it does not close the underlying channel endpoint. Programs should
be aware of this behavior, but they **must not** rely on it.
**ZX_ERR_NO_MEMORY** Failure due to lack of memory.
There is no good way for userspace to handle this (unlikely) error.
In a future build this error will no longer occur.
**ZX_ERR_OUT_OF_RANGE** *wr_num_bytes* or *wr_num_handles* are larger than the
largest allowable size for channel messages.
If the **ZX_CHANNEL_WRITE_USE_IOVEC** option is specified,
**ZX_ERR_OUT_OF_RANGE** will be produced if *num_bytes* is larger than
**ZX_CHANNEL_MAX_MSG_IOVEC** or the sum of the iovec capacities exceeds
**ZX_CHANNEL_MAX_MSG_BYTES**.
**ZX_ERR_BUFFER_TOO_SMALL** *rd_num_bytes* or *rd_num_handles* are too small
to contain the reply message.
**ZX_ERR_NOT_SUPPORTED** one of the handles in *handles* was *handle*
(the handle to the channel being written to).
## NOTES
The facilities provided by `zx_channel_call()` can interoperate with message dispatchers
using [`zx_channel_read()`] and [`zx_channel_write()`] directly, provided the following rules
are observed:
1. A server receiving synchronous messages via [`zx_channel_read()`] should ensure that the
txid of incoming messages is reflected back in outgoing responses via [`zx_channel_write()`]
so that clients using `zx_channel_call()` can correctly route the replies.
2. A client sending messages via [`zx_channel_write()`] that will be replied to should ensure
that it uses txids between 0 and 0x7FFFFFFF only, to avoid colliding with other threads
communicating via `zx_channel_call()`.
If a `zx_channel_call()` returns due to **ZX_ERR_TIMED_OUT**, if the server eventually replies,
at some point in the future, the reply *could* match another outbound request (provided about
2^31 `zx_channel_call()`s have happened since the original request. This syscall is designed
around the expectation that timeouts are generally fatal and clients do not expect to continue
communications on a channel that is timing out.
## SEE ALSO
- [timer slack]
- [`zx_channel_create()`]
- [`zx_channel_read()`]
- [`zx_channel_write()`]
- [`zx_handle_close()`]
- [`zx_handle_duplicate()`]
- [`zx_handle_replace()`]
- [`zx_object_wait_async()`]
- [`zx_object_wait_many()`]
- [`zx_object_wait_one()`]
<!-- References updated by update-docs-from-fidl, do not edit. -->
[timer slack]: /docs/concepts/kernel/timer_slack.md
[`zx_channel_create()`]: channel_create.md
[`zx_channel_read()`]: channel_read.md
[`zx_channel_write()`]: channel_write.md
[`zx_handle_close()`]: handle_close.md
[`zx_handle_duplicate()`]: handle_duplicate.md
[`zx_handle_replace()`]: handle_replace.md
[`zx_object_wait_async()`]: object_wait_async.md
[`zx_object_wait_many()`]: object_wait_many.md
[`zx_object_wait_one()`]: object_wait_one.md