starnix_core/fs/fuchsia/
zxio.rs

1// Copyright 2023 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
5use crate::task::{
6    EventHandler, SignalHandler, SignalHandlerInner, WaitCanceler, Waiter, ZxioSignalHandler,
7};
8use starnix_uapi::error;
9use starnix_uapi::errors::Errno;
10use starnix_uapi::vfs::FdEvents;
11
12use syncio::{Zxio, ZxioSignals, zxio};
13
14fn get_zxio_signals_from_events(events: FdEvents) -> zxio::zxio_signals_t {
15    let mut signals = ZxioSignals::NONE;
16
17    if events.contains(FdEvents::POLLIN) {
18        signals |= ZxioSignals::READABLE;
19    }
20    if events.contains(FdEvents::POLLPRI) {
21        signals |= ZxioSignals::OUT_OF_BAND;
22    }
23    if events.contains(FdEvents::POLLOUT) {
24        signals |= ZxioSignals::WRITABLE;
25    }
26    if events.contains(FdEvents::POLLERR) {
27        signals |= ZxioSignals::ERROR;
28    }
29    if events.contains(FdEvents::POLLHUP) {
30        signals |= ZxioSignals::PEER_CLOSED;
31    }
32    if events.contains(FdEvents::POLLRDHUP) {
33        signals |= ZxioSignals::READ_DISABLED;
34    }
35
36    signals.bits()
37}
38
39fn get_events_from_zxio_signals(signals: zxio::zxio_signals_t) -> FdEvents {
40    let zxio_signals = ZxioSignals::from_bits_truncate(signals);
41
42    let mut events = FdEvents::empty();
43
44    if zxio_signals.contains(ZxioSignals::READABLE) {
45        events |= FdEvents::POLLIN;
46    }
47    if zxio_signals.contains(ZxioSignals::OUT_OF_BAND) {
48        events |= FdEvents::POLLPRI;
49    }
50    if zxio_signals.contains(ZxioSignals::WRITABLE) {
51        events |= FdEvents::POLLOUT;
52    }
53    if zxio_signals.contains(ZxioSignals::ERROR) {
54        events |= FdEvents::POLLERR;
55    }
56    if zxio_signals.contains(ZxioSignals::PEER_CLOSED) {
57        events |= FdEvents::POLLHUP;
58    }
59    if zxio_signals.contains(ZxioSignals::READ_DISABLED) {
60        events |= FdEvents::POLLRDHUP;
61    }
62
63    events
64}
65
66pub fn zxio_wait_async(
67    zxio: &Zxio,
68    waiter: &Waiter,
69    events: FdEvents,
70    event_handler: EventHandler,
71) -> WaitCanceler {
72    let (handle, signals) = zxio.wait_begin(get_zxio_signals_from_events(events));
73    if handle.is_invalid() {
74        let observed_zxio_signals = zxio.wait_end(zx::Signals::empty());
75        let observed_events = get_events_from_zxio_signals(observed_zxio_signals);
76        waiter.wake_immediately(observed_events, event_handler);
77        return WaitCanceler::new_noop();
78    }
79
80    let signal_handler = SignalHandler {
81        inner: SignalHandlerInner::Zxio(ZxioSignalHandler {
82            zxio: zxio.downgrade(),
83            get_events_from_zxio_signals,
84        }),
85        event_handler,
86        err_code: None,
87    };
88
89    // unwrap OK here as errors are only generated from misuse
90    WaitCanceler::new_zxio(
91        zxio.downgrade(),
92        waiter.wake_on_zircon_signals(&handle, signals, signal_handler).unwrap(),
93    )
94}
95
96pub fn zxio_query_events(zxio: &Zxio) -> Result<FdEvents, Errno> {
97    let (handle, signals) = zxio.wait_begin(ZxioSignals::all().bits());
98    let observed_signals = if handle.is_invalid() {
99        zx::Signals::empty()
100    } else {
101        match handle.wait(signals, zx::MonotonicInstant::INFINITE_PAST).to_result() {
102            Ok(signals) => signals,
103            Err(zx::Status::TIMED_OUT) => zx::Signals::empty(),
104            Err(e) => return error!(EIO, e),
105        }
106    };
107    let observed_zxio_signals = zxio.wait_end(observed_signals);
108    Ok(get_events_from_zxio_signals(observed_zxio_signals))
109}