Skip to content

Commit 4db3e36

Browse files
add comment
1 parent ee47298 commit 4db3e36

1 file changed

Lines changed: 21 additions & 2 deletions

File tree

Modules/_ctypes/ctypes.h

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,7 @@ typedef struct CFieldObject {
376376

377377
typedef struct {
378378
#ifdef Py_GIL_DISABLED
379-
PyMutex mutex;
379+
PyMutex mutex; /* critical section mutex */
380380
#endif
381381
int initialized;
382382
Py_ssize_t size; /* number of bytes */
@@ -405,6 +405,23 @@ typedef struct {
405405
/* Py_ssize_t *suboffsets; */ /* unused in ctypes */
406406
} StgInfo;
407407

408+
/*
409+
In free-threading, concurrent mutations to StgInfo is not thread safe.
410+
Therefore to make it thread safe, when modifying StgInfo, `STGINFO_LOCK` and
411+
`STGINFO_UNLOCK` macros are used to acquire critical section of the StgInfo.
412+
The critical section is write only and is acquired when modifying the
413+
StgInfo fields and while setting the `dict_final` bit. Once the `dict_final`
414+
is set, StgInfo is treated as read only and no further modifications are
415+
allowed. This allows to avoid acquiring the critical section for most
416+
read operations when `dict_final` is set (general case).
417+
418+
It is important to set all the fields before setting the `dict_final` bit
419+
in functions like `PyCStructUnionType_update_stginfo` because the store of
420+
`dict_final` uses sequential consistency memory ordering. This ensures that
421+
all the other fields are visible to other threads before the `dict_final` bit
422+
is set thus allowing for lock free reads when `dict_final` is set.
423+
424+
*/
408425

409426
#define STGINFO_LOCK(stginfo) Py_BEGIN_CRITICAL_SECTION_MUT(&(stginfo)->mutex)
410427
#define STGINFO_LOCK2(stginfo1, stginfo2) Py_BEGIN_CRITICAL_SECTION2_MUT(&(stginfo1)->mutex, &(stginfo2)->mutex)
@@ -424,10 +441,12 @@ stginfo_set_dict_final_lock_held(StgInfo *info)
424441
FT_ATOMIC_STORE_INT(info->dict_final, 1);
425442
}
426443

444+
445+
// Set the `dict_final` bit in StgInfo. It checks if the bit is already set
446+
// and in that avoids acquiring the critical section (general case).
427447
static inline void
428448
stginfo_set_dict_final(StgInfo *info)
429449
{
430-
// avoid acquiring the lock if final is already set
431450
if (stginfo_get_dict_final(info) == 1) {
432451
return;
433452
}

0 commit comments

Comments
 (0)