- 
          
 - 
                Notifications
    
You must be signed in to change notification settings  - Fork 33.3k
 
gh-120198: Stop the world when setting __class__ on free-threaded build #120672
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
2e5667e
              b482f87
              d2a7095
              8a562ce
              a88d238
              8a25bfb
              13486cb
              a409ab2
              File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| 
          
            
          
           | 
    @@ -6626,6 +6626,12 @@ object_set_class(PyObject *self, PyObject *value, void *closure) | |
| return -1; | ||
| } | ||
| 
     | 
||
| #ifdef Py_GIL_DISABLED | ||
| PyInterpreterState *interp = _PyInterpreterState_GET(); | ||
| // The real Py_TYPE(self) (`oldto`) may have changed from | ||
| // underneath us in another thread, so we stop the world. | ||
| _PyEval_StopTheWorld(interp); | ||
                
      
                  Fidget-Spinner marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| #endif | ||
| PyTypeObject *oldto = Py_TYPE(self); | ||
| 
     | 
||
| /* In versions of CPython prior to 3.5, the code in | ||
| 
          
            
          
           | 
    @@ -6684,56 +6690,59 @@ object_set_class(PyObject *self, PyObject *value, void *closure) | |
| PyErr_Format(PyExc_TypeError, | ||
| "__class__ assignment only supported for mutable types " | ||
| "or ModuleType subclasses"); | ||
| return -1; | ||
| goto err; | ||
| } | ||
| 
     | 
||
| if (compatible_for_assignment(oldto, newto, "__class__")) { | ||
| /* Changing the class will change the implicit dict keys, | ||
| * so we must materialize the dictionary first. */ | ||
| if (oldto->tp_flags & Py_TPFLAGS_INLINE_VALUES) { | ||
| PyDictObject *dict = _PyObject_MaterializeManagedDict(self); | ||
| PyDictObject *dict = _PyObject_GetManagedDict(self); | ||
| if (dict == NULL) { | ||
| return -1; | ||
| dict = _PyObject_materialize_managed_dict_lock_held(self); | ||
| if (dict == NULL) { | ||
| goto err; | ||
| } | ||
| } | ||
| 
     | 
||
| bool error = false; | ||
| 
     | 
||
| Py_BEGIN_CRITICAL_SECTION2(self, dict); | ||
| 
     | 
||
| // If we raced after materialization and replaced the dict | ||
| // then the materialized dict should no longer have the | ||
| // inline values in which case detach is a nop. | ||
| // Note: we don't need to lock here because the world should be stopped. | ||
                
      
                  Fidget-Spinner marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| 
     | 
||
| assert(_PyObject_GetManagedDict(self) == dict || | ||
| dict->ma_values != _PyObject_InlineValues(self)); | ||
                
      
                  Fidget-Spinner marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| 
     | 
||
| if (_PyDict_DetachFromObject(dict, self) < 0) { | ||
| error = true; | ||
| goto err; | ||
| } | ||
| 
     | 
||
| Py_END_CRITICAL_SECTION2(); | ||
| if (error) { | ||
| return -1; | ||
| } | ||
| } | ||
| if (newto->tp_flags & Py_TPFLAGS_HEAPTYPE) { | ||
| Py_INCREF(newto); | ||
| } | ||
| Py_BEGIN_CRITICAL_SECTION(self); | ||
| // The real Py_TYPE(self) (`oldto`) may have changed from | ||
| // underneath us in another thread, so we re-fetch it here. | ||
| oldto = Py_TYPE(self); | ||
| 
     | 
||
| #ifdef Py_GIL_DISABLED | ||
| _PyEval_StartTheWorld(interp); | ||
                
      
                  Fidget-Spinner marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| #endif | ||
| Py_SET_TYPE(self, newto); | ||
| Py_END_CRITICAL_SECTION(); | ||
| 
     | 
||
| if (oldto->tp_flags & Py_TPFLAGS_HEAPTYPE) { | ||
| Py_DECREF(oldto); | ||
                
      
                  Fidget-Spinner marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| } | ||
| 
     | 
||
| RARE_EVENT_INC(set_class); | ||
| 
     | 
||
| return 0; | ||
| } | ||
| else { | ||
| return -1; | ||
| goto err; | ||
| } | ||
| err: | ||
                
       | 
||
| #ifdef Py_GIL_DISABLED | ||
| _PyEval_StartTheWorld(interp); | ||
| #endif | ||
| return -1; | ||
| } | ||
| 
     | 
||
| static PyGetSetDef object_getsets[] = { | ||
| 
          
            
          
           | 
    ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's name this like the other functions:
_PyObject_MaterializeManagedDict_LockHeldand move the definition up next to_PyObject_MaterializeManagedDict.