Skip to content

Commit

Permalink
Protect against reentrancy (messily)
Browse files Browse the repository at this point in the history
  • Loading branch information
francesca64 committed Dec 21, 2018
1 parent b75073a commit 5f4aa9f
Showing 1 changed file with 49 additions and 14 deletions.
63 changes: 49 additions & 14 deletions src/platform_impl/macos/app_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,13 @@ where
#[derive(Default)]
struct Handler {
ready: AtomicBool,
in_callback: AtomicBool,
control_flow: Mutex<ControlFlow>,
control_flow_prev: Mutex<ControlFlow>,
start_time: Mutex<Option<Instant>>,
callback: Mutex<Option<Box<dyn EventHandler>>>,
pending_events: Mutex<VecDeque<Event<Never>>>,
deferred_events: Mutex<VecDeque<Event<Never>>>,
pending_redraw: Mutex<Vec<WindowId>>,
waker: Mutex<EventLoopWaker>,
}
Expand All @@ -99,6 +101,10 @@ impl Handler {
self.pending_events.lock().unwrap()
}

fn deferred<'a>(&'a self) -> MutexGuard<'a, VecDeque<Event<Never>>> {
self.deferred_events.lock().unwrap()
}

fn redraw<'a>(&'a self) -> MutexGuard<'a, Vec<WindowId>> {
self.pending_redraw.lock().unwrap()
}
Expand Down Expand Up @@ -143,10 +149,22 @@ impl Handler {
mem::replace(&mut *self.events(), Default::default())
}

fn take_deferred(&self) -> VecDeque<Event<Never>> {
mem::replace(&mut *self.deferred(), Default::default())
}

fn should_redraw(&self) -> Vec<WindowId> {
mem::replace(&mut *self.redraw(), Default::default())
}

fn get_in_callback(&self) -> bool {
self.in_callback.load(Ordering::Acquire)
}

fn set_in_callback(&self, in_callback: bool) {
self.in_callback.store(in_callback, Ordering::Release);
}

fn handle_nonuser_event(&self, event: Event<Never>) {
if let Some(ref mut callback) = *self.callback.lock().unwrap() {
callback.handle_nonuser_event(
Expand Down Expand Up @@ -181,13 +199,17 @@ impl AppState {
}

pub fn exit() {
HANDLER.set_in_callback(true);
HANDLER.handle_nonuser_event(Event::LoopDestroyed);
HANDLER.set_in_callback(false);
}

pub fn launched() {
HANDLER.set_ready();
HANDLER.waker().start();
HANDLER.set_in_callback(true);
HANDLER.handle_nonuser_event(Event::NewEvents(StartCause::Init));
HANDLER.set_in_callback(false);
}

pub fn wakeup() {
Expand All @@ -214,7 +236,9 @@ impl AppState {
},
ControlFlow::Exit => StartCause::Poll,//panic!("unexpected `ControlFlow::Exit`"),
};
HANDLER.set_in_callback(true);
HANDLER.handle_nonuser_event(Event::NewEvents(cause));
HANDLER.set_in_callback(false);
}

// This is called from multiple threads at present
Expand All @@ -227,38 +251,49 @@ impl AppState {

pub fn queue_event(event: Event<Never>) {
if !unsafe { msg_send![class!(NSThread), isMainThread] } {
panic!("uh-oh");
panic!("Event queued from different thread: {:#?}", event);
}
HANDLER.events().push_back(event);
}

pub fn queue_events(mut events: VecDeque<Event<Never>>) {
if !unsafe { msg_send![class!(NSThread), isMainThread] } {
panic!("uh-ohs");
panic!("Events queued from different thread: {:#?}", events);
}
HANDLER.events().append(&mut events);
}

pub fn send_event_immediately(event: Event<Never>) {
if !unsafe { msg_send![class!(NSThread), isMainThread] } {
panic!("uh-oh");
panic!("Event sent from different thread: {:#?}", event);
}
HANDLER.deferred().push_back(event);
if !HANDLER.get_in_callback() {
HANDLER.set_in_callback(true);
for event in HANDLER.take_deferred() {
HANDLER.handle_nonuser_event(event);
}
HANDLER.set_in_callback(false);
}
HANDLER.handle_nonuser_event(event);
}

pub fn cleared() {
if !HANDLER.is_ready() { return }
HANDLER.handle_user_events();
for event in HANDLER.take_events() {
HANDLER.handle_nonuser_event(event);
}
for window_id in HANDLER.should_redraw() {
HANDLER.handle_nonuser_event(Event::WindowEvent {
window_id,
event: WindowEvent::RedrawRequested,
});
if !HANDLER.get_in_callback() {
HANDLER.set_in_callback(true);
HANDLER.handle_user_events();
for event in HANDLER.take_events() {
HANDLER.handle_nonuser_event(event);
}
for window_id in HANDLER.should_redraw() {
HANDLER.handle_nonuser_event(Event::WindowEvent {
window_id,
event: WindowEvent::RedrawRequested,
});
}
HANDLER.handle_nonuser_event(Event::EventsCleared);
HANDLER.set_in_callback(false);
}
HANDLER.handle_nonuser_event(Event::EventsCleared);
if HANDLER.should_exit() {
let _: () = unsafe { msg_send![NSApp(), stop:nil] };
return
Expand Down

0 comments on commit 5f4aa9f

Please sign in to comment.