Skip to content

Commit

Permalink
Fixed race condition in get_async_backend (#714)
Browse files Browse the repository at this point in the history
Fixes 425.

Co-authored-by: Alex Grönholm <alex.gronholm@nextday.fi>
Co-authored-by: Ganden Schaffner <github@xqzw.me>
  • Loading branch information
3 people committed May 10, 2024
1 parent db21ca7 commit 8e8b7f5
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 6 deletions.
4 changes: 4 additions & 0 deletions docs/versionhistory.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ This library adheres to `Semantic Versioning 2.0 <http://semver.org/>`_.

**UNRELEASED**

- Fixed a race condition that caused crashes when multiple event loops of the same
backend were running in separate threads and simultaneously attempted to use AnyIO for
their first time (`#425 <https://github.com/agronholm/anyio/issues/425>`_; PR by David
Jiricek and Ganden Schaffner)
- Added the ``BlockingPortalProvider`` class to aid with constructing synchronous
counterparts to asynchronous interfaces that would otherwise require multiple blocking
portals
Expand Down
15 changes: 9 additions & 6 deletions src/anyio/_core/_eventloop.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
PosArgsT = TypeVarTuple("PosArgsT")

threadlocals = threading.local()
loaded_backends: dict[str, type[AsyncBackend]] = {}


def run(
Expand Down Expand Up @@ -150,14 +151,16 @@ def claim_worker_thread(
del threadlocals.current_token


def get_async_backend(asynclib_name: str | None = None) -> AsyncBackend:
def get_async_backend(asynclib_name: str | None = None) -> type[AsyncBackend]:
if asynclib_name is None:
asynclib_name = sniffio.current_async_library()

modulename = "anyio._backends._" + asynclib_name
# We use our own dict instead of sys.modules to get the already imported back-end
# class because the appropriate modules in sys.modules could potentially be only
# partially initialized
try:
module = sys.modules[modulename]
return loaded_backends[asynclib_name]
except KeyError:
module = import_module(modulename)

return getattr(module, "backend_class")
module = import_module(f"anyio._backends._{asynclib_name}")
loaded_backends[asynclib_name] = module.backend_class
return module.backend_class

0 comments on commit 8e8b7f5

Please sign in to comment.