Skip to content

Python 3.14 free-threaded support #2720

@greateggsgreg

Description

@greateggsgreg

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
Chained ClassDerived.Finalize IL Nested Python-derived classes with __namespace__ chained through emitted Finalize methods, queuing the same __pyobj__ twice → PyObject_GC_Del on freed memory Skip the base-Finalize chain when the base is itself pythonnet-emitted (IPythonDerivedType)

See PR #2721 for the per-file detail.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions