-
Notifications
You must be signed in to change notification settings - Fork 867
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
event_loop: remove generic user event #3694
base: master
Are you sure you want to change the base?
Conversation
Let the users wake up the event loop and then they could poll their user sources.
5244f86
to
d5fdf2b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've reviewed the macOS, iOS and Windows implementations now to the best of my ability.
@@ -82,11 +82,11 @@ pub trait ApplicationHandler<T: 'static = ()> { | |||
/// [`Suspended`]: Self::suspended | |||
fn resumed(&mut self, event_loop: &ActiveEventLoop); | |||
|
|||
/// Emitted when an event is sent from [`EventLoopProxy::send_event`]. | |||
/// Called when user requested wake up via [`wake_up`] occurs. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Continuing from #3424 (comment).
I'd like to discuss the semantics of this. Here's what I think the semantics should be:
- It is guaranteed to happen between
new_events
andabout_to_wait
(like all the other events). - It will not be emitted the same number of times as the user called
wake_up
.- This should be documented thoroughly, ideally with an example on the method using a
std::sync::mpsc::channel
which loops over the received events (instead of doinglet event = receiver.try_recv().unwrap();
).
- This should be documented thoroughly, ideally with an example on the method using a
- The order in which this is emitted is not guaranteed (i.e. it may be emitted right after
new_events
, or it may be emitted just beforeabout_to_wait
, or any time in between those). - The time at which this will be emitted is not guaranteed (only that it will happen "soon", i.e. there may be several executions of the event loop, including multiple redraws to windows, between
wake_up
being called and the event being delivered). - The event may be emitted spuriously.
- The event may be ignored spuriously (see Return an error when Windows event loop is busy #3687).
- This seems like it'd make it too unreliable to be of any real use, though unsure if we can do it any other way? Maybe on Windows, we can keep a
wake_up_failed: Arc<AtomicBool>
around, and then do it in the next iteration if the boolean is set? - In any case, we can make no guarantee in this PR, and then in a follow-up, make the change and add the guarantee!
- This seems like it'd make it too unreliable to be of any real use, though unsure if we can do it any other way? Maybe on Windows, we can keep a
I've deliberately chosen the most conservative semantics here, if we find that users need stronger guarantees, we can always add them. Please raise your concerns with any of these!
Also, we should document all of this in detail once we agree.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a lot of words for something that should behave more or less like RedrawRequested
.
I'd say that the:
- Order is not defined, but generally should be before
RedrawRequsted
. - Events are squashed, as
request_redraw
.
Events being lost or busy can not really happen due to semantics of how it's written or should be written, if it does it's a bug.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- The event may be ignored spuriously (see Return an error when Windows event loop is busy #3687).
- This seems like it'd make it too unreliable to be of any real use, though unsure if we can do it any other way? Maybe on Windows, we can keep a
wake_up_failed: Arc<AtomicBool>
around, and then do it in the next iteration if the boolean is set?- In any case, we can make no guarantee in this PR, and then in a follow-up, make the change and add the guarantee!
I think without a guarantee that it will actually wake up it is indeed not very valuable, so I would prefer if we get everything in order right here.
I very much agree with all the other semantics.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll outline that the semantics must be:
- It's delivered only once between
NewEvents
andAboutToWait
, no matter how much you ask for it. That's how e.g.eventfd
works, for example(and that's what we use on linux here). - It can not fail (when the loop is running at least), winit must ensure that you get a wakeup.
Now I also think that we should communicate errors just in case for forward compat/backward, since it's a good way to detect whether the loop is still alive from auxiliary threads.
At least error should have the option of LoopLost
or something like that.
So as for the current implementation you already can see that everything is following 1, but as for the 2, there's no guarantee for that, so maybe adding an error for now is a good way forward with that.
@@ -2454,7 +2392,7 @@ unsafe extern "system" fn thread_event_target_callback( | |||
// user event is still in the mpsc channel and will be pulled | |||
// once the placeholder event is delivered to the wrapper | |||
// `event_handler` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Update comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's relatively accurate given that we still do roundtrips with channel, because I'm afraid to change that to use something else, because I can not really test this one.
pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> { | ||
self.sender.send(event).map_err(|mpsc::SendError(x)| EventLoopClosed(x))?; | ||
pub fn wake_up(&self) { | ||
self.user_wake_up.store(true, AtomicOrdering::Relaxed); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think there is a correct ordering to use here, technically the CPU could choose to execute all the code below, and wake up the main thread to process the event, before actually setting this flag (SeqCst
is not strong enough to do this either, as it'd have to have been used in CFRunLoopWakeUp
as well, which I'm not sure it has).
The proper way to do this would be to emit the wake-up event (or just set a flag) inside the event_loop_proxy_handler
function above (which runs on the main thread). That's a bit of a larger rework though, the current impl will work fine for now (and the old code had the same problem), I'll change it myself at a later point.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only thing I care about is that the event is emitted only once and the wake up is not lost. Though, I think more intense sync should be on the user here...
b3386f4
to
11bf122
Compare
Web should be good now. Apart from us agreeing on the details and adding some documentation I'm very much in favor of moving forward with this. |
11bf122
to
175e0ba
Compare
175e0ba
to
4e8bbc1
Compare
4e8bbc1
to
4ac84e5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK to X11
ac357ed
to
aa5b67b
Compare
aa5b67b
to
b142035
Compare
Let the users wake up the event loop and then they could poll their
user sources.
--
I haven't tested these changes outside of Wayland. Please carefully review your backend changes.
I know that
Windows
andWeb
are likely done not correctly.On macOS/ios the atomic ordering is likely not correct either, but I'm not familiar enough with the CFRunLoop behavior to ensure that.
There's also #3424 , but the proxy should be platform specific and in the end just a trait. Maybe we'll use
Waker
, but for now I went with just removing generic which prevents me from usingdyn
more actively.This PR is build on top of #3683