1// Copyright 2017 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <stdio.h>
6#include <stdlib.h>
7#include <string.h>
8#include <unistd.h>
9
10#include <zircon/syscalls.h>
11#include <zircon/syscalls/port.h>
12
13#include <lib/fdio/private.h>
14
15#include <port/port.h>
16
17#if TRACE_PORT_API
18#define zprintf(fmt...) printf(fmt)
19#else
20#define zprintf(fmt...) do {} while (0)
21#endif
22
23zx_status_t port_init(port_t* port) {
24    zx_status_t r = zx_port_create(0, &port->handle);
25    zprintf("port_init(%p) port=%x\n", port, port->handle);
26    return r;
27}
28
29zx_status_t port_wait(port_t* port, port_handler_t* ph) {
30    zprintf("port_wait(%p, %p) obj=%x port=%x\n",
31            port, ph, ph->handle, port->handle);
32    return zx_object_wait_async(ph->handle, port->handle,
33                                (uint64_t)(uintptr_t)ph,
34                                ph->waitfor, ZX_WAIT_ASYNC_ONCE);
35}
36
37zx_status_t port_wait_repeating(port_t* port, port_handler_t* ph) {
38    zprintf("port_wait_repeating(%p, %p) obj=%x port=%x\n",
39            port, ph, ph->handle, port->handle);
40    return zx_object_wait_async(ph->handle, port->handle,
41                                (uint64_t)(uintptr_t)ph,
42                                ph->waitfor, ZX_WAIT_ASYNC_REPEATING);
43}
44
45
46zx_status_t port_cancel(port_t* port, port_handler_t* ph) {
47    zx_status_t r = zx_port_cancel(port->handle, ph->handle,
48                                   (uint64_t)(uintptr_t)ph);
49    zprintf("port_cancel(%p, %p) obj=%x port=%x: r = %d\n",
50            port, ph, ph->handle, port->handle, r);
51    return r;
52}
53
54zx_status_t port_queue(port_t* port, port_handler_t* ph, uint32_t evt) {
55    zx_port_packet_t pkt;
56    pkt.key = (uintptr_t)ph;
57    pkt.user.u32[0] = evt;
58    zx_status_t r = zx_port_queue(port->handle, &pkt);
59    zprintf("port_queue(%p, %p) obj=%x port=%x evt=%x: r=%d\n",
60            port, ph, ph->handle, port->handle, r, evt);
61    return r;
62}
63
64zx_status_t port_dispatch(port_t* port, zx_time_t deadline, bool once) {
65    for (;;) {
66        zx_port_packet_t pkt;
67        zx_status_t r;
68        if ((r = zx_port_wait(port->handle, deadline, &pkt)) != ZX_OK) {
69            if (r != ZX_ERR_TIMED_OUT) {
70                printf("port_dispatch: port wait failed %d\n", r);
71            }
72            return r;
73        }
74        port_handler_t* ph = (void*) (uintptr_t) pkt.key;
75        if (pkt.type == ZX_PKT_TYPE_USER) {
76            zprintf("port_dispatch(%p) port=%x ph=%p func=%p: evt=%x\n",
77                    port, port->handle, ph, ph->func, pkt.user.u32[0]);
78            ph->func(ph, 0, pkt.user.u32[0]);
79        } else {
80            zprintf("port_dispatch(%p) port=%x ph=%p func=%p: signals=%x\n",
81                    port, port->handle, ph, ph->func, pkt.signal.observed);
82            if (ph->func(ph, pkt.signal.observed, 0) == ZX_OK) {
83                port_wait(port, ph);
84            }
85        }
86        if (once) {
87            return ZX_OK;
88        }
89    }
90}
91
92static zx_status_t port_fd_handler_func(port_handler_t* ph, zx_signals_t signals, uint32_t evt) {
93    port_fd_handler_t* fh = (void*) ph;
94
95    if (evt) {
96        return fh->func(fh, 0, evt);
97    } else {
98        uint32_t pollevt;
99        __fdio_wait_end(fh->fdio_context, signals, &pollevt);
100        return fh->func(fh, pollevt, 0);
101    }
102}
103
104zx_status_t port_fd_handler_init(port_fd_handler_t* fh, int fd, unsigned pollevt) {
105    fdio_t* io = __fdio_fd_to_io(fd);
106    if (io == NULL) {
107        return ZX_ERR_INVALID_ARGS;
108    }
109    __fdio_wait_begin(io, pollevt, &fh->ph.handle, &fh->ph.waitfor);
110    fh->ph.func = port_fd_handler_func;
111    fh->fdio_context = io;
112    return ZX_OK;
113}
114
115void port_fd_handler_done(port_fd_handler_t* fh) {
116    __fdio_release(fh->fdio_context);
117    fh->fdio_context = NULL;
118    fh->ph.handle = ZX_HANDLE_INVALID;
119    fh->ph.waitfor = 0;
120}
121