mirror of
https://github.com/joleuger/vuinputd.git
synced 2026-07-17 16:36:03 +00:00
Fix for poll and read.
This commit is contained in:
parent
080a72906d
commit
9e55cd84ab
4 changed files with 73 additions and 29 deletions
|
|
@ -106,15 +106,11 @@ fn evdev_write_watch_loop(shutdown: Arc<AtomicBool>, epoll: Arc<Epoll>) {
|
|||
let state = super::state::get_vuinput_state(&fh);
|
||||
if let Ok(state) = state {
|
||||
let mut state = state.lock().unwrap();
|
||||
|
||||
for handle in state.poll.take_waiters() {
|
||||
unsafe {
|
||||
fuse_lowlevel::fuse_lowlevel_notify_poll(handle.as_ptr());
|
||||
fuse_lowlevel::fuse_pollhandle_destroy(handle.as_ptr());
|
||||
}
|
||||
let handle = state.poll.take_waiters();
|
||||
if let Some(mut handle)= handle {
|
||||
handle.notify();
|
||||
}
|
||||
state.poll.pollphase = PollPhase::Readable;
|
||||
state.poll.pending.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ use ::cuse_lowlevel::*;
|
|||
use smallvec::SmallVec;
|
||||
|
||||
use crate::process_tools::RequestingProcess;
|
||||
use smallvec::smallvec;
|
||||
|
||||
pub type PendingPollHandles = SmallVec<[*mut fuse_lowlevel::fuse_pollhandle; 1]>;
|
||||
|
||||
|
|
@ -61,6 +60,43 @@ impl Default for PollPhase {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PollHandle {
|
||||
ptr: NonNull<fuse_lowlevel::fuse_pollhandle>,
|
||||
has_been_completed: bool,
|
||||
}
|
||||
|
||||
impl PollHandle {
|
||||
pub fn new(ptr: NonNull<fuse_lowlevel::fuse_pollhandle>) -> Self {
|
||||
Self {
|
||||
ptr: ptr,
|
||||
has_been_completed: false,
|
||||
}
|
||||
}
|
||||
pub fn notify(&mut self) {
|
||||
if !self.has_been_completed {
|
||||
unsafe {
|
||||
fuse_lowlevel::fuse_lowlevel_notify_poll(self.ptr.as_ptr());
|
||||
fuse_lowlevel::fuse_pollhandle_destroy(self.ptr.as_ptr());
|
||||
}
|
||||
self.has_been_completed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for PollHandle {
|
||||
fn drop(&mut self) {
|
||||
if !self.has_been_completed {
|
||||
unsafe {
|
||||
fuse_lowlevel::fuse_pollhandle_destroy(self.ptr.as_ptr());
|
||||
}
|
||||
self.has_been_completed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for PollHandle {}
|
||||
|
||||
/// 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.
|
||||
|
|
@ -78,31 +114,29 @@ pub struct PollState {
|
|||
/// Pending FUSE poll waiters for this device.
|
||||
/// Optimized for the common case of 0 or 1 waiter, but supports
|
||||
/// multiple concurrent poll() callers correctly.
|
||||
pub pending: SmallVec<[NonNull<fuse_lowlevel::fuse_pollhandle>; 1]>,
|
||||
pending: Option<PollHandle>,
|
||||
}
|
||||
|
||||
impl PollState {
|
||||
pub fn new() -> PollState {
|
||||
PollState {
|
||||
pollphase: PollPhase::Empty,
|
||||
pending: smallvec![],
|
||||
pending: None,
|
||||
}
|
||||
}
|
||||
pub fn has_waiters(&self) -> bool {
|
||||
!self.pending.is_empty()
|
||||
!self.pending.is_some()
|
||||
}
|
||||
|
||||
pub fn add_waiter(&mut self, handle: NonNull<fuse_lowlevel::fuse_pollhandle>) {
|
||||
self.pending.push(handle);
|
||||
pub fn set_waiter(&mut self, handle: NonNull<fuse_lowlevel::fuse_pollhandle>) {
|
||||
self.pending = Some(PollHandle::new(handle));
|
||||
}
|
||||
|
||||
pub fn take_waiters(&mut self) -> SmallVec<[NonNull<fuse_lowlevel::fuse_pollhandle>; 1]> {
|
||||
pub fn take_waiters(&mut self) -> Option<PollHandle> {
|
||||
std::mem::take(&mut self.pending)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for PollState {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct VuInputState {
|
||||
pub file: File,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
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, POLLIN};
|
||||
use libc::{off_t, size_t, EIO};
|
||||
use libc::{uinput_abs_setup, uinput_setup};
|
||||
use log::{debug, trace};
|
||||
|
|
@ -16,13 +16,18 @@ use std::ptr::NonNull;
|
|||
use uinput_ioctls::*;
|
||||
|
||||
// https://github.com/libfuse/libfuse/blob/master/example/poll.c
|
||||
// https://github.com/torvalds/linux/blob/f82b61de0f5dc58930fdb773b9e843573fcc374b/fs/fuse/file.c
|
||||
|
||||
// Note that poll in fuse blocks (because it calls fuse_simple_request, which is designed to block)
|
||||
// until the handle is notified.
|
||||
|
||||
pub unsafe extern "C" fn vuinput_poll(
|
||||
req: fuse_lowlevel::fuse_req_t,
|
||||
fi: *mut fuse_lowlevel::fuse_file_info,
|
||||
ph: *mut fuse_lowlevel::fuse_pollhandle,
|
||||
) {
|
||||
fuse_lowlevel::fuse_reply_err(req, EIO);
|
||||
return;
|
||||
//fuse_lowlevel::fuse_reply_err(req, EIO);
|
||||
//return;
|
||||
|
||||
let vuinput_state_mutex =
|
||||
get_vuinput_state(&VuFileHandle::from_fuse_file_info(fi.as_ref().unwrap())).unwrap();
|
||||
|
|
@ -32,16 +37,25 @@ pub unsafe extern "C" fn vuinput_poll(
|
|||
|
||||
match vuinput_state.poll.pollphase {
|
||||
PollPhase::Empty => {
|
||||
let ph = NonNull::<fuse_lowlevel::fuse_pollhandle>::new(ph);
|
||||
vuinput_state.poll.add_waiter(ph.unwrap());
|
||||
if ph != std::ptr::null_mut() {
|
||||
let ph = NonNull::<fuse_lowlevel::fuse_pollhandle>::new(ph);
|
||||
vuinput_state.poll.set_waiter(ph.unwrap());
|
||||
}
|
||||
fuse_lowlevel::fuse_reply_poll(req, 0);
|
||||
}
|
||||
PollPhase::Readable => {
|
||||
fuse_lowlevel::fuse_lowlevel_notify_poll(ph);
|
||||
fuse_lowlevel::fuse_pollhandle_destroy(ph);
|
||||
if ph != std::ptr::null_mut() {
|
||||
fuse_lowlevel::fuse_lowlevel_notify_poll(ph);
|
||||
fuse_lowlevel::fuse_pollhandle_destroy(ph);
|
||||
}
|
||||
fuse_lowlevel::fuse_reply_poll(req, POLLIN.try_into().unwrap());
|
||||
}
|
||||
PollPhase::Reading => {
|
||||
fuse_lowlevel::fuse_lowlevel_notify_poll(ph);
|
||||
fuse_lowlevel::fuse_pollhandle_destroy(ph);
|
||||
if ph != std::ptr::null_mut() {
|
||||
fuse_lowlevel::fuse_lowlevel_notify_poll(ph);
|
||||
fuse_lowlevel::fuse_pollhandle_destroy(ph);
|
||||
}
|
||||
fuse_lowlevel::fuse_reply_poll(req, POLLIN.try_into().unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ pub unsafe extern "C" fn vuinput_read(
|
|||
"vuinput_read: offset needs to be 0 but is {}",
|
||||
_off
|
||||
);
|
||||
fuse_lowlevel::fuse_reply_err(_req, EIO);
|
||||
return;
|
||||
//fuse_lowlevel::fuse_reply_err(_req, EIO);
|
||||
//return;
|
||||
|
||||
let fh = &(*_fi).fh;
|
||||
let vuinput_state_mutex =
|
||||
|
|
@ -41,10 +41,10 @@ pub unsafe extern "C" fn vuinput_read(
|
|||
|
||||
vuinput_state.poll.pollphase = PollPhase::Reading;
|
||||
// read up to 24 bytes
|
||||
println!("vuinput_read: read");
|
||||
//println!("vuinput_read: read");
|
||||
let result = vuinput_state.file.read(&mut buffer);
|
||||
|
||||
println!("vuinput_read: read finished");
|
||||
//println!("vuinput_read: read finished");
|
||||
match result {
|
||||
Ok(NORMAL_SIZE) => {
|
||||
if !is_compat {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue