bpo-46771: Implement task cancel requests counter (GH-31513) · python/cpython@7fce106 (original) (raw)
`@@ -91,7 +91,7 @@ typedef struct {
`
91
91
`PyObject *task_context;
`
92
92
`int task_must_cancel;
`
93
93
`int task_log_destroy_pending;
`
94
``
`-
int task_cancel_requested;
`
``
94
`+
int task_num_cancels_requested;
`
95
95
`} TaskObj;
`
96
96
``
97
97
`typedef struct {
`
`@@ -2036,7 +2036,7 @@ _asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop,
`
2036
2036
`Py_CLEAR(self->task_fut_waiter);
`
2037
2037
`self->task_must_cancel = 0;
`
2038
2038
`self->task_log_destroy_pending = 1;
`
2039
``
`-
self->task_cancel_requested = 0;
`
``
2039
`+
self->task_num_cancels_requested = 0;
`
2040
2040
`Py_INCREF(coro);
`
2041
2041
`Py_XSETREF(self->task_coro, coro);
`
2042
2042
``
`@@ -2191,22 +2191,24 @@ not return True (unless the task was already cancelled). A
`
2191
2191
`task will be marked as cancelled when the wrapped coroutine
`
2192
2192
`terminates with a CancelledError exception (even if cancel()
`
2193
2193
`was not called).
`
``
2194
+
``
2195
`+
This also increases the task's count of cancellation requests.
`
2194
2196
`[clinic start generated code]*/
`
2195
2197
``
2196
2198
`static PyObject *
`
2197
2199
`_asyncio_Task_cancel_impl(TaskObj *self, PyObject *msg)
`
2198
``
`-
/[clinic end generated code: output=c66b60d41c74f9f1 input=f4ff8e8ffc5f1c00]/
`
``
2200
`+
/[clinic end generated code: output=c66b60d41c74f9f1 input=7bb51bf25974c783]/
`
2199
2201
`{
`
2200
2202
`self->task_log_tb = 0;
`
2201
2203
``
2202
2204
`if (self->task_state != STATE_PENDING) {
`
2203
2205
`Py_RETURN_FALSE;
`
2204
2206
` }
`
2205
2207
``
2206
``
`-
if (self->task_cancel_requested) {
`
``
2208
`+
self->task_num_cancels_requested += 1;
`
``
2209
`+
if (self->task_num_cancels_requested > 1) {
`
2207
2210
`Py_RETURN_FALSE;
`
2208
2211
` }
`
2209
``
`-
self->task_cancel_requested = 1;
`
2210
2212
``
2211
2213
`if (self->task_fut_waiter) {
`
2212
2214
`PyObject *res;
`
`@@ -2238,51 +2240,40 @@ _asyncio_Task_cancel_impl(TaskObj *self, PyObject *msg)
`
2238
2240
`/*[clinic input]
`
2239
2241
`_asyncio.Task.cancelling
`
2240
2242
``
2241
``
`-
Return True if the task is in the process of being cancelled.
`
2242
``
-
2243
``
`-
This is set once .cancel() is called
`
2244
``
`-
and remains set until .uncancel() is called.
`
``
2243
`+
Return the count of the task's cancellation requests.
`
2245
2244
``
2246
``
`-
As long as this flag is set, further .cancel() calls will be ignored,
`
2247
``
`-
until .uncancel() is called to reset it.
`
``
2245
`+
This count is incremented when .cancel() is called
`
``
2246
`+
and may be decremented using .uncancel().
`
2248
2247
`[clinic start generated code]*/
`
2249
2248
``
2250
2249
`static PyObject *
`
2251
2250
`_asyncio_Task_cancelling_impl(TaskObj *self)
`
2252
``
`-
/[clinic end generated code: output=803b3af96f917d7e input=c50e50f9c3ca4676]/
`
``
2251
`+
/[clinic end generated code: output=803b3af96f917d7e input=b625224d310cbb17]/
`
2253
2252
`/[clinic end generated code]/
`
2254
2253
`{
`
2255
``
`-
if (self->task_cancel_requested) {
`
2256
``
`-
Py_RETURN_TRUE;
`
2257
``
`-
}
`
2258
``
`-
else {
`
2259
``
`-
Py_RETURN_FALSE;
`
2260
``
`-
}
`
``
2254
`+
return PyLong_FromLong(self->task_num_cancels_requested);
`
2261
2255
`}
`
2262
2256
``
2263
2257
`/*[clinic input]
`
2264
2258
`_asyncio.Task.uncancel
`
2265
2259
``
2266
``
`-
Reset the flag returned by cancelling().
`
``
2260
`+
Decrement the task's count of cancellation requests.
`
2267
2261
``
2268
2262
`This should be used by tasks that catch CancelledError
`
2269
2263
`and wish to continue indefinitely until they are cancelled again.
`
2270
2264
``
2271
``
`-
Returns the previous value of the flag.
`
``
2265
`+
Returns the remaining number of cancellation requests.
`
2272
2266
`[clinic start generated code]*/
`
2273
2267
``
2274
2268
`static PyObject *
`
2275
2269
`_asyncio_Task_uncancel_impl(TaskObj *self)
`
2276
``
`-
/[clinic end generated code: output=58184d236a817d3c input=5db95e28fcb6f7cd]/
`
``
2270
`+
/[clinic end generated code: output=58184d236a817d3c input=68f81a4b90b46be2]/
`
2277
2271
`/[clinic end generated code]/
`
2278
2272
`{
`
2279
``
`-
if (self->task_cancel_requested) {
`
2280
``
`-
self->task_cancel_requested = 0;
`
2281
``
`-
Py_RETURN_TRUE;
`
2282
``
`-
}
`
2283
``
`-
else {
`
2284
``
`-
Py_RETURN_FALSE;
`
``
2273
`+
if (self->task_num_cancels_requested > 0) {
`
``
2274
`+
self->task_num_cancels_requested -= 1;
`
2285
2275
` }
`
``
2276
`+
return PyLong_FromLong(self->task_num_cancels_requested);
`
2286
2277
`}
`
2287
2278
``
2288
2279
`/*[clinic input]
`