Skip to content

thread_aio: stop the thread pool on close(), bump Free Threading classifier to Beta - #74

Merged
mosquito merged 1 commit into
masterfrom
thread-aio-close-and-ft-beta
Aug 4, 2026
Merged

thread_aio: stop the thread pool on close(), bump Free Threading classifier to Beta#74
mosquito merged 1 commit into
masterfrom
thread-aio-close-and-ft-beta

Conversation

@mosquito

@mosquito mosquito commented Aug 4, 2026

Copy link
Copy Markdown
Owner

Summary

  • thread_aio.Context had no close() at all - the native thread pool only stopped on dealloc, so AsyncioContextBase.close()/async with on thread_aio_asyncio.AsyncioContext was a silent no-op and the pool kept running until GC. Added an explicit, idempotent close() (submit() after it raises RuntimeError) and wired it into thread_aio_asyncio.AsyncioContext._destroy_context, matching python_aio's close() and the loop-detach behavior already present for linux_aio/linux_uring.
  • The pool-pointer swap in close()/dealloc() and the dispatch loop in submit() now share one per-object critical section (CAIO_BEGIN/END_CRITICAL_SECTION) so a concurrent close() can't race a concurrent submit() into using a pool that's being torn down - a no-op under the GIL, a real per-object lock under free-threaded builds.
  • Bumped Programming Language :: Python :: Free Threading classifier from 1 - Unstable to 2 - Beta.

Test plan

  • uv run pytest --cov=caio --cov-report=term-missing tests - 78 passed (macOS, no linux_aio/linux_uring)
  • ruff check / mypy clean on changed files
  • Full suite run against a real free-threaded python3.14t interpreter on Linux (sys._is_gil_enabled() is False) - 741 passed, 0 failed, all 4 backends including test_free_threading.py
  • Manual check: Context(pool_size=8) spins up 8 real OS threads (/proc/pid/task), close() tears them back down to 1; submit() after close() raises RuntimeError; linux_uring's eventfd reader is removed from the event loop after AsyncioContext.close()

Context.close() is now explicit and idempotent (submit() after it raises
RuntimeError), wired into thread_aio_asyncio's _destroy_context to match
python_aio and the loop-detach the other backends already do on close().

The pool-pointer swap and submit()'s dispatch loop share one per-object
critical section, so a concurrent close() can't race a concurrent
submit() into using a pool mid-teardown - a no-op under the GIL, a real
lock under free-threaded builds. Verified against a real free-threaded
3.14 interpreter on Linux (all 4 backends green); bumped the Free
Threading classifier to 2 - Beta.
@mosquito
mosquito force-pushed the thread-aio-close-and-ft-beta branch from 623540a to 080b1c0 Compare August 4, 2026 14:38
@mosquito
mosquito merged commit a146688 into master Aug 4, 2026
20 of 21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant