bpo-38248: Fix inconsistent immediate asyncio.Task cancellation (GH-1… · python/cpython@edad4d8

4 files changed

lines changed

Original file line numberDiff line numberDiff line change

@@ -284,7 +284,7 @@ def __step(self, exc=None):

284284

if self._must_cancel:

285285

# Task is cancelled right before coro stops.

286286

self._must_cancel = False

287-

super().set_exception(exceptions.CancelledError())

287+

super().cancel()

288288

else:

289289

super().set_result(exc.value)

290290

except exceptions.CancelledError:

Original file line numberDiff line numberDiff line change

@@ -604,9 +604,11 @@ async def task():

604604

return 12

605605
606606

t = self.new_task(loop, task())

607+

self.assertFalse(t.cancelled())

607608

self.assertRaises(

608609

asyncio.CancelledError, loop.run_until_complete, t)

609610

self.assertTrue(t.done())

611+

self.assertTrue(t.cancelled())

610612

self.assertFalse(t._must_cancel) # White-box test.

611613

self.assertFalse(t.cancel())

612614

@@ -621,9 +623,11 @@ async def task():

621623

return 12

622624
623625

t = self.new_task(loop, task())

626+

self.assertFalse(t.cancelled())

624627

self.assertRaises(

625628

asyncio.CancelledError, loop.run_until_complete, t)

626629

self.assertTrue(t.done())

630+

self.assertTrue(t.cancelled())

627631

self.assertFalse(t._must_cancel) # White-box test.

628632

self.assertFalse(t.cancel())

629633
Original file line numberDiff line numberDiff line change

@@ -0,0 +1 @@

1+

asyncio: Fix inconsistent immediate Task cancellation

Original file line numberDiff line numberDiff line change

@@ -2628,18 +2628,19 @@ task_step_impl(TaskObj *task, PyObject *exc)

26282628

if (_PyGen_FetchStopIterationValue(&o) == 0) {

26292629

/* The error is StopIteration and that means that

26302630

the underlying coroutine has resolved */

2631+
2632+

PyObject *res;

26312633

if (task->task_must_cancel) {

26322634

// Task is cancelled right before coro stops.

2633-

Py_DECREF(o);

26342635

task->task_must_cancel = 0;

2635-

et = asyncio_CancelledError;

2636-

Py_INCREF(et);

2637-

ev = NULL;

2638-

tb = NULL;

2639-

goto set_exception;

2636+

res = future_cancel((FutureObj*)task);

2637+

}

2638+

else {

2639+

res = future_set_result((FutureObj*)task, o);

26402640

}

2641-

PyObject *res = future_set_result((FutureObj*)task, o);

2641+
26422642

Py_DECREF(o);

2643+
26432644

if (res == NULL) {

26442645

return NULL;

26452646

}