Skip to content
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

Return an error when Windows event loop is busy #3687

Open
wants to merge 9 commits into
base: master
Choose a base branch
from

Conversation

amrbashir
Copy link
Contributor

@amrbashir amrbashir commented May 7, 2024

This was a regression introduced in #3418

This new error could be used to retry events at later time

This also removes EventLoopClosed struct
and replaces it with EventLoopProxyError enum

  • Tested on all platforms changed
  • Added an entry to the changelog module if knowledge of this change could be valuable to users
  • Updated documentation to reflect any user-facing changes, including notes of platform-specific behavior
  • Created or updated an example program if it would help users understand this functionality
  • Updated feature matrix, if new features were added or implemented

This was a regression introduced in rust-windowing#3418

This new error could be used to retry events at later time

This also removes `EventLoopClosed` struct
and replaces it with `EventLoopProxyError` enum
@madsmtm
Copy link
Member

madsmtm commented May 7, 2024

Hmm, I'm unsure how you are expected to handle this as a user? The event is still in the queue, we can't just try to handle it later?

Also, this somewhat conflicts with #3424, I would really like the wakeup mechanism that we use to not be able to fail.

@amrbashir
Copy link
Contributor Author

Hmm, I'm unsure how you are expected to handle this as a user? The event is still in the queue, we can't just try to handle it later?

I initially started this PR with an older commit without noticing, it used to mess up the order of events, but no I am having a hard time reproducing it, will convert this to a draft until I can reproduce. (sorry for then noise)

Also, this somewhat conflicts with #3424, I would really like the wakeup mechanism that we use to not be able to fail.

yeah that would be great but PostMessageW has 10,000 limit so it will always fail with a lot of events so users will need to retry events (or at least a dummy event) or wait for the OS to send an event so the events in queue could be dispatched

@amrbashir amrbashir marked this pull request as draft May 8, 2024 00:29
@amrbashir
Copy link
Contributor Author

amrbashir commented May 8, 2024

I have added an example showcasing the problem, basically even though the events are not lost and are sitting in the queue, we need to send empty wakeup events so they can be dispatched again. Without this PR, we can't know if PostMessageW fails and so can't send empty wakeup events.

The example tries to send 15000 events, it fails to deliever 2667 of them and we need to send at least another successful 2667 equivalent wakup events

@amrbashir amrbashir marked this pull request as ready for review May 8, 2024 01:17
@madsmtm
Copy link
Member

madsmtm commented May 20, 2024

We're reworking user events in #3694, in there I noted an alternative:

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?

Do you think that's a viable solution to this problem?

@amrbashir
Copy link
Contributor Author

Quickly reading through the changes in #3694, it still exhibits the same problem, but it is a lot better since it won't consume the data being sent.

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?

Do you think that's a viable solution to this problem?

Not sure what you mean by "do it in the next iteration", do you mean call ApplicationHandler::user_wakeup_event method one more time?

I don't think that helps much, since more than one wakeup events can fail consecutively.

I could probably change my logic to use for event in rx.iter() to empty out the pending events once a successful wakeup has been through but still I would need to know that wakup failed by returning an error if PostMessageW failed, so I can run a timeout and wake the event loop again later.

@madsmtm
Copy link
Member

madsmtm commented May 20, 2024

Not sure what you mean by "do it in the next iteration", do you mean call ApplicationHandler::user_wakeup_event method one more time?

I meant to, if PostMessageW failed, set a variable somewhere that is then checked at the top-level inside public_window_callback (or thread_event_target_callback, not sure what the difference is) and if it is set, then emit the event.

This would work under the assumption that the reason why PostMessageW fails is that it's busy processing other events, and as such we don't actually need to wake up the event loop, it is already wide awake.

@amrbashir
Copy link
Contributor Author

Not sure what you mean by "do it in the next iteration", do you mean call ApplicationHandler::user_wakeup_event method one more time?

I meant to, if PostMessageW failed, set a variable somewhere that is then checked at the top-level inside public_window_callback (or thread_event_target_callback, not sure what the difference is) and if it is set, then emit the event.

But why not just return an error if it failed, ofc I am talking in the context of #3694 where the proxy just calls PostMessageW so you can check if it failed and return an error

@madsmtm
Copy link
Member

madsmtm commented May 21, 2024

But why not just return an error if it failed, ofc I am talking in the context of #3694 where the proxy just calls PostMessageW so you can check if it failed and return an error

Hmm, mostly because it's unclear how the user is expected to handle that error? Like, they can't just retry, waking up, as that'll likely just give them the same error.

Especially so if there is a solution for us to handle this fully internally in Winit, then I'd rather not push the error case onto users.

@amrbashir
Copy link
Contributor Author

But why not just return an error if it failed, ofc I am talking in the context of #3694 where the proxy just calls PostMessageW so you can check if it failed and return an error

Hmm, mostly because it's unclear how the user is expected to handle that error? Like, they can't just retry, waking up, as that'll likely just give them the same error.

Yeah that is expected, and in that case we have a logic to try which re-tries until succession

let mut res = wakeup_eventloop();
while (res.is_err()) {
  sleep(15ms);
  res = wakeup_eventloop();
}

This is a very basic solution and maybe sufficient along with a receiver implementation that uses for event in rx.iter(), but if needed we probably will add a state to track how many calls failed and we will dispatch equivalent number of wakeup calls.

Especially so if there is a solution for us to handle this fully internally in Winit, then I'd rather not push the error case onto users.

I don't see how Winit could handle this case tbh, especially since winit will no longer take ownership of the data, and if wakeup failed, user can't know if wakeup failed or which one failed and can't implement logic to gracefully handle that.

@madsmtm
Copy link
Member

madsmtm commented May 21, 2024

we will dispatch equivalent number of wakeup calls.

We haven't finalized this yet, but I think we're going to decide that multiple wakeup calls don't necessarily lead to multiple wakeups; i.e. they may be merged.

I don't see how Winit could handle this case tbh

I'll try to whip up another PR for it once #3694 is done (especially if reminded), so let's discuss it at that time.

@amrbashir
Copy link
Contributor Author

amrbashir commented May 21, 2024

We haven't finalized this yet, but I think we're going to decide that multiple wakeup calls don't necessarily lead to multiple wakeups; i.e. they may be merged.

That should still be fine for our use-case.

I'll try to whip up another PR for it once #3694 is done (especially if reminded), so let's discuss it at that time.

Thanks, I will keep an eye for it

@daxpedda
Copy link
Member

Especially so if there is a solution for us to handle this fully internally in Winit, then I'd rather not push the error case onto users.

I very much agree with this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants