MagicStack / MagicStack/uvloop
inconsistent file descriptor blocking state when running in asyncio vs uvloop
Nobody has claimed this yet.
- Dominant language
- Cython
- Stars
- 11.9k
- Forks
- 616
- PR merge metrics
- No merged PRs in 30d
Description
When running under uvloop, registering `stdin`, `stdout`, or `stderr` with `loop.add_reader()` / `loop.add_writer()` implicitly changes their blocking mode from blocking to non-blocking. This behaviour does not occur under the standard asyncio selector event loop.
This is causing some issues when running with rich/promptkit in [fast-agent](https://github.com/evalstate/fast-agent)
Under the following test code
```python
import anyio
import sys
import os
import asyncio
async def main():
loop = asyncio.get_running_loop()
print(f"Using event loop: {type(loop)}")
stdin = sys.stdin.fileno()
stdout = sys.stdout.fileno()
stderr = sys.stderr.fileno()
print(f"initial:\tstdin fd: {stdin}, stdout fd: {stdout}, stderr fd: {stderr}")
print(f"blocking:\tstdin fd: {os.get_blocking(stdin)}, stdout fd: {os.get_blocking(stdout)}, stderr fd: {os.get_blocking(stderr)}")
loop.add_writer(stdin, lambda: None)
loop.add_writer(stdout, lambda: None)
loop.add_writer(stderr, lambda: None)
print(f"writer: \tstdin fd: {stdin}, stdout fd: {stdout}, stderr fd: {stderr}")
print(f"blocking:\tstdin fd: {os.get_blocking(stdin)}, stdout fd: {os.get_blocking(stdout)}, stderr fd: {os.get_blocking(stderr)}")
loop.add_reader(stdin, lambda: None)
loop.add_reader(stdout, lambda: None)
loop.add_reader(stderr, lambda: None)
print(f"reader: \tstdin fd: {stdin}, stdout fd: {stdout}, stderr fd: {stderr}")
print(f"blocking:\tstdin fd: {os.get_blocking(stdin)}, stdout fd: {os.get_blocking(stdout)}, stderr fd: {os.get_blocking(stderr)}")
anyio.run(main, backend="asyncio", backend_options={"use_uvloop": False})
print("-" * 40)
anyio.run(main, backend="asyncio", backend_options={"use_uvloop": True})
```
I see the following output, where the blocking status of the stdio file descriptors are changed from blocking to non blocking when running under uvloop but not asyncio.
```
Using event loop:
initial: stdin fd: 0, stdout fd: 1, stderr fd: 2
blocking: stdin fd: True, stdout fd: True, stderr fd: True
writer: stdin fd: 0, stdout fd: 1, stderr fd: 2
blocking: stdin fd: True, stdout fd: True, stderr fd: True
reader: stdin fd: 0, stdout fd: 1, stderr fd: 2
blocking: stdin fd: True, stdout fd: True, stderr fd: True
----------------------------------------
Using event loop:
initial: stdin fd: 0, stdout fd: 1, stderr fd: 2
blocking: stdin fd: True, stdout fd: True, stderr fd: True
writer: stdin fd: 0, stdout fd: 1, stderr fd: 2
blocking: stdin fd: False, stdout fd: False, stderr fd: False
reader: stdin fd: 0, stdout fd: 1, stderr fd: 2
blocking: stdin fd: False, stdout fd: False, stderr fd: False
```
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by running the supplied asyncio versus uvloop reproduction and inspect the uvloop entry points for loop.add_reader() and loop.add_writer(). Compare their file-descriptor handling with the standard asyncio selector loop; done means registering stdin, stdout, and stderr preserves their blocking state under uvloop.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- operating-systems
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100