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

Add opt-in handlers for before sleeping and before handling events #144

Merged
merged 20 commits into from
Sep 9, 2023

Conversation

DJMcNab
Copy link
Contributor

@DJMcNab DJMcNab commented Aug 26, 2023

Solves #127. Designed to work with Smithay/wayland-rs#650 and to be used to fix #glazier > Freeze with Wayland egl

src/sources/mod.rs Outdated Show resolved Hide resolved
src/sources/mod.rs Outdated Show resolved Hide resolved
Comment on lines 60 to 61
pub(crate) sources: RefCell<Slab<Rc<dyn EventDispatcher<Data> + 'l>>>,
pub(crate) sources_with_additional_lifetime_events: AdditionalLifetimeEventsSet,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we just duplicate the way sources are defined instead of rolling new abstraction? And create an iterator which simply chains both when needed?

@codecov
Copy link

codecov bot commented Aug 28, 2023

Codecov Report

Patch coverage: 75.60% and project coverage change: -1.68% ⚠️

Comparison is base (d468cc9) 88.79% compared to head (33aed4a) 87.11%.

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #144      +/-   ##
==========================================
- Coverage   88.79%   87.11%   -1.68%     
==========================================
  Files          14       14              
  Lines        1669     1739      +70     
==========================================
+ Hits         1482     1515      +33     
- Misses        187      224      +37     
Flag Coverage Δ
macos-latest 86.61% <75.60%> (-1.85%) ⬇️
ubuntu-latest 86.64% <75.60%> (-1.73%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files Changed Coverage Δ
src/io.rs 73.51% <0.00%> (-9.05%) ⬇️
src/loop_logic.rs 86.90% <80.43%> (-3.56%) ⬇️
src/sources/mod.rs 95.18% <97.91%> (-0.52%) ⬇️
src/sys.rs 98.43% <100.00%> (+0.02%) ⬆️

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

src/sources/mod.rs Outdated Show resolved Hide resolved
/// Use this to perform operations which must be done before polling,
/// but which may conflict with other event handlers. For example,
/// if polling requires a lock to be taken.
fn before_will_sleep(&mut self) -> crate::Result<Option<(Readiness, Token)>> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about naming this before_sleep instead? This matches better the naming pattern of the other method.

@elinorbgr
Copy link
Member

Also, it looks like the signals test is failing? Is it because of the nix update?

Copy link
Member

@elinorbgr elinorbgr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are naming inconsistencies in the code, sometimes things are named "lifecycle events" and sometimes "lifetime events", I think we should use "lifecycle events" everywhere.

Also, could you rebase this PR on master? Otherwise, lgtm 👍

Cargo.toml Outdated Show resolved Hide resolved
src/sources/mod.rs Outdated Show resolved Hide resolved
Copy link
Member

@kchibisov kchibisov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we at least do something like that? it should at least make it more readable. The main pain point is still Rc stuff. Also, I'm not sure what this all logic wrt Registration token, TokenFactory tries to do, because it's not consistent with what it does. Like it seems that sometimes sub sources are being passed, sometimes real sources, it's just all over the place, but I don't want to go into details with it.

My patch is likely broken with regards to those tokens, but generally it's just more consistent with what already is. I don't disagree with the idea to cache tokens to improve lookups, it' just I'd rather follow the current abstractions.

diff --git a/src/io.rs b/src/io.rs
index ffbb857..980cd59 100644
--- a/src/io.rs
+++ b/src/io.rs
@@ -18,7 +18,7 @@ use rustix::fs::{fcntl_getfl, fcntl_setfl, OFlags};
 #[cfg(feature = "futures-io")]
 use futures_io::{AsyncRead, AsyncWrite, IoSlice, IoSliceMut};
 
-use crate::AdditionalLifetimeEventsRegister;
+use crate::AdditionalLifecycleEventsSet;
 use crate::{
     loop_logic::{LoopInner, MAX_SOURCES_MASK},
     sources::EventDispatcher,
@@ -241,7 +241,7 @@ impl<Data> EventDispatcher<Data> for RefCell<IoDispatcher> {
     fn register(
         &self,
         _: &mut Poll,
-        _: AdditionalLifetimeEventsRegister<'_>,
+        _: &mut AdditionalLifecycleEventsSet,
         _: &mut TokenFactory,
     ) -> crate::Result<()> {
         // registration is handled by IoLoopInner
@@ -251,7 +251,7 @@ impl<Data> EventDispatcher<Data> for RefCell<IoDispatcher> {
     fn reregister(
         &self,
         _: &mut Poll,
-        _: AdditionalLifetimeEventsRegister<'_>,
+        _: &mut AdditionalLifecycleEventsSet,
         _: &mut TokenFactory,
     ) -> crate::Result<bool> {
         // registration is handled by IoLoopInner
@@ -261,7 +261,8 @@ impl<Data> EventDispatcher<Data> for RefCell<IoDispatcher> {
     fn unregister(
         &self,
         poll: &mut Poll,
-        _: AdditionalLifetimeEventsRegister<'_>,
+        _: &mut AdditionalLifecycleEventsSet,
+        _: TokenFactory,
     ) -> crate::Result<bool> {
         let disp = self.borrow();
         if disp.is_registered {
diff --git a/src/loop_logic.rs b/src/loop_logic.rs
index a0ab8e5..661e58d 100644
--- a/src/loop_logic.rs
+++ b/src/loop_logic.rs
@@ -15,7 +15,7 @@ use slab::Slab;
 use crate::sources::{Dispatcher, EventSource, Idle, IdleDispatcher};
 use crate::sys::{Notifier, PollEvent};
 use crate::{
-    AdditionalLifetimeEventsSet, EventDispatcher, InsertError, Poll, PostAction, TokenFactory,
+    AdditionalLifecycleEventsSet, EventDispatcher, InsertError, Poll, PostAction, TokenFactory,
 };
 
 type IdleCallback<'i, Data> = Rc<RefCell<dyn IdleDispatcher<Data> + 'i>>;
@@ -58,7 +58,7 @@ pub struct RegistrationToken {
 pub(crate) struct LoopInner<'l, Data> {
     pub(crate) poll: RefCell<Poll>,
     pub(crate) sources: RefCell<Slab<Rc<dyn EventDispatcher<Data> + 'l>>>,
-    pub(crate) sources_with_additional_lifecycle_events: AdditionalLifetimeEventsSet,
+    pub(crate) sources_with_additional_lifecycle_events: RefCell<AdditionalLifecycleEventsSet>,
     idles: RefCell<Vec<IdleCallback<'l, Data>>>,
     pending_action: Cell<PostAction>,
 }
@@ -140,9 +140,10 @@ impl<'l, Data> LoopHandle<'l, Data> {
         let key = sources.insert(dispatcher.clone_as_event_dispatcher());
         let ret = sources.get(key).unwrap().register(
             &mut poll,
-            self.inner
+            &mut self
+                .inner
                 .sources_with_additional_lifecycle_events
-                .create_register_for_token(RegistrationToken { key }),
+                .borrow_mut(),
             &mut TokenFactory::new(key),
         );
 
@@ -178,9 +179,10 @@ impl<'l, Data> LoopHandle<'l, Data> {
         if let Some(source) = self.inner.sources.borrow().get(token.key) {
             source.register(
                 &mut self.inner.poll.borrow_mut(),
-                self.inner
+                &mut self
+                    .inner
                     .sources_with_additional_lifecycle_events
-                    .create_register_for_token(*token),
+                    .borrow_mut(),
                 &mut TokenFactory::new(token.key),
             )?;
         }
@@ -195,9 +197,10 @@ impl<'l, Data> LoopHandle<'l, Data> {
         if let Some(source) = self.inner.sources.borrow().get(token.key) {
             if !source.reregister(
                 &mut self.inner.poll.borrow_mut(),
-                self.inner
+                &mut self
+                    .inner
                     .sources_with_additional_lifecycle_events
-                    .create_register_for_token(*token),
+                    .borrow_mut(),
                 &mut TokenFactory::new(token.key),
             )? {
                 // we are in a callback, store for later processing
@@ -214,9 +217,11 @@ impl<'l, Data> LoopHandle<'l, Data> {
         if let Some(source) = self.inner.sources.borrow().get(token.key) {
             if !source.unregister(
                 &mut self.inner.poll.borrow_mut(),
-                self.inner
+                &mut self
+                    .inner
                     .sources_with_additional_lifecycle_events
-                    .create_register_for_token(*token),
+                    .borrow_mut(),
+                TokenFactory::new(token.key),
             )? {
                 // we are in a callback, store for later processing
                 self.inner.pending_action.set(PostAction::Disable);
@@ -230,9 +235,11 @@ impl<'l, Data> LoopHandle<'l, Data> {
         if let Some(source) = self.inner.sources.borrow_mut().try_remove(token.key) {
             if let Err(e) = source.unregister(
                 &mut self.inner.poll.borrow_mut(),
-                self.inner
+                &mut self
+                    .inner
                     .sources_with_additional_lifecycle_events
-                    .create_register_for_token(token),
+                    .borrow_mut(),
+                TokenFactory::new(token.key),
             ) {
                 log::warn!(
                     "[calloop] Failed to unregister source from the polling system: {:?}",
@@ -320,16 +327,17 @@ impl<'l, Data> EventLoop<'l, Data> {
     ) -> crate::Result<()> {
         let now = Instant::now();
         {
-            let mut extra_lifecycle_sources = self
+            let extra_lifecycle_sources = &mut self
                 .handle
                 .inner
                 .sources_with_additional_lifecycle_events
-                .values
-                .borrow_mut();
+                .borrow_mut()
+                .values;
+
             let sources = &self.handle.inner.sources.borrow();
-            for (source, has_event) in &mut *extra_lifecycle_sources {
+            for (source_key, has_event) in &mut *extra_lifecycle_sources {
                 *has_event = false;
-                if let Some(disp) = sources.get(source.key) {
+                if let Some(disp) = sources.get(*source_key) {
                     if let Some((readiness, token)) = disp.before_sleep()? {
                         // Wake up instantly after polling if we recieved an event
                         timeout = Some(Duration::ZERO);
@@ -363,21 +371,21 @@ impl<'l, Data> EventLoop<'l, Data> {
             }
         };
         {
-            let mut extra_lifecycle_sources = self
+            let extra_lifecycle_sources = &mut self
                 .handle
                 .inner
                 .sources_with_additional_lifecycle_events
-                .values
-                .borrow_mut();
+                .borrow_mut()
+                .values;
             if !extra_lifecycle_sources.is_empty() {
-                for (source, has_event) in &mut *extra_lifecycle_sources {
+                for (source_key, has_event) in &mut *extra_lifecycle_sources {
                     for event in &events {
-                        *has_event |= (event.token.key & MAX_SOURCES_MASK) == source.key;
+                        *has_event |= (event.token.key & MAX_SOURCES_MASK) == *source_key;
                     }
                 }
             }
-            for (source, has_event) in &*extra_lifecycle_sources {
-                if let Some(disp) = self.handle.inner.sources.borrow().get(source.key) {
+            for (source_key, has_event) in &*extra_lifecycle_sources {
+                if let Some(disp) = self.handle.inner.sources.borrow().get(*source_key) {
                     disp.before_handle_events(*has_event);
                 } else {
                     unreachable!()
@@ -414,24 +422,23 @@ impl<'l, Data> EventLoop<'l, Data> {
                     PostAction::Reregister => {
                         disp.reregister(
                             &mut self.handle.inner.poll.borrow_mut(),
-                            self.handle
+                            &mut self
+                                .handle
                                 .inner
                                 .sources_with_additional_lifecycle_events
-                                .create_register_for_token(RegistrationToken {
-                                    key: registroken_token,
-                                }),
+                                .borrow_mut(),
                             &mut TokenFactory::new(event.token.key),
                         )?;
                     }
                     PostAction::Disable => {
                         disp.unregister(
                             &mut self.handle.inner.poll.borrow_mut(),
-                            self.handle
+                            &mut self
+                                .handle
                                 .inner
                                 .sources_with_additional_lifecycle_events
-                                .create_register_for_token(RegistrationToken {
-                                    key: registroken_token,
-                                }),
+                                .borrow_mut(),
+                            TokenFactory::new(event.token.key),
                         )?;
                     }
                     PostAction::Remove => {
@@ -456,12 +463,12 @@ impl<'l, Data> EventLoop<'l, Data> {
                     let mut poll = self.handle.inner.poll.borrow_mut();
                     if let Err(e) = disp.unregister(
                         &mut poll,
-                        self.handle
+                        &mut self
+                            .handle
                             .inner
                             .sources_with_additional_lifecycle_events
-                            .create_register_for_token(RegistrationToken {
-                                key: registroken_token,
-                            }),
+                            .borrow_mut(),
+                        TokenFactory::new(registroken_token),
                     ) {
                         log::warn!(
                             "[calloop] Failed to unregister source from the polling system: {:?}",
diff --git a/src/sources/mod.rs b/src/sources/mod.rs
index 4ccc1d5..3111dfa 100644
--- a/src/sources/mod.rs
+++ b/src/sources/mod.rs
@@ -4,7 +4,7 @@ use std::{
     rc::Rc,
 };
 
-use crate::{sys::TokenFactory, Poll, Readiness, RegistrationToken, Token};
+use crate::{sys::TokenFactory, Poll, Readiness, Token};
 
 pub mod channel;
 #[cfg(feature = "executor")]
@@ -314,13 +314,13 @@ where
     fn register(
         &self,
         poll: &mut Poll,
-        mut additional_lifecycle_register: AdditionalLifetimeEventsRegister<'_>,
+        additional_lifecycle_register: &mut AdditionalLifecycleEventsSet,
         token_factory: &mut TokenFactory,
     ) -> crate::Result<()> {
         let mut this = self.borrow_mut();
 
         if this.needs_additional_lifecycle_events {
-            additional_lifecycle_register.register();
+            additional_lifecycle_register.register(token_factory.key);
         }
         this.source.register(poll, token_factory)
     }
@@ -328,13 +328,13 @@ where
     fn reregister(
         &self,
         poll: &mut Poll,
-        mut additional_lifecycle_register: AdditionalLifetimeEventsRegister<'_>,
+        additional_lifecycle_register: &mut AdditionalLifecycleEventsSet,
         token_factory: &mut TokenFactory,
     ) -> crate::Result<bool> {
         if let Ok(mut me) = self.try_borrow_mut() {
             me.source.reregister(poll, token_factory)?;
             if me.needs_additional_lifecycle_events {
-                additional_lifecycle_register.register();
+                additional_lifecycle_register.register(token_factory.key);
             }
             Ok(true)
         } else {
@@ -345,12 +345,13 @@ where
     fn unregister(
         &self,
         poll: &mut Poll,
-        mut additional_lifecycle_register: AdditionalLifetimeEventsRegister<'_>,
+        additional_lifecycle_register: &mut AdditionalLifecycleEventsSet,
+        token_factory: TokenFactory,
     ) -> crate::Result<bool> {
         if let Ok(mut me) = self.try_borrow_mut() {
             me.source.unregister(poll)?;
             if me.needs_additional_lifecycle_events {
-                additional_lifecycle_register.unregister();
+                additional_lifecycle_register.unregister(token_factory.key);
             }
             Ok(true)
         } else {
@@ -382,60 +383,43 @@ pub(crate) trait EventDispatcher<Data> {
     fn register(
         &self,
         poll: &mut Poll,
-        additional_lifecycle_register: AdditionalLifetimeEventsRegister<'_>,
+        additional_lifecycle_register: &mut AdditionalLifecycleEventsSet,
         token_factory: &mut TokenFactory,
     ) -> crate::Result<()>;
 
     fn reregister(
         &self,
         poll: &mut Poll,
-        additional_lifecycle_register: AdditionalLifetimeEventsRegister<'_>,
+        additional_lifecycle_register: &mut AdditionalLifecycleEventsSet,
         token_factory: &mut TokenFactory,
     ) -> crate::Result<bool>;
 
     fn unregister(
         &self,
         poll: &mut Poll,
-        additional_lifecycle_register: AdditionalLifetimeEventsRegister<'_>,
+        additional_lifecycle_register: &mut AdditionalLifecycleEventsSet,
+        token_factory: TokenFactory,
     ) -> crate::Result<bool>;
 
     fn before_sleep(&self) -> crate::Result<Option<(Readiness, Token)>>;
     fn before_handle_events(&self, was_awoken: bool);
 }
 
+/// Track sources which require extra lifecycle events.
 #[derive(Default)]
-/// The list of events
-pub(crate) struct AdditionalLifetimeEventsSet {
+pub(crate) struct AdditionalLifecycleEventsSet {
     /// The list of events. The boolean indicates whether the source had an event
     /// - this is stored in this list because we need to know this value for each
     /// item at once - that is, to avoid allocating in the hot loop
-    pub(crate) values: RefCell<Vec<(RegistrationToken, bool)>>,
+    pub(crate) values: Vec<(usize, bool)>,
 }
-
-impl AdditionalLifetimeEventsSet {
-    pub(crate) fn create_register_for_token(
-        &self,
-        token: RegistrationToken,
-    ) -> AdditionalLifetimeEventsRegister {
-        AdditionalLifetimeEventsRegister { set: self, token }
-    }
-}
-
-/// To ensure that registering the events which need additional lifecycle events
-/// happens correctly, we do this within the implementations of `EventDispatcher`
-/// `AdditionalLifetimeEventsRegister` is a helper type to centralise this logic
-pub(crate) struct AdditionalLifetimeEventsRegister<'a> {
-    set: &'a AdditionalLifetimeEventsSet,
-    token: RegistrationToken,
-}
-
-impl<'a> AdditionalLifetimeEventsRegister<'a> {
-    fn register(&mut self) {
-        self.set.values.borrow_mut().push((self.token, false))
+impl AdditionalLifecycleEventsSet {
+    fn register(&mut self, token: usize) {
+        self.values.push((token, false))
     }
 
-    fn unregister(&mut self) {
-        self.set.values.borrow_mut().retain(|it| it.0 != self.token)
+    fn unregister(&mut self, token: usize) {
+        self.values.retain(|it| it.0 != token)
     }
 }
 

Cargo.toml Outdated Show resolved Hide resolved
@DJMcNab
Copy link
Contributor Author

DJMcNab commented Aug 30, 2023

So there are three changes you're asking for there:

  1. To make AdditionalLifecycleEventsSet not have the inner RefCell. The current design was intended to avoid doing the borrow_mut operations in the cases where they weren't needed, but that is only a small difference, as these shouldn't be on the hot path. This transformation hardly changes the code length, so I'll defer to @elinorbgr on this
  2. To make the vector inside AdditionalLifecycleEventsSet not type-safe. There is definitely a slight verbosity cost, but I believe it's generally better to be more type safe than less type safe. Again, I'll defer to @elinorbgr
  3. To use the key which is already present in TokenFactory, thus avoiding AdditionalLifecycleEventsRegister. I had avoided doing this because the key field on TokenFactory isn't public. (Edit: I had made it public in a prior commit, which I never used) I think there are two aspects to this:
    • Whether the key field on TokenFactory should be exposed outside of sys.rs. I personally that would be a layering violation, but I think it is also much cleaner for this PR. I think I will make this change (by adding a pub(crate) fn registration_token(&self)->RegistrationToken method on TokenFactory)
    • Whether this key field should be exposed in the public API. I probably would expose it, but I've not done much thinking on that, and I'm not planning to do so in this PR.

@elinorbgr
Copy link
Member

Just to make sure I didn't miss anything, point 1) is just about having the RefCell inside or outside of the AdditionalLifecycleEventsSet right? Given how small the difference is in terms of running, I think I'd prefer to have it outside, as it'd be more coherent with the rest of the contents of LoopInner.

Regarding 2/3, I think I like the way it is currently on the PR, keeping the type-safety and using the token from he available tokenfactory is good imo, especially given this concerns crate-internals anyway.

@elinorbgr
Copy link
Member

Also, AdditionalLifetimeEventsSet is still named using lifetime rather than lifecycle, I guess this one slipped through your attention? 😅

@DJMcNab DJMcNab requested a review from elinorbgr August 31, 2023 17:01
Copy link
Member

@kchibisov kchibisov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have concerns with this anymore. Thanks.

CHANGELOG.md Outdated
Comment on lines 9 to 10
- Replace the `nix` crate with standard library I/O errors and the `rustix`
crate.
crate.s
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like a typo snuck in there? Also actually I don't get why "crate" is on its own line there, let's just put it at the end of the previous line.

Cargo.toml Outdated
@@ -24,7 +24,7 @@ bitflags = "1.2"
futures-io = { version = "0.3.5", optional = true }
io-lifetimes = "1.0.3"
log = "0.4"
nix = { version = "0.26", default-features = false, features = ["signal"], optional = true }
nix = { version = "0.26", default-features = false, features = ["signal",], optional = true }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the point of this change?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have an extension which formats TOML files. In 0364c1c, I reverted some edits made by this manually, but missed this comma

Comment on lines 386 to 399
if !extra_lifecycle_sources.values.is_empty() {
for (source, has_event) in &mut *extra_lifecycle_sources.values {
for event in &events {
*has_event |= (event.token.key & MAX_SOURCES_MASK) == source.key;
}
}
}
for (source, has_event) in &*extra_lifecycle_sources.values {
if let Some(disp) = self.handle.inner.sources.borrow().get(source.key) {
disp.before_handle_events(*has_event);
} else {
unreachable!()
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't these two loops be fused into a single one?

And then, it looks like has_event is only used by those two loops, so it can probably be removed altogether from extra_lifecycle_sources, no?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't believe so - we need to run all before_handle_events handlers, even those which didn't receive events

I suppose we could have two different handler methods for the different parts, so that we don't need to track was_awoken. That means that if a source needs was_awoken, it would have to track it itself. But that's fine

I'm fairly sure we do need two loops though

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But what about something like this?

for each extra_lifecycle_source {
    let has_event = /* loop over events to check if that source was woken up */;
    disp.before_handle_events(has_event);
}

Comment on lines 172 to 173
/// If this returns Ok(Some), polling will shortcircuit, and
/// your event handler will be called with the returned Token and Readiness
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current implementation does still invoke poll with a timeout of 0 even if the before_sleep() method returned Ok(Some(...)), which means it is possible that poll generates another legit event. We need to document what happens in this case.

What the current implementation does is:

  • before_handle_events() is invoked if a real event was generated, independently of what before_sleep() returned
  • If a real event is generated in addition to the one from before_sleep(), then dispatch_events() is invoked twice.

Imo this is the correct thing to do (to handle composite sources with multiple tokens), but this needs to be documented clearly.

/// code may run. This could be used to drop a lock obtained in
/// [`EventSource::before_sleep`]
#[allow(unused_variables)]
fn before_handle_events(&mut self, was_awoken: bool) {}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if it might be relevant to pass the (Token, Readiness) couple as argument to this, instead of just a was_awoken bool. Again as a way to properly handle composite sources that may have multiple underlying FDs and tokens.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be more precise, I see two ways to achieve this:

  • make the function take as argument Option<(Token, Readiness)>, and say that it is called once with None if no event is received, or once ore more times with Some() if events were triggered
  • make the function take a &dyn Iterator<Item=(Token, Readiness)>> as argument, with that iterator being empty if no event was triggered

///
/// If this returns Ok(Some), this will be treated as an event arriving in polling, and
/// your event handler will be called with the returned `Token` and `Readiness`.
/// Polling will however still occur, so additional events from this or other sources
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Polling will however still occur, but with a timeout of 0

Comment on lines 192 to 193
/// Please note, the iterator will also include any synthetic event returned from
/// [`EventSource::before_sleep`]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we actually want that?

The source can already internally track if it gave a synthetic event or not, and at least for the wayland socket, it'd be more useful in this method to know if other real events occurred during the polling.

In both cases the wayland source will be able to work with it, but it seems to me including the synthetic events in this iterator only increases the complexity of implementing the sources.

@elinorbgr
Copy link
Member

Alright, thanks a lot this is perfect! 👍

@elinorbgr elinorbgr merged commit 6319d81 into Smithay:master Sep 9, 2023
10 of 12 checks passed
@DJMcNab DJMcNab deleted the additional-lifecycle branch September 9, 2023 08:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants