mirror of
https://github.com/joleuger/vuinputd.git
synced 2026-07-17 16:36:03 +00:00
poll: First alpha implementation
This commit is contained in:
parent
8d4a0c9413
commit
5cffaec3da
5 changed files with 53 additions and 29 deletions
|
|
@ -18,7 +18,7 @@ use anyhow::Context;
|
|||
use cuse_lowlevel::fuse_lowlevel;
|
||||
use nix::sys::epoll::{Epoll, EpollCreateFlags, EpollEvent, EpollFlags};
|
||||
|
||||
use crate::cuse_device::state::{get_vuinput_state, VuFileHandle};
|
||||
use crate::cuse_device::state::{get_vuinput_state, PollPhase, VuFileHandle};
|
||||
|
||||
pub static EVDEV_WRITE_WATCHER: OnceLock<Mutex<EvdevWriteWatcher>> = OnceLock::new();
|
||||
|
||||
|
|
@ -113,7 +113,7 @@ fn evdev_write_watch_loop(shutdown: Arc<AtomicBool>, epoll: Arc<Epoll>) {
|
|||
fuse_lowlevel::fuse_pollhandle_destroy(handle.as_ptr());
|
||||
}
|
||||
}
|
||||
state.poll.readable = true;
|
||||
state.poll.pollphase = PollPhase::Readable;
|
||||
state.poll.pending.clear();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ pub fn vuinput_make_cuse_ops() -> cuse_lowlevel::cuse_lowlevel_ops {
|
|||
release: Some(vuinput_release::vuinput_release),
|
||||
fsync: None,
|
||||
ioctl: Some(vuinput_ioctl::vuinput_ioctl),
|
||||
//poll: Some(vuinput_poll::vuinput_poll),
|
||||
poll: None,
|
||||
poll: Some(vuinput_poll::vuinput_poll),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,24 @@ impl KeyTracker {
|
|||
}
|
||||
}
|
||||
|
||||
/// EMPTY -> READY -> READING -> { EMPTY | READY }
|
||||
/// EMPTY -> READABLE (new data arrives / watcher can observe)
|
||||
/// READABLE -> READING (read callback starts draining)
|
||||
/// READING -> EMPTY (read drained everything)
|
||||
/// READING -> READABLE (read finished, but more data still remains)
|
||||
#[derive(Debug)]
|
||||
pub enum PollPhase {
|
||||
Empty,
|
||||
Readable,
|
||||
Reading,
|
||||
}
|
||||
|
||||
impl Default for PollPhase {
|
||||
fn default() -> Self {
|
||||
Self::Empty
|
||||
}
|
||||
}
|
||||
|
||||
/// this data structure ensures poll and read are synchronized.
|
||||
/// poll() and read() must synchronize through one shared readines
|
||||
/// state, and the state transitions must be done under the same per-handle mutex.
|
||||
|
|
@ -55,7 +73,7 @@ impl KeyTracker {
|
|||
pub struct PollState {
|
||||
/// Sticky readiness latch:
|
||||
/// true once evdev became readable, false again after read/drain.
|
||||
pub readable: bool,
|
||||
pub pollphase: PollPhase,
|
||||
|
||||
/// Pending FUSE poll waiters for this device.
|
||||
/// Optimized for the common case of 0 or 1 waiter, but supports
|
||||
|
|
@ -66,7 +84,7 @@ pub struct PollState {
|
|||
impl PollState {
|
||||
pub fn new() -> PollState {
|
||||
PollState {
|
||||
readable: false,
|
||||
pollphase: PollPhase::Empty,
|
||||
pending: smallvec![],
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ use log::{debug, trace};
|
|||
use std::io::{Read, Write};
|
||||
use std::os::fd::AsRawFd;
|
||||
use std::os::raw::c_char;
|
||||
use std::ptr::NonNull;
|
||||
use uinput_ioctls::*;
|
||||
|
||||
// https://github.com/libfuse/libfuse/blob/master/example/poll.c
|
||||
|
|
@ -20,14 +21,22 @@ pub unsafe extern "C" fn vuinput_poll(
|
|||
fi: *mut fuse_lowlevel::fuse_file_info,
|
||||
ph: *mut fuse_lowlevel::fuse_pollhandle,
|
||||
) {
|
||||
let vuinput_state_mutex =
|
||||
get_vuinput_state(&VuFileHandle::from_fuse_file_info(fi.as_ref().unwrap())).unwrap();
|
||||
let mut vuinput_state = vuinput_state_mutex.lock().unwrap();
|
||||
|
||||
/*
|
||||
let vuinput_state_mutex =
|
||||
get_vuinput_state(&VuFileHandle::from_fuse_file_info(fi.as_ref().unwrap())).unwrap();
|
||||
let mut vuinput_state = vuinput_state_mutex.lock().unwrap();
|
||||
|
||||
if state.poll.readable {
|
||||
// return POLLIN immediately
|
||||
} else if let Some(handle) = NonNull::new(ph) {
|
||||
state.poll.add_waiter(handle); */
|
||||
match vuinput_state.poll.pollphase {
|
||||
PollPhase::Empty => {
|
||||
let ph = NonNull::<fuse_lowlevel::fuse_pollhandle>::new(ph);
|
||||
vuinput_state.poll.add_waiter(ph.unwrap());
|
||||
}
|
||||
PollPhase::Readable => {
|
||||
fuse_lowlevel::fuse_lowlevel_notify_poll(ph);
|
||||
fuse_lowlevel::fuse_pollhandle_destroy(ph);
|
||||
}
|
||||
PollPhase::Reading => {
|
||||
fuse_lowlevel::fuse_lowlevel_notify_poll(ph);
|
||||
fuse_lowlevel::fuse_pollhandle_destroy(ph);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,15 +3,12 @@
|
|||
// Author: Johannes Leupolz <dev@leupolz.eu>
|
||||
|
||||
use crate::cuse_device::*;
|
||||
use crate::global_config::get_device_policy;
|
||||
use ::cuse_lowlevel::*;
|
||||
use libc::{__s32, __u16, input_event};
|
||||
use libc::{__s32, __u16, input_event, EAGAIN};
|
||||
use libc::{off_t, size_t, EIO};
|
||||
use libc::{uinput_abs_setup, uinput_setup};
|
||||
use log::{debug, trace};
|
||||
use std::io::{Read, Write};
|
||||
use std::os::fd::AsRawFd;
|
||||
use std::os::raw::c_char;
|
||||
use uinput_ioctls::*;
|
||||
|
||||
// TODO: compat-mode+ ensure sizeof(struct input_event)
|
||||
|
|
@ -38,12 +35,12 @@ pub unsafe extern "C" fn vuinput_read(
|
|||
|
||||
let mut buffer: [u8; 24] = [0; 24];
|
||||
|
||||
vuinput_state.poll.pollphase = PollPhase::Reading;
|
||||
// read up to 24 bytes
|
||||
// todo: non-blocking or timeout
|
||||
let result = vuinput_state.file.read(&mut buffer);
|
||||
match result {
|
||||
Ok(NORMAL_SIZE) => {
|
||||
if (!is_compat) {
|
||||
if !is_compat {
|
||||
let buffer = buffer.as_ptr() as *const i8;
|
||||
fuse_lowlevel::fuse_reply_buf(_req, buffer, 24);
|
||||
} else {
|
||||
|
|
@ -56,18 +53,19 @@ pub unsafe extern "C" fn vuinput_read(
|
|||
}
|
||||
}
|
||||
Err(e) => {
|
||||
debug!("fh {}: error reading from uinput: {e:?}", fh);
|
||||
fuse_lowlevel::fuse_reply_err(_req, EIO);
|
||||
if e.kind() == io::ErrorKind::WouldBlock {
|
||||
// EAGAIN / EWOULDBLOCK
|
||||
//println!("Received EAGAIN: The read would block!");
|
||||
vuinput_state.poll.pollphase = PollPhase::Empty;
|
||||
fuse_lowlevel::fuse_reply_err(_req, EAGAIN);
|
||||
} else {
|
||||
debug!("fh {}: error reading from uinput: {e:?}", fh);
|
||||
fuse_lowlevel::fuse_reply_err(_req, EIO);
|
||||
}
|
||||
}
|
||||
Ok(_) => {
|
||||
debug!("fh {}: error reading from uinput: wrong size", fh);
|
||||
fuse_lowlevel::fuse_reply_err(_req, EIO);
|
||||
}
|
||||
}
|
||||
/*
|
||||
if drained_to_eagain {
|
||||
state.poll.readable = false;
|
||||
} else {
|
||||
state.poll.readable = true;
|
||||
} */
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue