# zx_port_wait

## Summary

Wait for a packet arrival in a port.

## Declaration

    #include <zircon/syscalls.h>
    #include <zircon/syscalls/port.h>

    zx_status_t zx_port_wait(zx_handle_t handle,
                             zx_instant_mono_t deadline,
                             zx_port_packet_t* packet);

## Description

`zx_port_wait()` is a blocking syscall, which causes the caller to wait until at least
one packet is available.

Upon return, if successful *packet* will contain the earliest (in FIFO order)
available packet data.

The *deadline* indicates when to stop waiting for a packet (with respect to
`ZX_CLOCK_MONOTONIC`) and will be automatically adjusted according to the job's
[timer slack](https://fuchsia.dev/docs/concepts/kernel/timer_slack) policy. If no packet has arrived by the deadline,
`ZX_ERR_TIMED_OUT` is returned. The value `ZX_TIME_INFINITE` will result in
waiting forever. A value in the past will result in an immediate timeout,
unless a packet is already available for reading.

Unlike [`zx_object_wait_one()`](https://fuchsia.dev/reference/syscalls/object_wait_one) and [`zx_object_wait_many()`](https://fuchsia.dev/reference/syscalls/object_wait_many) only one
waiting thread is released (per available packet), which makes ports
amenable to be serviced by thread pools.

There are two classes of packets: packets queued by userspace with [`zx_port_queue()`](https://fuchsia.dev/reference/syscalls/port_queue)
and packets queued by the kernel when objects a port is registered with change state. In both
cases the packet is always of type `zx_port_packet_t`:

    struct zx_port_packet_t {
        uint64_t key;
        uint32_t type;
        zx_status_t status;
        union {
            zx_packet_user_t user;
            zx_packet_signal_t signal;
            zx_packet_guest_bell_t guest_bell;
            zx_packet_guest_mem_t guest_mem;
            zx_packet_guest_io_t guest_io;
            zx_packet_guest_vcpu_t guest_vcpu;
            zx_packet_interrupt_t interrupt;
            zx_packet_page_request_t page_request;
        };
    };

In the case of packets generated via [`zx_port_queue()`](https://fuchsia.dev/reference/syscalls/port_queue), *type* will be set to
`ZX_PKT_TYPE_USER`, and the caller of [`zx_port_queue()`](https://fuchsia.dev/reference/syscalls/port_queue) controls all other values in the
`zx_port_packet_t` structure. Access to the packet data is provided by the *user* member, with
type `zx_packet_user_t`:

    typedef union zx_packet_user {
        uint64_t u64[4];
        uint32_t u32[8];
        uint16_t u16[16];
        uint8_t   c8[32];
    } zx_packet_user_t;

For packets generated by the kernel, type can be one of the following values:

`ZX_PKT_TYPE_SIGNAL_ONE` - generated by objects registered via
[`zx_object_wait_async()`](https://fuchsia.dev/reference/syscalls/object_wait_async).

`ZX_PKT_TYPE_GUEST_BELL`, `ZX_PKT_TYPE_GUEST_MEM`, `ZX_PKT_TYPE_GUEST_IO`,
or `ZX_PKT_TYPE_GUEST_VCPU` - generated by objects registered via [`zx_guest_set_trap()`](https://fuchsia.dev/reference/syscalls/guest_set_trap).

`ZX_PKT_TYPE_INTERRUPT` - generated by objects registered via [`zx_interrupt_bind()`](https://fuchsia.dev/reference/syscalls/interrupt_bind).

`ZX_PKT_TYPE_PAGE_REQUEST` - generated by objects registered via [`zx_pager_create_vmo()`](https://fuchsia.dev/reference/syscalls/pager_create_vmo).

All kernel queued packets will have *status* set to `ZX_OK` and *key* set to the
value provided to the registration syscall. For details on how to interpret the union, see
the corresponding registration syscall.

## Rights

*handle* must be of type `ZX_OBJ_TYPE_PORT` and have `ZX_RIGHT_READ`.

## Return value

`zx_port_wait()` returns `ZX_OK` on successful packet dequeuing.

## Errors

`ZX_ERR_BAD_HANDLE` *handle* is not a valid handle.

`ZX_ERR_INVALID_ARGS` *packet* isn't a valid pointer

`ZX_ERR_ACCESS_DENIED` *handle* does not have `ZX_RIGHT_READ` and may
not be waited upon.

`ZX_ERR_TIMED_OUT` *deadline* passed and no packet was available.

## See also

- [timer slack](https://fuchsia.dev/docs/concepts/kernel/timer_slack)
- [`zx_object_wait_async()`](https://fuchsia.dev/reference/syscalls/object_wait_async)
- [`zx_port_create()`](https://fuchsia.dev/reference/syscalls/port_create)
- [`zx_port_queue()`](https://fuchsia.dev/reference/syscalls/port_queue)