From 68a1898e5647c291722aa08c9e281937cbc8eb61 Mon Sep 17 00:00:00 2001 From: "Nathaniel J. Smith" Date: Mon, 4 Sep 2017 02:04:24 -0700 Subject: [PATCH] yield_indefinitely -> wait_task_rescheduled --- docs/source/reference-hazmat.rst | 8 ++++---- trio/__init__.py | 4 ++++ trio/_core/_io_epoll.py | 2 +- trio/_core/_io_kqueue.py | 2 +- trio/_core/_io_windows.py | 4 ++-- trio/_core/_parking_lot.py | 2 +- trio/_core/_run.py | 14 +++++++------- trio/_core/_traps.py | 14 +++++++------- trio/_core/tests/test_ki.py | 8 +++++--- trio/_core/tests/test_run.py | 10 +++++----- trio/_threads.py | 2 +- trio/_timeouts.py | 2 +- trio/tests/test_threads.py | 2 +- trio/tests/test_util.py | 2 +- 14 files changed, 41 insertions(+), 35 deletions(-) diff --git a/docs/source/reference-hazmat.rst b/docs/source/reference-hazmat.rst index 8547ed1600..abc3eeb22b 100644 --- a/docs/source/reference-hazmat.rst +++ b/docs/source/reference-hazmat.rst @@ -398,19 +398,19 @@ make sure that the call always acts as a checkpoint, it calls Low-level blocking ------------------ -.. autofunction:: yield_indefinitely +.. autofunction:: wait_task_rescheduled .. autoclass:: Abort .. autofunction:: reschedule Here's an example lock class implemented using -:func:`yield_indefinitely` directly. This implementation has a number +:func:`wait_task_rescheduled` directly. This implementation has a number of flaws, including lack of fairness, O(n) cancellation, missing error checking, failure to insert a checkpoint on the non-blocking path, etc. If you really want to implement your own lock, then you should study the implementation of :class:`trio.Lock` and use :class:`ParkingLot`, which handles some of these issues for you. But this does serve to illustrate the basic structure of the -:func:`yield_indefinitely` API:: +:func:`wait_task_rescheduled` API:: class NotVeryGoodLock: def __init__(self): @@ -424,7 +424,7 @@ this does serve to illustrate the basic structure of the def abort_fn(_): self._blocked_tasks.remove(task) return trio.hazmat.Abort.SUCCEEDED - await trio.hazmat.yield_indefinitely(abort_fn) + await trio.hazmat.wait_task_rescheduled(abort_fn) self._held = True def release(self): diff --git a/trio/__init__.py b/trio/__init__.py index a64ccb67b8..c82ca81e0e 100644 --- a/trio/__init__.py +++ b/trio/__init__.py @@ -115,6 +115,10 @@ _deprecate.DeprecatedAttribute( hazmat.checkpoint_if_cancelled, "0.2.0", issue=157 ), + "yield_indefinitely": + _deprecate.DeprecatedAttribute( + hazmat.wait_task_rescheduled, "0.2.0", issue=157 + ), } # Having the public path in .__module__ attributes is important for: diff --git a/trio/_core/_io_epoll.py b/trio/_core/_io_epoll.py index 1965ce6cda..bb720d0029 100644 --- a/trio/_core/_io_epoll.py +++ b/trio/_core/_io_epoll.py @@ -113,7 +113,7 @@ def abort(_): self._update_registrations(fd, True) return _core.Abort.SUCCEEDED - await _core.yield_indefinitely(abort) + await _core.wait_task_rescheduled(abort) @_public @_hazmat diff --git a/trio/_core/_io_kqueue.py b/trio/_core/_io_kqueue.py index 719230be01..9715b76d3d 100644 --- a/trio/_core/_io_kqueue.py +++ b/trio/_core/_io_kqueue.py @@ -111,7 +111,7 @@ def abort(raise_cancel): del self._registered[key] return r - return await _core.yield_indefinitely(abort) + return await _core.wait_task_rescheduled(abort) async def _wait_common(self, fd, filter): if not isinstance(fd, int): diff --git a/trio/_core/_io_windows.py b/trio/_core/_io_windows.py index ab3fe4b23e..cc214ae399 100644 --- a/trio/_core/_io_windows.py +++ b/trio/_core/_io_windows.py @@ -328,7 +328,7 @@ def abort(raise_cancel_): _check(kernel32.CancelIoEx(handle, lpOverlapped)) return _core.Abort.FAILED - await _core.yield_indefinitely(abort) + await _core.wait_task_rescheduled(abort) if lpOverlapped.Internal != 0: if lpOverlapped.Internal == ErrorCodes.ERROR_OPERATION_ABORTED: assert raise_cancel is not None @@ -373,7 +373,7 @@ def abort(_): del self._socket_waiters[which][sock] return _core.Abort.SUCCEEDED - await _core.yield_indefinitely(abort) + await _core.wait_task_rescheduled(abort) @_public @_hazmat diff --git a/trio/_core/_parking_lot.py b/trio/_core/_parking_lot.py index 1d3c00b22c..a2205e8ace 100644 --- a/trio/_core/_parking_lot.py +++ b/trio/_core/_parking_lot.py @@ -137,7 +137,7 @@ async def park(self): """ task = _core.current_task() self._parked[task] = None - await _core.yield_indefinitely(self._abort_func_for(task)) + await _core.wait_task_rescheduled(self._abort_func_for(task)) def _pop_several(self, count): for _ in range(min(count, len(self._parked))): diff --git a/trio/_core/_run.py b/trio/_core/_run.py index b6e37e4b24..1261cf1f34 100644 --- a/trio/_core/_run.py +++ b/trio/_core/_run.py @@ -27,7 +27,7 @@ from ._traps import ( cancel_shielded_checkpoint, Abort, - yield_indefinitely, + wait_task_rescheduled, YieldBrieflyNoCancel, YieldIndefinitely, ) @@ -829,18 +829,18 @@ def reschedule(self, task, next_send=Value(None)): """Reschedule the given task with the given :class:`~trio.hazmat.Result`. - See :func:`yield_indefinitely` for the gory details. + See :func:`wait_task_rescheduled` for the gory details. There must be exactly one call to :func:`reschedule` for every call to - :func:`yield_indefinitely`. (And when counting, keep in mind that + :func:`wait_task_rescheduled`. (And when counting, keep in mind that returning :data:`Abort.SUCCEEDED` from an abort callback is equivalent to calling :func:`reschedule` once.) Args: task (trio.hazmat.Task): the task to be rescheduled. Must be blocked - in a call to :func:`yield_indefinitely`. + in a call to :func:`wait_task_rescheduled`. next_send (trio.hazmat.Result): the value (or error) to return (or - raise) from :func:`yield_indefinitely`. + raise) from :func:`wait_task_rescheduled`. """ assert task._runner is self @@ -1341,7 +1341,7 @@ def abort(_): del self.waiting_for_idle[key] return Abort.SUCCEEDED - await yield_indefinitely(abort) + await wait_task_rescheduled(abort) ################ # Instrumentation @@ -1756,7 +1756,7 @@ async def checkpoint(): """ with open_cancel_scope(deadline=-inf) as scope: - await _core.yield_indefinitely(lambda _: _core.Abort.SUCCEEDED) + await _core.wait_task_rescheduled(lambda _: _core.Abort.SUCCEEDED) @_hazmat diff --git a/trio/_core/_traps.py b/trio/_core/_traps.py index defac17bb0..2914b72740 100644 --- a/trio/_core/_traps.py +++ b/trio/_core/_traps.py @@ -8,7 +8,7 @@ from . import _hazmat -__all__ = ["cancel_shielded_checkpoint", "Abort", "yield_indefinitely"] +__all__ = ["cancel_shielded_checkpoint", "Abort", "wait_task_rescheduled"] # Decorator to turn a generator into a well-behaved async function: @@ -53,7 +53,7 @@ def cancel_shielded_checkpoint(): class Abort(enum.Enum): """:class:`enum.Enum` used as the return value from abort functions. - See :func:`yield_indefinitely` for details. + See :func:`wait_task_rescheduled` for details. .. data:: SUCCEEDED FAILED @@ -71,7 +71,7 @@ class YieldIndefinitely: @_hazmat @asyncfunction -def yield_indefinitely(abort_func): +def wait_task_rescheduled(abort_func): """Put the current task to sleep, with cancellation support. This is the lowest-level API for blocking in trio. Every time a @@ -85,7 +85,7 @@ def yield_indefinitely(abort_func): arrangements for "someone" to call :func:`reschedule` on the current task at some later point. - Then you call :func:`yield_indefinitely`, passing in ``abort_func``, an + Then you call :func:`wait_task_rescheduled`, passing in ``abort_func``, an "abort callback". (Terminology: in trio, "aborting" is the process of attempting to @@ -94,7 +94,7 @@ def yield_indefinitely(abort_func): There are two possibilities for what happens next: 1. "Someone" calls :func:`reschedule` on the current task, and - :func:`yield_indefinitely` returns or raises whatever value or error + :func:`wait_task_rescheduled` returns or raises whatever value or error was passed to :func:`reschedule`. 2. The call's context transitions to a cancelled state (e.g. due to a @@ -145,13 +145,13 @@ def abort(inner_raise_cancel): outer_raise_cancel = inner_raise_cancel TRY_TO_CANCEL_OPERATION() return trio.hazmat.Abort.FAILED - await yield_indefinitely(abort) + await wait_task_rescheduled(abort) if OPERATION_WAS_SUCCESSFULLY_CANCELLED: # raises the error outer_raise_cancel() In any case it's guaranteed that we only call the ``abort_func`` at most - once per call to :func:`yield_indefinitely`. + once per call to :func:`wait_task_rescheduled`. .. warning:: diff --git a/trio/_core/tests/test_ki.py b/trio/_core/tests/test_ki.py index 5372cd077e..4e9486d80d 100644 --- a/trio/_core/tests/test_ki.py +++ b/trio/_core/tests/test_ki.py @@ -225,7 +225,9 @@ async def raiser(name, record): # If we didn't raise (b/c protected), then we *should* get # cancelled at the next opportunity try: - await _core.yield_indefinitely(lambda _: _core.Abort.SUCCEEDED) + await _core.wait_task_rescheduled( + lambda _: _core.Abort.SUCCEEDED + ) except _core.Cancelled: record.add((name + " cancel ok")) @@ -335,7 +337,7 @@ def abort(_): _core.reschedule(task, _core.Value(1)) return _core.Abort.FAILED - assert await _core.yield_indefinitely(abort) == 1 + assert await _core.wait_task_rescheduled(abort) == 1 with pytest.raises(KeyboardInterrupt): await _core.checkpoint() @@ -356,7 +358,7 @@ def abort(raise_cancel): return _core.Abort.FAILED with pytest.raises(KeyboardInterrupt): - assert await _core.yield_indefinitely(abort) + assert await _core.wait_task_rescheduled(abort) await _core.checkpoint() _core.run(main) diff --git a/trio/_core/tests/test_run.py b/trio/_core/tests/test_run.py index 513463d750..32f973e1dd 100644 --- a/trio/_core/tests/test_run.py +++ b/trio/_core/tests/test_run.py @@ -26,7 +26,7 @@ # its rescheduled with, which is really only useful for tests of # rescheduling... async def sleep_forever(): - return await _core.yield_indefinitely(lambda _: _core.Abort.SUCCEEDED) + return await _core.wait_task_rescheduled(lambda _: _core.Abort.SUCCEEDED) # Some of our tests need to leak coroutines, and thus trigger the @@ -949,7 +949,7 @@ async def stubborn_sleeper(): with _core.open_cancel_scope() as scope: stubborn_scope[0] = scope record.append("sleep") - x = await _core.yield_indefinitely(lambda _: _core.Abort.FAILED) + x = await _core.wait_task_rescheduled(lambda _: _core.Abort.FAILED) assert x == 1 record.append("woke") try: @@ -985,7 +985,7 @@ async def main(): with _core.open_cancel_scope() as scope: scope.cancel() # None is not a legal return value here - await _core.yield_indefinitely(lambda _: None) + await _core.wait_task_rescheduled(lambda _: None) with pytest.raises(_core.TrioInternalError): _core.run(main) @@ -1447,7 +1447,7 @@ def slow_abort(raise_cancel): call_soon(_core.reschedule, task, result) return _core.Abort.FAILED - await _core.yield_indefinitely(slow_abort) + await _core.wait_task_rescheduled(slow_abort) async def test_slow_abort_edge_cases(): @@ -1465,7 +1465,7 @@ def slow_abort(raise_cancel): with pytest.raises(_core.Cancelled): record.append("sleeping") - await _core.yield_indefinitely(slow_abort) + await _core.wait_task_rescheduled(slow_abort) record.append("cancelled") # blocking again, this time it's okay, because we're shielded await _core.checkpoint() diff --git a/trio/_threads.py b/trio/_threads.py index 38cdc2b74c..752ffaf8cd 100644 --- a/trio/_threads.py +++ b/trio/_threads.py @@ -338,4 +338,4 @@ def abort(_): else: return _core.Abort.FAILED - return await _core.yield_indefinitely(abort) + return await _core.wait_task_rescheduled(abort) diff --git a/trio/_timeouts.py b/trio/_timeouts.py index 0deaa4970a..1437f9f9f6 100644 --- a/trio/_timeouts.py +++ b/trio/_timeouts.py @@ -48,7 +48,7 @@ async def sleep_forever(): Equivalent to calling ``await sleep(math.inf)``. """ - await _core.yield_indefinitely(lambda _: _core.Abort.SUCCEEDED) + await _core.wait_task_rescheduled(lambda _: _core.Abort.SUCCEEDED) async def sleep_until(deadline): diff --git a/trio/tests/test_threads.py b/trio/tests/test_threads.py index 60da5c8008..47e84847d4 100644 --- a/trio/tests/test_threads.py +++ b/trio/tests/test_threads.py @@ -145,7 +145,7 @@ def test_await_in_trio_thread_while_main_exits(): async def trio_fn(): record.append("sleeping") ev.set() - await _core.yield_indefinitely(lambda _: _core.Abort.SUCCEEDED) + await _core.wait_task_rescheduled(lambda _: _core.Abort.SUCCEEDED) def thread_fn(await_in_trio_thread): try: diff --git a/trio/tests/test_util.py b/trio/tests/test_util.py index 09ac5aa67f..b0c273c873 100644 --- a/trio/tests/test_util.py +++ b/trio/tests/test_util.py @@ -169,6 +169,6 @@ def test_module_metadata_is_fixed_up(): assert trio.open_cancel_scope.__module__ == "trio" assert trio.ssl.SSLStream.__module__ == "trio.ssl" assert trio.abc.Stream.__module__ == "trio.abc" - assert trio.hazmat.yield_indefinitely.__module__ == "trio.hazmat" + assert trio.hazmat.wait_task_rescheduled.__module__ == "trio.hazmat" import trio.testing assert trio.testing.trio_test.__module__ == "trio.testing"