smol-rs / polling

Portable interface to epoll, kqueue, event ports, and wepoll
Apache License 2.0
551 stars 68 forks source link

Handle interrupts while polling #164

Closed notgull closed 1 year ago

notgull commented 1 year ago

Previous, Poller::wait would bubble signal interruption error to the user. However, this may be unexpected for simple use cases. Thus, this commit makes it so, if ErrorKind::Interrupted is received by the underlying wait() call, it clears the events and tries to wait again.

This also adds a test for this interruption written by @psychon.

Closes #162

psychon commented 1 year ago

I would claim that this mis-handles timeouts. A poll with a timeout of one second can now run infinitely long (although this is quite unlikely):

I would propose:

diff --git a/src/lib.rs b/src/lib.rs
index 9882c8e..8078ee1 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -652,7 +652,14 @@ impl Poller {

         if let Ok(_lock) = self.lock.try_lock() {
             // Wait for I/O events.
-            self.poller.wait(&mut events.events, timeout)?;
+            match self.poller.wait(&mut events.events, timeout) {
+                Ok(()) => {}
+                // Turn interruption into a spurious wakeup without errors
+                Err(e) if e.kind() == io::ErrorKind::Interrupted => {
+                    events.clear();
+                },
+                Err(e) => return Err(e),
+            };

             // Clear the notification, if any.
             self.notified.swap(false, Ordering::SeqCst);
fogti commented 1 year ago

An alternative would be to only do this if no timeout was given (because spurious/non-action wakeups need to be handled anyways when using timeouts usually)