GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Keep watching an fd after a poll error on Linux by Ayush701-code-zm · Pull Request #791 · MagicStack/uvloop

Conversation

@Ayush701-code-zm

@Ayush701-code-zm Ayush701-code-zm commented Nov 10, 2026

Copy link
Copy Markdown

Fixes #787

On Linux, libuv reports POLLERR on a polled fd as UV_EBADF after it has stopped the watcher. __on_uvpoll_event passed that to UVPoll._fatal_error, which ran the callbacks once, closed the poll and left the closed UVPoll in Loop._polls. After that the fd was no longer watched, a later add_writer() raised RuntimeError: ... the handler is closed, and re-arming from inside the callback did nothing.

This change makes a poll error behave like asyncio's level-triggered epoll:

  • _on_poll_error runs the reader and writer callbacks as for a ready fd, then restarts the watcher with the current mask if a reader or writer is still set. The callbacks keep being called until they are removed, as in asyncio.
  • If the fd is gone (checked with os.fstat, since restarting a watcher on a closed fd makes libuv abort in epoll_ctl) or uv_poll_start fails, _close_on_error drops the poll from Loop._polls, closes it and reports the error to the exception handler. A later add_reader()/add_writer() then creates a new poll.
  • _fatal_error is unchanged and still used for the start/stop failure paths.

Tests: four Linux-only tests in tests/test_base.py, run for both uvloop and asyncio, based on the reproducers in the issue (writer keeps being called after the read end is closed, add_writer after the error with and without remove_writer, and a callback re-arming itself). They fail on master for uvloop and pass for asyncio; with this change all pass. The full test suite passes locally (Linux x86_64, Python 3.12, bundled libuv 1.53.0).

One thing to note: like asyncio, an fd stuck in an error state now keeps calling its callback every iteration until it is removed. If you'd prefer only the smaller fix (dropping the closed poll from _polls and reporting the error), I can trim it to that.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@Ayush701-code-zm
Keep watching an fd after a poll error on Linux
08c0b0f
On Linux, libuv reports POLLERR to the poll callback as UV_EBADF after
it has stopped the watcher. UVPoll handled this as a fatal error: it
ran the reader and the writer once, dropped them and closed the handle,
which stayed in Loop._polls. The fd was then no longer watched, a later
add_writer() raised RuntimeError and re-arming from the callback did
nothing.

Match asyncio (level-triggered epoll) instead: run the callbacks as for
a ready fd and start the poll again, so they keep being called until
they are removed. If the fd is gone or the restart fails, close the
handle, remove it from Loop._polls so that a later add_reader() or
add_writer() creates a new one, and report the error to the exception
handler.

Fixes MagicStack#787.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

No reviews

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

uvloop stops watching a handle after an error of it on Linux

Uh oh!

There was an error while loading. Please reload this page.

1 participant

@Ayush701-code-zm
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.