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]

`