Tracking issue for free-threaded Python (Py_GIL_DISABLED) support. Companion to the umbrella 3.14 tracker #2610.
Why FT is different from a normal GIL build
PyObject_HEAD is 16 bytes larger; the refcount is split across ob_ref_local + ob_ref_shared and must be read via Py_REFCNT (a real exported symbol on 3.14+).
- Build detection:
sys._is_gil_enabled() (added in 3.13) returns False on FT.
- The GIL has been silently serialising every pythonnet static cache, lock-free counter, finalizer-thread interaction, and
Reflection.Emit use site. All of those need explicit synchronisation under FT.
Hazards in pythonnet (resolved by PR #2721)
| Area |
What broke |
How it was fixed |
| Refcount / ABI |
Single-offset read |
Py_REFCNT P/Invoke + ObjectHeadOffset = 16 for FT |
| Type-creation race |
Duplicate cache.Add; partial-type visibility |
Two-cache (cache + _inProgressCache) under _cacheCreateLock |
GCHandle in tp_clear/tp_dealloc |
Double-free under main-thread + finalizer-thread race |
Interlocked.Exchange on the slot |
Reflection.Emit |
Concurrent DefineType corrupts IL / throws "Duplicate type name" |
Lock both CreateDerivedType and DelegateManager.GetDispatcher |
| Static collections |
Plain Dictionary/HashSet/List thread-safety issues |
ConcurrentDictionary where possible; Interlocked/Volatile for single-cell state; locks for nested mutation and ordered list semantics |
Finalizer-thread / Py_Finalize interaction |
Stale ob_ref_local reads after teardown crash the process |
Runtime._Py_IsFinalizing() guards on all decref-from-finalizer paths |
See PR #2721 for the per-file detail.
References
Tracking issue for free-threaded Python (
Py_GIL_DISABLED) support. Companion to the umbrella 3.14 tracker #2610.Why FT is different from a normal GIL build
PyObject_HEADis 16 bytes larger; the refcount is split acrossob_ref_local+ob_ref_sharedand must be read viaPy_REFCNT(a real exported symbol on 3.14+).sys._is_gil_enabled()(added in 3.13) returnsFalseon FT.Reflection.Emituse site. All of those need explicit synchronisation under FT.Hazards in pythonnet (resolved by PR #2721)
Py_REFCNTP/Invoke +ObjectHeadOffset = 16for FTcache.Add; partial-type visibilitycache+_inProgressCache) under_cacheCreateLocktp_clear/tp_deallocInterlocked.Exchangeon the slotReflection.EmitDefineTypecorrupts IL / throws "Duplicate type name"CreateDerivedTypeandDelegateManager.GetDispatcherDictionary/HashSet/Listthread-safety issuesConcurrentDictionarywhere possible;Interlocked/Volatilefor single-cell state; locks for nested mutation and ordered list semanticsPy_Finalizeinteractionob_ref_localreads after teardown crash the processRuntime._Py_IsFinalizing()guards on all decref-from-finalizer pathsSee PR #2721 for the per-file detail.
References