blob: cbc5b60dd18955c6d1932084c8ffa4805448ac38 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <zircon/syscalls.h>
#include <zircon/syscalls/port.h>
#include <lib/fdio/unsafe.h>
#include <port/port.h>
#if TRACE_PORT_API
#define zprintf(fmt...) printf(fmt)
#else
#define zprintf(fmt...) do {} while (0)
#endif
zx_status_t port_init(port_t* port) {
zx_status_t r = zx_port_create(0, &port->handle);
zprintf("port_init(%p) port=%x\n", port, port->handle);
return r;
}
zx_status_t port_wait(port_t* port, port_handler_t* ph) {
zprintf("port_wait(%p, %p) obj=%x port=%x\n",
port, ph, ph->handle, port->handle);
return zx_object_wait_async(ph->handle, port->handle,
(uint64_t)(uintptr_t)ph,
ph->waitfor, ZX_WAIT_ASYNC_ONCE);
}
zx_status_t port_cancel(port_t* port, port_handler_t* ph) {
zx_status_t r = zx_port_cancel(port->handle, ph->handle,
(uint64_t)(uintptr_t)ph);
zprintf("port_cancel(%p, %p) obj=%x port=%x: r = %d\n",
port, ph, ph->handle, port->handle, r);
return r;
}
zx_status_t port_queue(port_t* port, port_handler_t* ph, uint32_t evt) {
zx_port_packet_t pkt;
pkt.key = (uintptr_t)ph;
pkt.user.u32[0] = evt;
zx_status_t r = zx_port_queue(port->handle, &pkt);
zprintf("port_queue(%p, %p) obj=%x port=%x evt=%x: r=%d\n",
port, ph, ph->handle, port->handle, r, evt);
return r;
}
zx_status_t port_dispatch(port_t* port, zx_time_t deadline, bool once) {
for (;;) {
zx_port_packet_t pkt;
zx_status_t r;
if ((r = zx_port_wait(port->handle, deadline, &pkt)) != ZX_OK) {
if (r != ZX_ERR_TIMED_OUT) {
printf("port_dispatch: port wait failed %d\n", r);
}
return r;
}
port_handler_t* ph = (void*) (uintptr_t) pkt.key;
if (pkt.type == ZX_PKT_TYPE_USER) {
zprintf("port_dispatch(%p) port=%x ph=%p func=%p: evt=%x\n",
port, port->handle, ph, ph->func, pkt.user.u32[0]);
ph->func(ph, 0, pkt.user.u32[0]);
} else {
zprintf("port_dispatch(%p) port=%x ph=%p func=%p: signals=%x\n",
port, port->handle, ph, ph->func, pkt.signal.observed);
if (ph->func(ph, pkt.signal.observed, 0) == ZX_OK) {
port_wait(port, ph);
}
}
if (once) {
return ZX_OK;
}
}
}
static zx_status_t port_fd_handler_func(port_handler_t* ph, zx_signals_t signals, uint32_t evt) {
port_fd_handler_t* fh = (void*) ph;
if (evt) {
return fh->func(fh, 0, evt);
} else {
uint32_t pollevt;
fdio_unsafe_wait_end(fh->fdio_context, signals, &pollevt);
return fh->func(fh, pollevt, 0);
}
}
zx_status_t port_fd_handler_init(port_fd_handler_t* fh, int fd, unsigned pollevt) {
fdio_t* io = fdio_unsafe_fd_to_io(fd);
if (io == NULL) {
return ZX_ERR_INVALID_ARGS;
}
fdio_unsafe_wait_begin(io, pollevt, &fh->ph.handle, &fh->ph.waitfor);
fh->ph.func = port_fd_handler_func;
fh->fdio_context = io;
return ZX_OK;
}
void port_fd_handler_done(port_fd_handler_t* fh) {
fdio_unsafe_release(fh->fdio_context);
fh->fdio_context = NULL;
fh->ph.handle = ZX_HANDLE_INVALID;
fh->ph.waitfor = 0;
}