<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>xiio, branch HEAD</title>
<subtitle>really simple async runtime</subtitle>
<entry>
<id>feefa7d576feb55762f29663aef8e7d81d2243ae</id>
<published>2026-04-25T11:44:14Z</published>
<updated>2026-04-25T11:48:38Z</updated>
<title type="text">bump minimum python version to 3.11</title>
<link rel="alternate" type="text/html" href="commit/feefa7d576feb55762f29663aef8e7d81d2243ae.html" />
<author>
<name>Tobias Bengfort</name>
<email>tobias.bengfort@posteo.de</email>
</author>
<content type="text">bump minimum python version to 3.11

asyncio.timeout() is not available before that
</content>
</entry>
<entry>
<id>5750a828cfb92a889a672e3e018ce4c0f1a719b1</id>
<published>2026-04-25T11:35:24Z</published>
<updated>2026-04-25T11:48:29Z</updated>
<title type="text">ci: fix python version</title>
<link rel="alternate" type="text/html" href="commit/5750a828cfb92a889a672e3e018ce4c0f1a719b1.html" />
<author>
<name>Tobias Bengfort</name>
<email>tobias.bengfort@posteo.de</email>
</author>
<content type="text">ci: fix python version
</content>
</entry>
<entry>
<id>c6b5d2af9309c2bb20c737d7bf2e164d23f56de3</id>
<published>2026-04-18T18:59:08Z</published>
<updated>2026-04-22T17:46:27Z</updated>
<title type="text">avoid context switch in thread pool</title>
<link rel="alternate" type="text/html" href="commit/c6b5d2af9309c2bb20c737d7bf2e164d23f56de3.html" />
<author>
<name>Tobias Bengfort</name>
<email>tobias.bengfort@posteo.de</email>
</author>
<content type="text">avoid context switch in thread pool
</content>
</entry>
<entry>
<id>d0bc4771606dc88db648aaa06bd70d87c8929a84</id>
<published>2026-04-16T20:37:03Z</published>
<updated>2026-04-22T17:46:12Z</updated>
<title type="text">TaskGroup: refactor</title>
<link rel="alternate" type="text/html" href="commit/d0bc4771606dc88db648aaa06bd70d87c8929a84.html" />
<author>
<name>Tobias Bengfort</name>
<email>tobias.bengfort@posteo.de</email>
</author>
<content type="text">TaskGroup: refactor

also removes one cancellation point
</content>
</entry>
<entry>
<id>b34bac8ed1f750b2fb8db0a0358826d0593a7b90</id>
<published>2026-04-16T17:16:49Z</published>
<updated>2026-04-22T17:46:12Z</updated>
<title type="text">add ThreadPool and in_thread()</title>
<link rel="alternate" type="text/html" href="commit/b34bac8ed1f750b2fb8db0a0358826d0593a7b90.html" />
<author>
<name>Tobias Bengfort</name>
<email>tobias.bengfort@posteo.de</email>
</author>
<content type="text">add ThreadPool and in_thread()
</content>
</entry>
<entry>
<id>5b257c932b01485db2170c21116f5ef06754b76b</id>
<published>2026-04-12T17:29:25Z</published>
<updated>2026-04-17T20:19:02Z</updated>
<title type="text">reduce test timing precision</title>
<link rel="alternate" type="text/html" href="commit/5b257c932b01485db2170c21116f5ef06754b76b.html" />
<author>
<name>Tobias Bengfort</name>
<email>tobias.bengfort@posteo.de</email>
</author>
<content type="text">reduce test timing precision
</content>
</entry>
<entry>
<id>c383ca69e8b62de8bd033d2b664192d7a70ea35e</id>
<published>2026-04-11T06:56:45Z</published>
<updated>2026-04-17T20:19:02Z</updated>
<title type="text">add on_asyncio() compat function</title>
<link rel="alternate" type="text/html" href="commit/c383ca69e8b62de8bd033d2b664192d7a70ea35e.html" />
<author>
<name>Tobias Bengfort</name>
<email>tobias.bengfort@posteo.de</email>
</author>
<content type="text">add on_asyncio() compat function
</content>
</entry>
<entry>
<id>d241b8a53cab1f54563072f953803756c32cbf02</id>
<published>2026-04-12T16:45:47Z</published>
<updated>2026-04-17T20:19:02Z</updated>
<title type="text">add subscribe_signals()</title>
<link rel="alternate" type="text/html" href="commit/d241b8a53cab1f54563072f953803756c32cbf02.html" />
<author>
<name>Tobias Bengfort</name>
<email>tobias.bengfort@posteo.de</email>
</author>
<content type="text">add subscribe_signals()
</content>
</entry>
<entry>
<id>37911ea6ed293cd987fad904b07ab4b027857604</id>
<published>2026-04-12T13:36:32Z</published>
<updated>2026-04-17T20:19:02Z</updated>
<title type="text">add run_process()</title>
<link rel="alternate" type="text/html" href="commit/37911ea6ed293cd987fad904b07ab4b027857604.html" />
<author>
<name>Tobias Bengfort</name>
<email>tobias.bengfort@posteo.de</email>
</author>
<content type="text">add run_process()

Mostly the same interface as `subprocess.run()` from the standard
library, just async.

Uses a pidfd to integrate into the event loop, so it is linux-specific.

https://docs.python.org/3/library/subprocess.html
https://docs.python.org/3/library/asyncio-subprocess.html
https://trio.readthedocs.io/en/stable/reference-io.html#trio.Process
</content>
</entry>
<entry>
<id>e8447dd8daf816df9be346b112c65e57e538fcd5</id>
<published>2026-04-12T17:21:24Z</published>
<updated>2026-04-17T20:19:02Z</updated>
<title type="text">refactor: split into multiple files</title>
<link rel="alternate" type="text/html" href="commit/e8447dd8daf816df9be346b112c65e57e538fcd5.html" />
<author>
<name>Tobias Bengfort</name>
<email>tobias.bengfort@posteo.de</email>
</author>
<content type="text">refactor: split into multiple files
</content>
</entry>
<entry>
<id>782851e16a4988987e94d22388efb84d2ab988ac</id>
<published>2026-02-27T00:46:27Z</published>
<updated>2026-04-17T20:19:02Z</updated>
<title type="text">add timeout()</title>
<link rel="alternate" type="text/html" href="commit/782851e16a4988987e94d22388efb84d2ab988ac.html" />
<author>
<name>Tobias Bengfort</name>
<email>tobias.bengfort@posteo.de</email>
</author>
<content type="text">add timeout()

Just a higher level abstraction on top of TaskGroup.
</content>
</entry>
<entry>
<id>0df8fb90d90a5f881d9815ac411c82c769ee5a00</id>
<published>2026-02-27T15:55:03Z</published>
<updated>2026-04-17T20:19:02Z</updated>
<title type="text">turn TaskGroup into a context manager</title>
<link rel="alternate" type="text/html" href="commit/0df8fb90d90a5f881d9815ac411c82c769ee5a00.html" />
<author>
<name>Tobias Bengfort</name>
<email>tobias.bengfort@posteo.de</email>
</author>
<content type="text">turn TaskGroup into a context manager

This is wild and I am honestly not 100% sold that this is worth it.

Feature-wise, the main difference from the previous version is that the
subtasks already start executing before the inner block is done.

A similar thing was already possible before by using an additional
function:

```python
async def foo(tg):
    tg.add_task(sleep(1))
    sleep(1)

tg = TaskGroup()
tg.add_task(foo(tg))
await tg
```

But I must admit that the context manager syntax is nicer:

```python
async with TaskGroup() as tg:
    tg.add_task(sleep(1))
    sleep(1)
```

Unfortunately, the implementation is a real mind bender:

When we enter the TaskGroup, we want to wrap the parent task. In order
to do that, we first need to get a reference to it. The way we do that
is a bit hacky: We usually use the async/await syntax to pass conditions
and available files back and forth between the coroutines and our
plumbing. Now we abuse the same system to pass a task into the
coroutine.

Now we put the generator of the coroutine that is currently running in a
new task and add it to the TaskGroup. The parent task instead receives
the generator of the `wrapper()` coroutine.

The next time we await, a condition will be yielded to the parent task,
which now references a completely different generator. In addition, the
task that now wraps this coroutine will never receive the condition.
Fortunately, there is a simple fix: We can await
`Condition(time=-math.inf)` in both coroutines to make everything line
up.

After that switcharoo is done, we can `await self` to wait for the
TaskGroup to complete. As part of that, we will at some point exit the
TaskGroup. At that point we abuse the async/await syntax a second time
to raise an exception, which will finish the task without stopping the
generator.

Once the TaskGroup has finished executing, we can attach the generator
back to the parent task and yield control back to it. It will resume
execution of its original generator inside `__aexit__()`. `wrapper()` is
not referenced anywhere anymore, so it will be garbage collected.
</content>
</entry>
<entry>
<id>d3f5e579b6fc9897910ec87023a14366b298faad</id>
<published>2026-02-26T22:33:19Z</published>
<updated>2026-04-17T20:19:02Z</updated>
<title type="text">add TaskGroup</title>
<link rel="alternate" type="text/html" href="commit/d3f5e579b6fc9897910ec87023a14366b298faad.html" />
<author>
<name>Tobias Bengfort</name>
<email>tobias.bengfort@posteo.de</email>
</author>
<content type="text">add TaskGroup

a more general multiplexing primitive that allows to add tasks after it
has already started.
</content>
</entry>
<entry>
<id>919c743e81d34b2eba2473c60d5026d3290d0679</id>
<published>2026-02-26T23:31:48Z</published>
<updated>2026-04-17T20:19:02Z</updated>
<title type="text">test read/write</title>
<link rel="alternate" type="text/html" href="commit/919c743e81d34b2eba2473c60d5026d3290d0679.html" />
<author>
<name>Tobias Bengfort</name>
<email>tobias.bengfort@posteo.de</email>
</author>
<content type="text">test read/write
</content>
</entry>
<entry>
<id>5395e355f1325dd1a5a621148a18020615e612e6</id>
<published>2026-02-26T22:55:29Z</published>
<updated>2026-04-17T20:19:02Z</updated>
<title type="text">add README</title>
<link rel="alternate" type="text/html" href="commit/5395e355f1325dd1a5a621148a18020615e612e6.html" />
<author>
<name>Tobias Bengfort</name>
<email>tobias.bengfort@posteo.de</email>
</author>
<content type="text">add README
</content>
</entry>
<entry>
<id>47d701f6d787451e3cbb15c5ef1f6dd28ffb617e</id>
<published>2026-02-26T22:15:54Z</published>
<updated>2026-04-17T20:19:02Z</updated>
<title type="text">add gather() for multiplexing</title>
<link rel="alternate" type="text/html" href="commit/47d701f6d787451e3cbb15c5ef1f6dd28ffb617e.html" />
<author>
<name>Tobias Bengfort</name>
<email>tobias.bengfort@posteo.de</email>
</author>
<content type="text">add gather() for multiplexing
</content>
</entry>
<entry>
<id>2ca58a870010e789abb171a8cba9f0547fa1d920</id>
<published>2026-02-26T21:31:55Z</published>
<updated>2026-04-17T20:18:58Z</updated>
<title type="text">allow to combine and check conditions</title>
<link rel="alternate" type="text/html" href="commit/2ca58a870010e789abb171a8cba9f0547fa1d920.html" />
<author>
<name>Tobias Bengfort</name>
<email>tobias.bengfort@posteo.de</email>
</author>
<content type="text">allow to combine and check conditions

We can not multiplex over multiple coroutines yet. To do that, we have
to wait for a combined condition from multiple coroutines, and then
decide which condition is fulfilled so we know which coroutine to
resume. So here we are building the necessary infrastructure.
</content>
</entry>
<entry>
<id>3261d16114cc24b5d12975c008a3a87cf7f98b7c</id>
<published>2026-02-26T21:25:04Z</published>
<updated>2026-04-16T17:34:38Z</updated>
<title type="text">add type annotations</title>
<link rel="alternate" type="text/html" href="commit/3261d16114cc24b5d12975c008a3a87cf7f98b7c.html" />
<author>
<name>Tobias Bengfort</name>
<email>tobias.bengfort@posteo.de</email>
</author>
<content type="text">add type annotations
</content>
</entry>
<entry>
<id>fc000f4a6a23c0aa964652959f2296015a985d76</id>
<published>2026-02-26T22:16:41Z</published>
<updated>2026-04-16T17:33:49Z</updated>
<title type="text">add futures</title>
<link rel="alternate" type="text/html" href="commit/fc000f4a6a23c0aa964652959f2296015a985d76.html" />
<author>
<name>Tobias Bengfort</name>
<email>tobias.bengfort@posteo.de</email>
</author>
<content type="text">add futures

If multiple coroutines are waiting for a message on the same socket, it
can be helpful to have a mechanism to wake up the right one. Futures are
a pure python abstraction that does exactly that.
</content>
</entry>
<entry>
<id>62f05c12a608b69bda7bb5eff30a0be859df96a4</id>
<published>2026-02-26T18:42:02Z</published>
<updated>2026-04-16T17:33:25Z</updated>
<title type="text">add support for reading/writing files</title>
<link rel="alternate" type="text/html" href="commit/62f05c12a608b69bda7bb5eff30a0be859df96a4.html" />
<author>
<name>Tobias Bengfort</name>
<email>tobias.bengfort@posteo.de</email>
</author>
<content type="text">add support for reading/writing files

So far we can wait for timeouts. In a real system, we also want to be
able to wait for files. So we replace the `Timeout` class by a more
generic `Condition` class together with the `sleep()`, `read()` and
`write()` helpers. We use the `selectors` module to wait for files to
become available.
</content>
</entry>
<entry>
<id>8ed7defd595a8e895c90830093d01959b19a03cc</id>
<published>2026-02-26T18:37:21Z</published>
<updated>2026-02-27T00:22:09Z</updated>
<title type="text">async/await syntax</title>
<link rel="alternate" type="text/html" href="commit/8ed7defd595a8e895c90830093d01959b19a03cc.html" />
<author>
<name>Tobias Bengfort</name>
<email>tobias.bengfort@posteo.de</email>
</author>
<content type="text">async/await syntax

This is just an abstraction on top of generators. Our function is now
called a *coroutine*.
</content>
</entry>
<entry>
<id>d39fb2b7a1d88a6447fe62d7206fea21e836dabe</id>
<published>2026-02-26T18:34:19Z</published>
<updated>2026-02-27T00:22:06Z</updated>
<title type="text">allow to pause execution</title>
<link rel="alternate" type="text/html" href="commit/d39fb2b7a1d88a6447fe62d7206fea21e836dabe.html" />
<author>
<name>Tobias Bengfort</name>
<email>tobias.bengfort@posteo.de</email>
</author>
<content type="text">allow to pause execution

The first step is to move the blocking call out of the function. To do
that, we pause execution by using the `yield` keyword. This turns our
function into a generator function. The separate `run()` function will
do the blocking call and resume the generator function once that is
done. The special `StopIteration` exception is raised when the generator
function returns.
</content>
</entry>
<entry>
<id>6b9965a49151195a363b7eb06f53a6379e1102ea</id>
<published>2026-02-27T00:04:20Z</published>
<updated>2026-02-27T00:08:14Z</updated>
<title type="text">simple sync test functions</title>
<link rel="alternate" type="text/html" href="commit/6b9965a49151195a363b7eb06f53a6379e1102ea.html" />
<author>
<name>Tobias Bengfort</name>
<email>tobias.bengfort@posteo.de</email>
</author>
<content type="text">simple sync test functions
</content>
</entry>
</feed>
