@@ -1021,7 +1021,8 @@ _PyJit_TryInitializeTracing(
10211021 _tstate -> jit_tracer_state .initial_state .jump_backward_instr = curr_instr ;
10221022
10231023 if (_PyOpcode_Caches [_PyOpcode_Deopt [close_loop_instr -> op .code ]]) {
1024- close_loop_instr [1 ].counter = trigger_backoff_counter ();
1024+ _Py_BackoffCounter zero = trigger_backoff_counter ();;
1025+ FT_ATOMIC_STORE_UINT16_RELAXED (close_loop_instr [1 ].counter .value_and_backoff , zero .value_and_backoff );
10251026 }
10261027 _Py_BloomFilter_Init (& _tstate -> jit_tracer_state .prev_state .dependencies );
10271028 return 1 ;
@@ -1694,112 +1695,65 @@ _PyJit_Tracer_InvalidateDependency(PyThreadState *tstate, void *obj)
16941695 _tstate -> jit_tracer_state .prev_state .dependencies_still_valid = false;
16951696 }
16961697}
1698+ void
1699+ _Py_Executors_ClearExecutorList (PyObject * invalidate , int is_invalidation )
1700+ {
1701+ if (invalidate == NULL ) {
1702+ return ;
1703+ }
1704+ for (Py_ssize_t i = 0 ; i < PyList_GET_SIZE (invalidate ); i ++ ) {
1705+ PyObject * exec = PyList_GET_ITEM (invalidate , i );
1706+ executor_clear (exec );
1707+ if (is_invalidation ) {
1708+ OPT_STAT_INC (executors_invalidated );
1709+ }
1710+ }
1711+ Py_DECREF (invalidate );
1712+ }
16971713
16981714/* Invalidate all executors that depend on `obj`
16991715 * May cause other executors to be invalidated as well
1716+ * To avoid deadlocks due to stop the world, we just invalidate the executors but leave them to be freed
1717+ * on their own later.
17001718 */
17011719void
1702- _Py_Executors_InvalidateDependencyWorldStopped (PyInterpreterState * interp , void * obj , int is_invalidation )
1720+ _Py_Executors_InvalidateDependency (PyInterpreterState * interp , void * obj , int is_invalidation )
17031721{
17041722 _PyBloomFilter obj_filter ;
17051723 _Py_BloomFilter_Init (& obj_filter );
17061724 _Py_BloomFilter_Add (& obj_filter , obj );
17071725 /* Walk the list of executors */
1708- /* TO DO -- Use a tree to avoid traversing as many objects */
1709- PyObject * invalidate = PyList_New (0 );
1710- if (invalidate == NULL ) {
1711- goto error ;
1712- }
17131726 /* Clearing an executor can deallocate others, so we need to make a list of
17141727 * executors to invalidate first */
17151728 _Py_FOR_EACH_TSTATE_UNLOCKED (interp , p ) {
17161729 _PyJit_Tracer_InvalidateDependency (p , obj );
17171730 for (_PyExecutorObject * exec = ((_PyThreadStateImpl * )p )-> jit_executor_state .executor_list_head ; exec != NULL ;) {
17181731 assert (exec -> vm_data .valid );
17191732 if (bloom_filter_may_contain (& exec -> vm_data .bloom , & obj_filter )) {
1720- if (PyList_Append (invalidate , (PyObject * )exec ) < 0 ) {
1721- PyErr_Clear ();
1722- Py_DECREF (invalidate );
1723- _PyEval_StartTheWorldAll (& _PyRuntime );
1724- return ;
1725- }
1733+ exec -> vm_data .valid = 0 ;
17261734 }
17271735 _PyExecutorObject * next = exec -> vm_data .links .next ;
17281736 exec = next ;
17291737 }
17301738 }
1731- for (Py_ssize_t i = 0 ; i < PyList_GET_SIZE (invalidate ); i ++ ) {
1732- PyObject * exec = PyList_GET_ITEM (invalidate , i );
1733- executor_clear (exec );
1734- if (is_invalidation ) {
1735- OPT_STAT_INC (executors_invalidated );
1736- }
1737- }
1738- Py_DECREF (invalidate );
1739- return ;
1740- error :
1741- PyErr_Clear ();
1742- Py_XDECREF (invalidate );
1743- // If we're truly out of memory, DO NOT wipe everything as the world is stopped, and we might deadlock.
1744- }
1745-
1746- void
1747- _Py_Executors_InvalidateDependency (PyInterpreterState * interp , void * obj , int is_invalidation )
1748- {
1749- _PyEval_StopTheWorld (interp );
1750- _Py_Executors_InvalidateDependencyWorldStopped (interp , obj , is_invalidation );
1751- _PyEval_StartTheWorld (interp );
17521739}
17531740
1741+ // To avoid deadlocks due to stop the world, we just invalidate the executors but leave them to be freed
1742+ // on their own later.
17541743void
1755- _Py_Executors_InvalidateAllWorldStopped (PyInterpreterState * interp , int is_invalidation )
1744+ _Py_Executors_InvalidateAll (PyInterpreterState * interp , int is_invalidation )
17561745{
1757- PyObject * invalidate = PyList_New (0 );
1758- if (invalidate == NULL ) {
1759- PyErr_Clear ();
1760- return ;
1761- }
17621746 /* Clearing an executor can deallocate others, so we need to make a list of
17631747 * executors to invalidate first */
17641748 _Py_FOR_EACH_TSTATE_UNLOCKED (interp , p ) {
17651749 for (_PyExecutorObject * exec = ((_PyThreadStateImpl * )p )-> jit_executor_state .executor_list_head ; exec != NULL ;) {
17661750 assert (exec -> vm_data .valid );
17671751 assert (exec -> tstate == p );
1752+ exec -> vm_data .valid = 0 ;
17681753 _PyExecutorObject * next = exec -> vm_data .links .next ;
1769- if (PyList_Append (invalidate , (PyObject * )exec ) < 0 ) {
1770- PyErr_Clear ();
1771- Py_DECREF (invalidate );
1772- _PyEval_StartTheWorldAll (& _PyRuntime );
1773- return ;
1774- }
17751754 exec = next ;
17761755 }
17771756 }
1778- Py_ssize_t list_len = PyList_GET_SIZE (invalidate );
1779- for (Py_ssize_t i = 0 ; i < list_len ; i ++ ) {
1780- _PyExecutorObject * executor = (_PyExecutorObject * )PyList_GET_ITEM (invalidate , i );
1781-
1782- assert (executor -> vm_data .valid == 1 );
1783- if (executor -> vm_data .code ) {
1784- // Clear the entire code object so its co_executors array be freed:
1785- _PyCode_Clear_Executors (executor -> vm_data .code );
1786- }
1787- executor_clear ((PyObject * )executor );
1788- if (is_invalidation ) {
1789- OPT_STAT_INC (executors_invalidated );
1790- }
1791- }
1792- Py_DECREF (invalidate );
1793- // If we're truly out of memory, DO NOT wipe everything as the world is stopped, and we might deadlock.
1794- }
1795-
1796- /* Invalidate all executors */
1797- void
1798- _Py_Executors_InvalidateAll (PyInterpreterState * interp , int is_invalidation )
1799- {
1800- _PyEval_StopTheWorld (interp );
1801- _Py_Executors_InvalidateAllWorldStopped (interp , is_invalidation );
1802- _PyEval_StartTheWorld (interp );
18031757}
18041758
18051759
0 commit comments