Pass a richer State pointer to fsevents trampoline

This will be useful to re-instate a new stream when dropping events.
This commit is contained in:
Antonio Scandurra 2022-05-23 09:06:09 +02:00
parent e287425dee
commit f3bc4feaf0

View file

@ -22,11 +22,24 @@ pub struct Event {
pub struct EventStream { pub struct EventStream {
stream: fs::FSEventStreamRef, stream: fs::FSEventStreamRef,
state: Arc<Mutex<Lifecycle>>, lifecycle: Arc<Mutex<Lifecycle>>,
callback: Box<Option<RunCallback>>, state: Box<State>,
} }
type RunCallback = Box<dyn FnMut(Vec<Event>) -> bool>; struct State {
latency: Duration,
paths: cf::CFMutableArrayRef,
callback: Option<Box<dyn FnMut(Vec<Event>) -> bool>>,
last_valid_event_id: Option<fs::FSEventStreamEventId>,
}
impl Drop for State {
fn drop(&mut self) {
unsafe {
cf::CFRelease(self.paths);
}
}
}
enum Lifecycle { enum Lifecycle {
New, New,
@ -42,15 +55,6 @@ unsafe impl Send for Lifecycle {}
impl EventStream { impl EventStream {
pub fn new(paths: &[&Path], latency: Duration) -> (Self, Handle) { pub fn new(paths: &[&Path], latency: Duration) -> (Self, Handle) {
unsafe { unsafe {
let callback = Box::new(None);
let stream_context = fs::FSEventStreamContext {
version: 0,
info: callback.as_ref() as *const _ as *mut c_void,
retain: None,
release: None,
copy_description: None,
};
let cf_paths = let cf_paths =
cf::CFArrayCreateMutable(cf::kCFAllocatorDefault, 0, &cf::kCFTypeArrayCallBacks); cf::CFArrayCreateMutable(cf::kCFAllocatorDefault, 0, &cf::kCFTypeArrayCallBacks);
assert!(!cf_paths.is_null()); assert!(!cf_paths.is_null());
@ -69,6 +73,19 @@ impl EventStream {
cf::CFRelease(cf_url); cf::CFRelease(cf_url);
} }
let state = Box::new(State {
latency,
paths: cf_paths,
callback: None,
last_valid_event_id: None,
});
let stream_context = fs::FSEventStreamContext {
version: 0,
info: state.as_ref() as *const _ as *mut c_void,
retain: None,
release: None,
copy_description: None,
};
let stream = fs::FSEventStreamCreate( let stream = fs::FSEventStreamCreate(
cf::kCFAllocatorDefault, cf::kCFAllocatorDefault,
Self::trampoline, Self::trampoline,
@ -80,17 +97,15 @@ impl EventStream {
| fs::kFSEventStreamCreateFlagNoDefer | fs::kFSEventStreamCreateFlagNoDefer
| fs::kFSEventStreamCreateFlagWatchRoot, | fs::kFSEventStreamCreateFlagWatchRoot,
); );
cf::CFRelease(cf_paths);
let state = Arc::new(Mutex::new(Lifecycle::New));
let lifecycle = Arc::new(Mutex::new(Lifecycle::New));
( (
EventStream { EventStream {
stream, stream,
state: state.clone(), lifecycle: lifecycle.clone(),
callback, state,
}, },
Handle(state), Handle(lifecycle),
) )
} }
} }
@ -99,11 +114,11 @@ impl EventStream {
where where
F: FnMut(Vec<Event>) -> bool + 'static, F: FnMut(Vec<Event>) -> bool + 'static,
{ {
*self.callback = Some(Box::new(f)); self.state.callback = Some(Box::new(f));
unsafe { unsafe {
let run_loop = cf::CFRunLoopGetCurrent(); let run_loop = cf::CFRunLoopGetCurrent();
{ {
let mut state = self.state.lock(); let mut state = self.lifecycle.lock();
match *state { match *state {
Lifecycle::New => *state = Lifecycle::Running(run_loop), Lifecycle::New => *state = Lifecycle::Running(run_loop),
Lifecycle::Running(_) => unreachable!(), Lifecycle::Running(_) => unreachable!(),
@ -129,8 +144,8 @@ impl EventStream {
let event_paths = event_paths as *const *const ::std::os::raw::c_char; let event_paths = event_paths as *const *const ::std::os::raw::c_char;
let e_ptr = event_flags as *mut u32; let e_ptr = event_flags as *mut u32;
let i_ptr = event_ids as *mut u64; let i_ptr = event_ids as *mut u64;
let callback_ptr = (info as *mut Option<RunCallback>).as_mut().unwrap(); let state = (info as *mut State).as_mut().unwrap();
let callback = if let Some(callback) = callback_ptr.as_mut() { let callback = if let Some(callback) = state.callback.as_mut() {
callback callback
} else { } else {
return; return;