@@ -148,7 +148,6 @@ types_publish_gen_inc(void)
148148#define TYPES_PUBLISH_GEN_NONE UINT64_MAX
149149
150150// Return true if the prepared state that was snapshotted at 'gen' is stale.
151- // Must be called with the world stopped.
152151static inline bool
153152types_publish_is_stale (uint64_t gen )
154153{
@@ -1741,10 +1740,8 @@ type_set_abstractmethods(PyObject *tp, PyObject *value, void *Py_UNUSED(closure)
17411740 else
17421741 type_clear_flags (type , Py_TPFLAGS_IS_ABSTRACT );
17431742 types_start_world ();
1744- // Invalidate the version tag after the flag update, while TYPE_LOCK is
1745- // still held: no other thread can assign a new tag before we release it.
1746- // The lock may have been released while waiting for the stop-the-world,
1747- // so invalidating before the update would not be enough.
1743+ // Invalidate the version tag after update, while TYPE_LOCK is
1744+ // still held.
17481745 ASSERT_TYPE_LOCK_HELD ();
17491746 _PyType_Modified_Unlocked (type );
17501747 END_TYPE_LOCK ();
@@ -3872,12 +3869,8 @@ solid_base(PyTypeObject *type)
38723869// updates to perform but don't actually update the type structures. After we
38733870// are finished the lookups, we stop-the-world and apply all of the updates.
38743871// The apply_slot_updates() code is simple and easy to confirm that it is
3875- // safe.
3876- //
3877- // TYPE_LOCK is a critical section and so it can be released while the lookups
3878- // run (they can call Python code and block on other locks) and while waiting
3879- // to stop the world. The queue is therefore validated with the publish
3880- // generation before it is applied and rebuilt if it went stale.
3872+ // safe. We use publish_gen to determine if the queued updates have been
3873+ // potentially invalidated, we re-build it in that case.
38813874
38823875typedef struct {
38833876 PyTypeObject * type ;
@@ -3992,18 +3985,6 @@ apply_slot_updates(slot_update_t *updates)
39923985// generation is still 'gen' (the value snapshotted before the
39933986// queue was built). Returns 1 if the updates were applied and 0 if the
39943987// queue went stale and must be rebuilt.
3995- //
3996- // The queue was built while holding TYPE_LOCK (and, for type_setattro(),
3997- // the type dict mutex). Both are critical section mutexes, so they were
3998- // released whenever the lookups blocked and are released while this thread
3999- // waits to stop the world. Other threads can update type dicts, MROs and
4000- // slots in the meantime, which is what the generation check detects.
4001- //
4002- // Must be called with TYPE_LOCK held. The lock is re-acquired when the
4003- // thread re-attaches after waiting for the stop-the-world mutex, so it is
4004- // held continuously from before the world is stopped until after it is
4005- // started again. Callers rely on that to invalidate version tags after the
4006- // update, before any other thread can assign a new one.
40073988static int
40083989apply_type_slot_updates (slot_update_t * updates , uint64_t gen )
40093990{
@@ -6517,11 +6498,8 @@ _PyType_SetFlagsRecursive(PyTypeObject *self, unsigned long mask, unsigned long
65176498 types_stop_world ();
65186499 set_flags_recursive (self , mask , flags );
65196500 types_start_world ();
6520- // Invalidate the version tags after the flag update, while TYPE_LOCK is
6521- // still held: no other thread can assign a new tag before we release it.
6522- // _PyType_Modified_Unlocked() is re-entrant and cannot run with the world
6523- // stopped, and invalidating before the update would not be enough because
6524- // the lock may be released while waiting for the stop-the-world.
6501+ // Invalidate the version tags after update, while TYPE_LOCK is
6502+ // still held.
65256503 ASSERT_TYPE_LOCK_HELD ();
65266504 if (modified ) {
65276505 _PyType_Modified_Unlocked (self );
0 commit comments