@@ -156,7 +156,7 @@ types_mutex_unlock(void)
156
156
}
157
157
158
158
#define ASSERT_TYPE_LOCK_HELD () \
159
- {if (! types_world_is_stopped()) assert( types_mutex_is_owned());}
159
+ assert( types_world_is_stopped() || types_mutex_is_owned())
160
160
161
161
#else
162
162
@@ -432,7 +432,8 @@ type_set_flags(PyTypeObject *tp, unsigned long flags)
432
432
if (tp -> tp_flags & Py_TPFLAGS_READY ) {
433
433
// It's possible the type object has been exposed to other threads
434
434
// if it's been marked ready. In that case, the type lock should be
435
- // held when flags are modified.
435
+ // held when flags are modified (or the stop-the-world mechanism should
436
+ // be active).
436
437
ASSERT_TYPE_LOCK_HELD ();
437
438
}
438
439
ASSERT_NEW_OR_STOPPED (tp );
@@ -1923,18 +1924,9 @@ type_set_bases(PyObject *tp, PyObject *new_bases, void *Py_UNUSED(closure))
1923
1924
{
1924
1925
PyTypeObject * type = PyTypeObject_CAST (tp );
1925
1926
int res ;
1926
- bool need_stop = !types_world_is_stopped ();
1927
- if (need_stop ) {
1928
- // This function can be re-entered. We want to avoid trying to stop
1929
- // the world a second time if that happens. Example call chain:
1930
- // mro_invoke() -> call_unbound_noarg() -> type_setattro() ->
1931
- // type_set_bases()
1932
- types_stop_world ();
1933
- }
1927
+ types_stop_world ();
1934
1928
res = type_set_bases_unlocked (type , new_bases );
1935
- if (need_stop ) {
1936
- types_start_world ();
1937
- }
1929
+ types_start_world ();
1938
1930
return res ;
1939
1931
}
1940
1932
@@ -3487,16 +3479,48 @@ mro_invoke(PyTypeObject *type)
3487
3479
const int custom = !Py_IS_TYPE (type , & PyType_Type );
3488
3480
3489
3481
if (custom ) {
3482
+ // Custom mro() method on metaclass. This is potentially
3483
+ // re-entrant. We are called either from type_ready(), in which case
3484
+ // the TYPE_LOCK mutex is held, or from type_set_bases() (assignment to
3485
+ // __bases__), in which case we need to stop-the-world in order to avoid
3486
+ // data races.
3487
+ bool stopped = types_world_is_stopped ();
3488
+ if (stopped ) {
3489
+ // Called for type_set_bases(), re-assigment of __bases__
3490
+ types_start_world ();
3491
+ }
3492
+ else {
3493
+ // Called from type_ready()
3494
+ ASSERT_TYPE_LOCK_HELD ();
3495
+ types_mutex_unlock ();
3496
+ }
3490
3497
mro_result = call_method_noarg ((PyObject * )type , & _Py_ID (mro ));
3498
+ if (mro_result != NULL ) {
3499
+ new_mro = PySequence_Tuple (mro_result );
3500
+ Py_DECREF (mro_result );
3501
+ }
3502
+ else {
3503
+ new_mro = NULL ;
3504
+ }
3505
+ if (stopped ) {
3506
+ types_stop_world ();
3507
+ }
3508
+ else {
3509
+ types_mutex_lock ();
3510
+ }
3491
3511
}
3492
3512
else {
3513
+ // In this case, the mro() method on the type object is being used and
3514
+ // we know that these calls are not re-entrant.
3493
3515
mro_result = mro_implementation (type );
3516
+ if (mro_result != NULL ) {
3517
+ new_mro = PySequence_Tuple (mro_result );
3518
+ Py_DECREF (mro_result );
3519
+ }
3520
+ else {
3521
+ new_mro = NULL ;
3522
+ }
3494
3523
}
3495
- if (mro_result == NULL )
3496
- return NULL ;
3497
-
3498
- new_mro = PySequence_Tuple (mro_result );
3499
- Py_DECREF (mro_result );
3500
3524
if (new_mro == NULL ) {
3501
3525
return NULL ;
3502
3526
}
@@ -3549,9 +3573,7 @@ mro_internal_unlocked(PyTypeObject *type, int initial, PyObject **p_old_mro)
3549
3573
Don't let old_mro be GC'ed and its address be reused for
3550
3574
another object, like (suddenly!) a new tp_mro. */
3551
3575
old_mro = Py_XNewRef (lookup_tp_mro (type ));
3552
- types_mutex_unlock ();
3553
3576
new_mro = mro_invoke (type ); /* might cause reentrance */
3554
- types_mutex_lock ();
3555
3577
reent = (lookup_tp_mro (type ) != old_mro );
3556
3578
Py_XDECREF (old_mro );
3557
3579
if (new_mro == NULL ) {
@@ -5523,7 +5545,6 @@ PyType_GetModuleByDef(PyTypeObject *type, PyModuleDef *def)
5523
5545
}
5524
5546
5525
5547
PyObject * res = NULL ;
5526
- types_mutex_lock ();
5527
5548
5528
5549
PyObject * mro = lookup_tp_mro (type );
5529
5550
// The type must be ready
@@ -5550,7 +5571,6 @@ PyType_GetModuleByDef(PyTypeObject *type, PyModuleDef *def)
5550
5571
break ;
5551
5572
}
5552
5573
}
5553
- types_mutex_unlock ();
5554
5574
5555
5575
if (res == NULL ) {
5556
5576
PyErr_Format (
@@ -5806,12 +5826,14 @@ _PyTypes_AfterFork(void)
5806
5826
#endif
5807
5827
}
5808
5828
5809
- // Try to assign a new type version tag, return it if
5810
- // successful. Return 0 if no version was assigned.
5829
+ // Try to assign a new type version tag, return it if successful. Return 0
5830
+ // if no version was assigned. Note that this function can be called while
5831
+ // holding the TYPE_LOCK mutex or when the stop-the-world mechanism is active.
5811
5832
static unsigned int
5812
5833
type_assign_version_lock_held (PyTypeObject * type )
5813
5834
{
5814
5835
ASSERT_TYPE_LOCK_HELD ();
5836
+ assert (!types_world_is_stopped ());
5815
5837
PyInterpreterState * interp = _PyInterpreterState_GET ();
5816
5838
if (assign_version_tag (interp , type )) {
5817
5839
return type -> tp_version_tag ;
@@ -5916,6 +5938,8 @@ type_lookup_ex(PyTypeObject *type, PyObject *name, _PyStackRef *out,
5916
5938
return assigned_version ;
5917
5939
}
5918
5940
5941
+ // Note that this function can be called while holding the TYPE_LOCK mutex or
5942
+ // when the stop-the-world mechanism is active.
5919
5943
static unsigned int
5920
5944
type_lookup_lock_held (PyTypeObject * type , PyObject * name , _PyStackRef * out )
5921
5945
{
@@ -6019,15 +6043,13 @@ _PyType_CacheGetItemForSpecialization(PyHeapTypeObject *ht, PyObject *descriptor
6019
6043
void
6020
6044
_PyType_SetFlags (PyTypeObject * self , unsigned long mask , unsigned long flags )
6021
6045
{
6022
- types_mutex_lock ();
6023
6046
unsigned long new_flags = (self -> tp_flags & ~mask ) | flags ;
6024
6047
if (new_flags != self -> tp_flags ) {
6025
6048
types_stop_world ();
6026
6049
// can't use new_flags here since they could be out-of-date
6027
6050
self -> tp_flags = (self -> tp_flags & ~mask ) | flags ;
6028
6051
types_start_world ();
6029
6052
}
6030
- types_mutex_unlock ();
6031
6053
}
6032
6054
6033
6055
int
@@ -6190,18 +6212,6 @@ _Py_type_getattro(PyObject *tp, PyObject *name)
6190
6212
return _Py_type_getattro_impl (type , name , NULL );
6191
6213
}
6192
6214
6193
- #ifdef Py_GIL_DISABLED
6194
- static int
6195
- update_slot_world_stopped (PyTypeObject * type , PyObject * name )
6196
- {
6197
- int ret ;
6198
- types_stop_world ();
6199
- ret = update_slot (type , name );
6200
- types_start_world ();
6201
- return ret ;
6202
- }
6203
- #endif
6204
-
6205
6215
// Called by type_setattro(). Updates both the type dict and
6206
6216
// any type slots that correspond to the modified entry.
6207
6217
static int
@@ -6241,7 +6251,11 @@ type_update_dict(PyTypeObject *type, PyDictObject *dict, PyObject *name,
6241
6251
#ifdef Py_GIL_DISABLED
6242
6252
if (is_dunder_name (name ) && has_slotdef (name )) {
6243
6253
// update is potentially changing one or more slots
6244
- return update_slot_world_stopped (type , name );
6254
+ int ret ;
6255
+ types_stop_world ();
6256
+ ret = update_slot (type , name );
6257
+ types_start_world ();
6258
+ return ret ;
6245
6259
}
6246
6260
#else
6247
6261
if (is_dunder_name (name )) {
@@ -6319,7 +6333,7 @@ type_setattro(PyObject *self, PyObject *name, PyObject *value)
6319
6333
}
6320
6334
}
6321
6335
6322
- // FIXME: can this deadlock? if so, how to avoid
6336
+ // FIXME: I'm not totaly sure this is safe from a deadlock. If so, how to avoid?
6323
6337
types_mutex_lock ();
6324
6338
Py_BEGIN_CRITICAL_SECTION (dict );
6325
6339
res = type_update_dict (type , (PyDictObject * )dict , name , value , & old_value );
@@ -7254,14 +7268,10 @@ object_set_class(PyObject *self, PyObject *value, void *closure)
7254
7268
return -1 ;
7255
7269
}
7256
7270
7257
- #ifdef Py_GIL_DISABLED
7258
7271
types_stop_world ();
7259
- #endif
7260
7272
PyTypeObject * oldto = Py_TYPE (self );
7261
7273
int res = object_set_class_world_stopped (self , newto );
7262
- #ifdef Py_GIL_DISABLED
7263
7274
types_start_world ();
7264
- #endif
7265
7275
if (res == 0 ) {
7266
7276
if (oldto -> tp_flags & Py_TPFLAGS_HEAPTYPE ) {
7267
7277
Py_DECREF (oldto );
@@ -10736,9 +10746,7 @@ releasebuffer_maybe_call_super(PyObject *self, Py_buffer *buffer)
10736
10746
{
10737
10747
releasebufferproc base_releasebuffer ;
10738
10748
10739
- types_mutex_lock ();
10740
10749
base_releasebuffer = releasebuffer_maybe_call_super_unlocked (self , buffer );
10741
- types_mutex_unlock ();
10742
10750
10743
10751
if (base_releasebuffer != NULL ) {
10744
10752
base_releasebuffer (self , buffer );
@@ -11806,14 +11814,8 @@ _super_lookup_descr(PyTypeObject *su_type, PyTypeObject *su_obj_type, PyObject *
11806
11814
PyObject * mro , * res ;
11807
11815
Py_ssize_t i , n ;
11808
11816
11809
- types_mutex_lock ();
11810
11817
mro = lookup_tp_mro (su_obj_type );
11811
- /* keep a strong reference to mro because su_obj_type->tp_mro can be
11812
- replaced during PyDict_GetItemRef(dict, name, &res) and because
11813
- another thread can modify it after we end the critical section
11814
- below */
11815
11818
Py_XINCREF (mro );
11816
- types_mutex_unlock ();
11817
11819
11818
11820
if (mro == NULL )
11819
11821
return NULL ;
0 commit comments