@@ -26,7 +26,6 @@ _Py_IDENTIFIER(_wakeup);
26
26
/* State of the _asyncio module */
27
27
static PyObject * asyncio_mod ;
28
28
static PyObject * inspect_isgenerator ;
29
- static PyObject * os_getpid ;
30
29
static PyObject * traceback_extract_stack ;
31
30
static PyObject * asyncio_get_event_loop_policy ;
32
31
static PyObject * asyncio_future_repr_info_func ;
@@ -38,6 +37,9 @@ static PyObject *asyncio_InvalidStateError;
38
37
static PyObject * asyncio_CancelledError ;
39
38
static PyObject * context_kwname ;
40
39
40
+ static PyObject * cached_running_holder ;
41
+ static volatile uint64_t cached_running_holder_tsid ;
42
+
41
43
42
44
/* WeakSet containing all alive tasks. */
43
45
static PyObject * all_tasks ;
@@ -95,9 +97,18 @@ typedef struct {
95
97
TaskObj * ww_task ;
96
98
} TaskWakeupMethWrapper ;
97
99
100
+ typedef struct {
101
+ PyObject_HEAD
102
+ PyObject * rl_loop ;
103
+ #if defined(HAVE_GETPID ) && !defined(MS_WINDOWS )
104
+ pid_t rl_pid ;
105
+ #endif
106
+ } PyRunningLoopHolder ;
107
+
98
108
99
109
static PyTypeObject FutureType ;
100
110
static PyTypeObject TaskType ;
111
+ static PyTypeObject PyRunningLoopHolder_Type ;
101
112
102
113
103
114
#define Future_CheckExact (obj ) (Py_TYPE(obj) == &FutureType)
@@ -116,9 +127,11 @@ class _asyncio.Future "FutureObj *" "&Future_Type"
116
127
117
128
118
129
/* Get FutureIter from Future */
119
- static PyObject * future_new_iter (PyObject * );
130
+ static PyObject * future_new_iter (PyObject * );
120
131
static inline int future_call_schedule_callbacks (FutureObj * );
121
132
133
+ static PyRunningLoopHolder * new_running_loop_holder (PyObject * );
134
+
122
135
123
136
static int
124
137
_is_coroutine (PyObject * coro )
@@ -214,60 +227,57 @@ get_future_loop(PyObject *fut)
214
227
static int
215
228
get_running_loop (PyObject * * loop )
216
229
{
217
- PyObject * ts_dict ;
218
- PyObject * running_tuple ;
219
- PyObject * running_loop ;
220
- PyObject * running_loop_pid ;
221
- PyObject * current_pid ;
222
- int same_pid ;
230
+ PyObject * rl ;
223
231
224
- ts_dict = PyThreadState_GetDict (); // borrowed
225
- if (ts_dict == NULL ) {
226
- PyErr_SetString (
227
- PyExc_RuntimeError , "thread-local storage is not available" );
228
- goto error ;
232
+ PyThreadState * ts = PyThreadState_Get ();
233
+ if (ts -> id == cached_running_holder_tsid && cached_running_holder != NULL ) {
234
+ // Fast path, check the cache.
235
+ rl = cached_running_holder ; // borrowed
229
236
}
237
+ else {
238
+ if (ts -> dict == NULL ) {
239
+ goto not_found ;
240
+ }
230
241
231
- running_tuple = _PyDict_GetItemId (
232
- ts_dict , & PyId___asyncio_running_event_loop__ ); // borrowed
233
- if (running_tuple == NULL ) {
234
- /* _PyDict_GetItemId doesn't set an error if key is not found */
235
- goto not_found ;
242
+ rl = _PyDict_GetItemIdWithError (
243
+ ts -> dict , & PyId___asyncio_running_event_loop__ ); // borrowed
244
+ if (rl == NULL ) {
245
+ if (PyErr_Occurred ()) {
246
+ goto error ;
247
+ }
248
+ else {
249
+ goto not_found ;
250
+ }
251
+ }
252
+
253
+ cached_running_holder = rl ; // borrowed
254
+ cached_running_holder_tsid = ts -> id ;
236
255
}
237
256
238
- assert (PyTuple_CheckExact (running_tuple ));
239
- assert (PyTuple_Size (running_tuple ) == 2 );
240
- running_loop = PyTuple_GET_ITEM (running_tuple , 0 ); // borrowed
241
- running_loop_pid = PyTuple_GET_ITEM (running_tuple , 1 ); // borrowed
257
+ assert (Py_TYPE (rl ) == & PyRunningLoopHolder_Type );
258
+ PyObject * running_loop = ((PyRunningLoopHolder * )rl )-> rl_loop ;
242
259
243
260
if (running_loop == Py_None ) {
244
261
goto not_found ;
245
262
}
246
263
247
- current_pid = _PyObject_CallNoArg (os_getpid );
248
- if (current_pid == NULL ) {
249
- goto error ;
250
- }
251
- same_pid = PyObject_RichCompareBool (current_pid , running_loop_pid , Py_EQ );
252
- Py_DECREF (current_pid );
253
- if (same_pid == -1 ) {
254
- goto error ;
264
+ #if defined(HAVE_GETPID ) && !defined(MS_WINDOWS )
265
+ /* On Windows there is no getpid, but there is also no os.fork(),
266
+ so there is no need for this check.
267
+ */
268
+ if (getpid () != ((PyRunningLoopHolder * )rl )-> rl_pid ) {
269
+ goto not_found ;
255
270
}
271
+ #endif
256
272
257
- if (same_pid ) {
258
- // current_pid == running_loop_pid
259
- goto found ;
260
- }
273
+ Py_INCREF (running_loop );
274
+ * loop = running_loop ;
275
+ return 0 ;
261
276
262
277
not_found :
263
278
* loop = NULL ;
264
279
return 0 ;
265
280
266
- found :
267
- Py_INCREF (running_loop );
268
- * loop = running_loop ;
269
- return 0 ;
270
-
271
281
error :
272
282
* loop = NULL ;
273
283
return -1 ;
@@ -277,38 +287,28 @@ get_running_loop(PyObject **loop)
277
287
static int
278
288
set_running_loop (PyObject * loop )
279
289
{
280
- PyObject * ts_dict ;
281
- PyObject * running_tuple ;
282
- PyObject * current_pid ;
290
+ cached_running_holder = NULL ;
291
+ cached_running_holder_tsid = 0 ;
283
292
284
- ts_dict = PyThreadState_GetDict (); // borrowed
293
+ PyObject * ts_dict = PyThreadState_GetDict (); // borrowed
285
294
if (ts_dict == NULL ) {
286
295
PyErr_SetString (
287
296
PyExc_RuntimeError , "thread-local storage is not available" );
288
297
return -1 ;
289
298
}
290
299
291
- current_pid = _PyObject_CallNoArg ( os_getpid );
292
- if (current_pid == NULL ) {
300
+ PyRunningLoopHolder * rl = new_running_loop_holder ( loop );
301
+ if (rl == NULL ) {
293
302
return -1 ;
294
303
}
295
304
296
- running_tuple = PyTuple_New (2 );
297
- if (running_tuple == NULL ) {
298
- Py_DECREF (current_pid );
299
- return -1 ;
300
- }
301
-
302
- Py_INCREF (loop );
303
- PyTuple_SET_ITEM (running_tuple , 0 , loop );
304
- PyTuple_SET_ITEM (running_tuple , 1 , current_pid ); // borrowed
305
-
306
305
if (_PyDict_SetItemId (
307
- ts_dict , & PyId___asyncio_running_event_loop__ , running_tuple )) {
308
- Py_DECREF (running_tuple ); // will cleanup loop & current_pid
306
+ ts_dict , & PyId___asyncio_running_event_loop__ , (PyObject * )rl ) < 0 )
307
+ {
308
+ Py_DECREF (rl ); // will cleanup loop & current_pid
309
309
return -1 ;
310
310
}
311
- Py_DECREF (running_tuple );
311
+ Py_DECREF (rl );
312
312
313
313
return 0 ;
314
314
}
@@ -3184,6 +3184,47 @@ _asyncio__leave_task_impl(PyObject *module, PyObject *loop, PyObject *task)
3184
3184
}
3185
3185
3186
3186
3187
+ /*********************** PyRunningLoopHolder ********************/
3188
+
3189
+
3190
+ static PyRunningLoopHolder *
3191
+ new_running_loop_holder (PyObject * loop )
3192
+ {
3193
+ PyRunningLoopHolder * rl = PyObject_New (
3194
+ PyRunningLoopHolder , & PyRunningLoopHolder_Type );
3195
+ if (rl == NULL ) {
3196
+ return NULL ;
3197
+ }
3198
+
3199
+ #if defined(HAVE_GETPID ) && !defined(MS_WINDOWS )
3200
+ rl -> rl_pid = getpid ();
3201
+ #endif
3202
+
3203
+ Py_INCREF (loop );
3204
+ rl -> rl_loop = loop ;
3205
+
3206
+ return rl ;
3207
+ }
3208
+
3209
+
3210
+ static void
3211
+ PyRunningLoopHolder_tp_dealloc (PyRunningLoopHolder * rl )
3212
+ {
3213
+ Py_CLEAR (rl -> rl_loop );
3214
+ PyObject_Free (rl );
3215
+ }
3216
+
3217
+
3218
+ static PyTypeObject PyRunningLoopHolder_Type = {
3219
+ PyVarObject_HEAD_INIT (NULL , 0 )
3220
+ "_RunningLoopHolder" ,
3221
+ sizeof (PyRunningLoopHolder ),
3222
+ .tp_getattro = PyObject_GenericGetAttr ,
3223
+ .tp_flags = Py_TPFLAGS_DEFAULT ,
3224
+ .tp_dealloc = (destructor )PyRunningLoopHolder_tp_dealloc ,
3225
+ };
3226
+
3227
+
3187
3228
/*********************** Module **************************/
3188
3229
3189
3230
@@ -3212,7 +3253,6 @@ module_free(void *m)
3212
3253
{
3213
3254
Py_CLEAR (asyncio_mod );
3214
3255
Py_CLEAR (inspect_isgenerator );
3215
- Py_CLEAR (os_getpid );
3216
3256
Py_CLEAR (traceback_extract_stack );
3217
3257
Py_CLEAR (asyncio_future_repr_info_func );
3218
3258
Py_CLEAR (asyncio_get_event_loop_policy );
@@ -3295,9 +3335,6 @@ module_init(void)
3295
3335
WITH_MOD ("inspect" )
3296
3336
GET_MOD_ATTR (inspect_isgenerator , "isgenerator" )
3297
3337
3298
- WITH_MOD ("os" )
3299
- GET_MOD_ATTR (os_getpid , "getpid" )
3300
-
3301
3338
WITH_MOD ("traceback" )
3302
3339
GET_MOD_ATTR (traceback_extract_stack , "extract_stack" )
3303
3340
@@ -3370,6 +3407,9 @@ PyInit__asyncio(void)
3370
3407
if (PyType_Ready (& TaskType ) < 0 ) {
3371
3408
return NULL ;
3372
3409
}
3410
+ if (PyType_Ready (& PyRunningLoopHolder_Type ) < 0 ) {
3411
+ return NULL ;
3412
+ }
3373
3413
3374
3414
PyObject * m = PyModule_Create (& _asynciomodule );
3375
3415
if (m == NULL ) {
0 commit comments