Skip to content

Commit 6db4542

Browse files
committed
Improve comments.
1 parent ca00e74 commit 6db4542

1 file changed

Lines changed: 20 additions & 6 deletions

File tree

Objects/typeobject.c

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,23 +60,32 @@ class object "PyObject *" "&PyBaseObject_Type"
6060

6161
#ifdef Py_GIL_DISABLED
6262

63-
// There's a global lock for mutation of types. This avoids having to take
63+
// There's a global lock for types that ensures that the tp_version_tag is
64+
// correctly updated if the type is modified. This avoids having to take
6465
// additional locks while doing various subclass processing which may result
6566
// in odd behaviors w.r.t. running with the GIL as the outer type lock could
6667
// be released and reacquired during a subclass update if there's contention
6768
// on the subclass lock.
6869
//
69-
// While modification of type slots and type flags is protected by the
70-
// global types lock. However, the slots and flags are read non-atomically
71-
// without holding the type lock. So, we need to stop-the-world while
72-
// modifying these, in order to avoid data races.
70+
// Note that this lock does not protect when updating type slots or the
71+
// tp_flags member. Instead, we either ensure those updates are done before
72+
// the type has been revealed to other threads or we only do those updates
73+
// while the stop-the-world mechanism is active. The slots and flags are read
74+
// in many places without holding a lock and without atomics.
75+
//
76+
// Since TYPE_LOCK is used as regular mutex, we must take special care about
77+
// potential re-entrant code paths. We use TYPE_LOCK_TID in debug builds to
78+
// ensure that we are not trying to re-acquire the mutex when it is already
79+
// held by the current thread. There are a couple cases when we release the
80+
// mutex, when we call functions that might re-enter.
7381
#define TYPE_LOCK &PyInterpreterState_Get()->types.mutex
7482

75-
// Used to check for correct use of the TYPE_LOCK mutex. It is a simple
83+
// Used to check for correct use of the TYPE_LOCK mutex. It is a regular
7684
// mutex and does not support re-entrancy. If we already hold the lock and
7785
// try to acquire it again with the same thread, it is a bug on the code.
7886
#define TYPE_LOCK_TID &PyInterpreterState_Get()->types.mutex_tid
7987

88+
// Return true if the world is currently stopped.
8089
static bool
8190
types_world_is_stopped(void)
8291
{
@@ -109,6 +118,7 @@ types_start_world(void)
109118
}
110119

111120
#ifdef Py_DEBUG
121+
// Return true if the TYPE_LOCK mutex is held by the current thread.
112122
static bool
113123
types_mutex_is_owned(void)
114124
{
@@ -117,6 +127,7 @@ types_mutex_is_owned(void)
117127
}
118128
#endif
119129

130+
// Set the TID of the thread currently holding TYPE_LOCK.
120131
static void
121132
types_mutex_set_owned(PyThread_ident_t tid)
122133
{
@@ -3401,6 +3412,7 @@ mro_invoke(PyTypeObject *type)
34013412
if (mro_result == NULL)
34023413
return NULL;
34033414

3415+
// FIXME: possible re-entrancy, drop lock?
34043416
new_mro = PySequence_Tuple(mro_result);
34053417
Py_DECREF(mro_result);
34063418
if (new_mro == NULL) {
@@ -4576,6 +4588,7 @@ type_new_impl(type_new_ctx *ctx)
45764588
}
45774589

45784590
assert(_PyType_CheckConsistency(type));
4591+
// After this point, other threads can potentally use this type.
45794592
type->tp_flags |= Py_TPFLAGS_EXPOSED;
45804593

45814594
return (PyObject *)type;
@@ -5290,6 +5303,7 @@ PyType_FromMetaclass(
52905303
}
52915304

52925305
assert(_PyType_CheckConsistency(type));
5306+
// After this point, other threads can potentally use this type.
52935307
type->tp_flags |= Py_TPFLAGS_EXPOSED;
52945308

52955309
finally:

0 commit comments

Comments
 (0)