Subscribe for signals on an object.


#include <zircon/syscalls.h>

zx_status_t zx_object_wait_async(zx_handle_t handle,
                                 zx_handle_t port,
                                 uint64_t key,
                                 zx_signals_t signals,
                                 uint32_t options);


zx_object_wait_async() is a non-blocking syscall that causes packets to be enqueued on port when the object specified by handle has one or more of the specified signals asserted. Use zx_port_wait() to retrieve the packets.

handle points to the object that is to be watched for changes and must be a waitable object.

The options argument can be 0 or it can be one or more of

  • ZX_WAIT_ASYNC_TIMESTAMP which causes the system to capture a timestamp when the wait triggered.
  • ZX_WAIT_ASYNC_EDGE causes the port to not enqueue a packet for signals active at the time of the zx_object_wait_async() call.

The signals argument is a bitmask indicating which signals on the object specified by handle will cause a packet to be enqueued.

Without ZX_WAIT_ASYNC_EDGE, if any of the signals in signals are active when zx_object_wait_async() is called or become active afterwards, a packet will be enqueued on port.

With ZX_WAIT_ASYNC_EDGE, a packet will be enqueued on port only after one or more signals in signals have transitioned from inactive to active. When using this option, care should be taken that an inactive signal becomes unexpectedly active before the call zx_object_wait_async() has completed. In such cases the transition can be missed and no packet will ever be queued to the port. For example, this is often used before performing non-blocking I/O until the signal becomes inactive, ensuring that a subsequent transition from inactive to active will cause a packet to be queued.

When a packet is enqueued, it will contain all of the currently-asserted signals (not just the ones listed in the signals argument). Once a packet has been enqueued the asynchronous waiting ends. No further packets will be enqueued. Note that signals are OR'd into the state maintained by the port thus you may see any combination of requested signals when zx_port_wait() returns.

Each call to zx_object_wait_async() creates a new asynchronous wait operation, or observer. These operations are not deduplicated in any way. That is, if zx_object_wait_async() is called twice with the same arguments, two operations will be created. And if an asserted signal matches those operations, two packets will be enqueued, one for each operation.

There is a limit to the number of operations each port may have. When the limit is exceeded, a job policy exception (ZX_EXCP_POLICY_CODE_PORT_TOO_MANY_OBSERVERS) is raised by the process that crossed the limit.

zx_port_cancel() will terminate all asynchronous wait operations with handle and port that have the specified key. In addition, any packets in the queue generated by those operations will be removed from the queue.

If handle is closed, the operations associated with it will also be terminated, but packets already in the queue are not affected.

Packets generated via this syscall will have type set to ZX_PKT_TYPE_SIGNAL_ONE and the union is of type zx_packet_signal_t:

typedef struct zx_packet_signal {
    zx_signals_t trigger;
    zx_signals_t observed;
    uint64_t count;
    zx_time_t timestamp;       // depends on ZX_WAIT_ASYNC_TIMESTAMP
    uint64_t reserved1;
} zx_packet_signal_t;

trigger is the signals used in the call to zx_object_wait_async(), observed is the signals actually observed, and timestamp is clock-monotonic time when the object state transitioned to meet the trigger condition. If options does not include ZX_WAIT_ASYNC_TIMESTAMP the timestamp is reported as 0.

Use the zx_port_packet_t's key member to track what object this packet corresponds.


handle must have ZX_RIGHT_WAIT.

port must be of type ZX_OBJ_TYPE_PORT and have ZX_RIGHT_WRITE.

Return value

zx_object_wait_async() returns ZX_OK if the subscription succeeded.



ZX_ERR_BAD_HANDLE handle is not a valid handle or port is not a valid handle.

ZX_ERR_WRONG_TYPE port is not a Port handle.

ZX_ERR_ACCESS_DENIED handle does not have ZX_RIGHT_WAIT or port does not have ZX_RIGHT_WRITE.

ZX_ERR_NOT_SUPPORTED handle is a handle that cannot be waited on.

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.


See signals for more information about signals and their terminology.

See also