Skip to content

Application hangs with the poll-based selector #1874

Open
@t6tb7n

Description

@t6tb7n

The following program hangs indefinitely when using the poll-based Selector:

#[tokio::main(flavor = "current_thread")]
async fn main() {
    let response = reqwest::get("http://www.google.com").await.unwrap().text().await.unwrap();
    println!("{}", response.len());
}

I am primarily targeting QNX Neutrino but experience the same behaviour on Linux with the mio_unsupported_force_poll_poll flag (with or without the mio_unsupported_force_waker_pipe flag).

After some investigations it seems that the problem is happening because the deregistration of the file descriptor associated with the TCP stream erases the still unhandled notification to wake the blocked-on future after the complete HTTP response has been received.

I pinpointed the issue to the modify_fds method in src/sys/unix/selector/poll.rs:

    fn modify_fds<T>(&self, f: impl FnOnce(&mut Fds) -> T) -> T {
        self.waiting_operations.fetch_add(1, Ordering::SeqCst);

        // Wake up the current caller of `wait` if there is one.
        let sent_notification = self.notify_waker.wake().is_ok();

        let mut fds = self.fds.lock().unwrap();

        // If there was no caller of `wait` our notification was not removed from the pipe.
        if sent_notification {
            self.notify_waker.ack_and_reset(); // ERASES PENDING NOTIFICATIONS
        }

        let res = f(&mut *fds);

        if self.waiting_operations.fetch_sub(1, Ordering::SeqCst) == 1 {
            self.operations_complete.notify_one();
        }

        res
    }

The implementation has evolved a bit in the original poll implementation and seems to handle this case correctly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions