From 41a298ad6bd4afc7f8806b853d75b5877eb0e378 Mon Sep 17 00:00:00 2001 From: jakkdl Date: Mon, 2 Sep 2024 16:34:28 +0200 Subject: [PATCH] raise BrokenResourceError if lock owner has exited. --- src/trio/_sync.py | 9 +++++++++ src/trio/_tests/test_sync.py | 29 +++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/src/trio/_sync.py b/src/trio/_sync.py index 698716ea35..3eefe3ab96 100644 --- a/src/trio/_sync.py +++ b/src/trio/_sync.py @@ -1,5 +1,6 @@ from __future__ import annotations +import inspect import math from typing import TYPE_CHECKING, Protocol @@ -571,11 +572,19 @@ def acquire_nowait(self) -> None: """ task = trio.lowlevel.current_task() + if self._owner is task: raise RuntimeError("attempt to re-acquire an already held Lock") elif self._owner is None and not self._lot: # No-one owns it self._owner = task + elif ( + self._owner is not None + and inspect.getcoroutinestate(self._owner.coro) is inspect.CORO_CLOSED + ): + raise trio.BrokenResourceError( + "Attempted acquire on Lock which will never be released, owner has exited.", + ) else: raise trio.WouldBlock diff --git a/src/trio/_tests/test_sync.py b/src/trio/_tests/test_sync.py index caf3f04f5b..32f7ddca39 100644 --- a/src/trio/_tests/test_sync.py +++ b/src/trio/_tests/test_sync.py @@ -6,6 +6,7 @@ import pytest from .. import _core +from .._core._tests.tutil import slow from .._sync import * from .._timeouts import sleep_forever from ..testing import assert_checkpoints, wait_all_tasks_blocked @@ -586,3 +587,31 @@ async def lock_taker() -> None: await wait_all_tasks_blocked() assert record == ["started"] lock_like.release() + + +async def test_lock_acquire_unowned_lock() -> None: + """Test that trying to acquire a lock whose owner has exited raises an error. + Partial fix for https://github.com/python-trio/trio/issues/3035 + """ + lock = trio.Lock() + async with trio.open_nursery() as nursery: + nursery.start_soon(lock.acquire) + with pytest.raises( + trio.BrokenResourceError, + match="^Attempted acquire on Lock which will never be released, owner has exited.$", + ): + await lock.acquire() + + +@slow +async def test_lock_multiple_acquire() -> None: + """This currently hangs without throwing any error + See https://github.com/python-trio/trio/issues/3035 + """ + lock = trio.Lock() + with pytest.raises(trio.TooSlowError): + with trio.fail_after(1): + async with trio.open_nursery() as nursery: + nursery.start_soon(lock.acquire) + # this should probably raise trio.BrokenResourceError + nursery.start_soon(lock.acquire)