@@ -26,7 +26,6 @@ _Py_IDENTIFIER(_wakeup);
2626/* State of the _asyncio module */
2727static PyObject * asyncio_mod ;
2828static PyObject * inspect_isgenerator ;
29- static PyObject * os_getpid ;
3029static PyObject * traceback_extract_stack ;
3130static PyObject * asyncio_get_event_loop_policy ;
3231static PyObject * asyncio_future_repr_info_func ;
@@ -38,6 +37,9 @@ static PyObject *asyncio_InvalidStateError;
3837static PyObject * asyncio_CancelledError ;
3938static PyObject * context_kwname ;
4039
40+ static PyObject * cached_running_holder ;
41+ static volatile uint64_t cached_running_holder_tsid ;
42+
4143
4244/* WeakSet containing all alive tasks. */
4345static PyObject * all_tasks ;
@@ -95,9 +97,18 @@ typedef struct {
9597 TaskObj * ww_task ;
9698} TaskWakeupMethWrapper ;
9799
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+
98108
99109static PyTypeObject FutureType ;
100110static PyTypeObject TaskType ;
111+ static PyTypeObject PyRunningLoopHolder_Type ;
101112
102113
103114#define Future_CheckExact (obj ) (Py_TYPE(obj) == &FutureType)
@@ -116,9 +127,11 @@ class _asyncio.Future "FutureObj *" "&Future_Type"
116127
117128
118129/* Get FutureIter from Future */
119- static PyObject * future_new_iter (PyObject * );
130+ static PyObject * future_new_iter (PyObject * );
120131static inline int future_call_schedule_callbacks (FutureObj * );
121132
133+ static PyRunningLoopHolder * new_running_loop_holder (PyObject * );
134+
122135
123136static int
124137_is_coroutine (PyObject * coro )
@@ -214,60 +227,57 @@ get_future_loop(PyObject *fut)
214227static int
215228get_running_loop (PyObject * * loop )
216229{
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 ;
223231
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
229236 }
237+ else {
238+ if (ts -> dict == NULL ) {
239+ goto not_found ;
240+ }
230241
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 ;
236255 }
237256
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 ;
242259
243260 if (running_loop == Py_None ) {
244261 goto not_found ;
245262 }
246263
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 ;
255270 }
271+ #endif
256272
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 ;
261276
262277not_found :
263278 * loop = NULL ;
264279 return 0 ;
265280
266- found :
267- Py_INCREF (running_loop );
268- * loop = running_loop ;
269- return 0 ;
270-
271281error :
272282 * loop = NULL ;
273283 return -1 ;
@@ -277,38 +287,28 @@ get_running_loop(PyObject **loop)
277287static int
278288set_running_loop (PyObject * loop )
279289{
280- PyObject * ts_dict ;
281- PyObject * running_tuple ;
282- PyObject * current_pid ;
290+ cached_running_holder = NULL ;
291+ cached_running_holder_tsid = 0 ;
283292
284- ts_dict = PyThreadState_GetDict (); // borrowed
293+ PyObject * ts_dict = PyThreadState_GetDict (); // borrowed
285294 if (ts_dict == NULL ) {
286295 PyErr_SetString (
287296 PyExc_RuntimeError , "thread-local storage is not available" );
288297 return -1 ;
289298 }
290299
291- current_pid = _PyObject_CallNoArg ( os_getpid );
292- if (current_pid == NULL ) {
300+ PyRunningLoopHolder * rl = new_running_loop_holder ( loop );
301+ if (rl == NULL ) {
293302 return -1 ;
294303 }
295304
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-
306305 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
309309 return -1 ;
310310 }
311- Py_DECREF (running_tuple );
311+ Py_DECREF (rl );
312312
313313 return 0 ;
314314}
@@ -3184,6 +3184,47 @@ _asyncio__leave_task_impl(PyObject *module, PyObject *loop, PyObject *task)
31843184}
31853185
31863186
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+
31873228/*********************** Module **************************/
31883229
31893230
@@ -3212,7 +3253,6 @@ module_free(void *m)
32123253{
32133254 Py_CLEAR (asyncio_mod );
32143255 Py_CLEAR (inspect_isgenerator );
3215- Py_CLEAR (os_getpid );
32163256 Py_CLEAR (traceback_extract_stack );
32173257 Py_CLEAR (asyncio_future_repr_info_func );
32183258 Py_CLEAR (asyncio_get_event_loop_policy );
@@ -3295,9 +3335,6 @@ module_init(void)
32953335 WITH_MOD ("inspect" )
32963336 GET_MOD_ATTR (inspect_isgenerator , "isgenerator" )
32973337
3298- WITH_MOD ("os" )
3299- GET_MOD_ATTR (os_getpid , "getpid" )
3300-
33013338 WITH_MOD ("traceback" )
33023339 GET_MOD_ATTR (traceback_extract_stack , "extract_stack" )
33033340
@@ -3370,6 +3407,9 @@ PyInit__asyncio(void)
33703407 if (PyType_Ready (& TaskType ) < 0 ) {
33713408 return NULL ;
33723409 }
3410+ if (PyType_Ready (& PyRunningLoopHolder_Type ) < 0 ) {
3411+ return NULL ;
3412+ }
33733413
33743414 PyObject * m = PyModule_Create (& _asynciomodule );
33753415 if (m == NULL ) {
0 commit comments