Skip to content

Add python freethreading support - #307

Merged
tschoonj merged 6 commits into
masterfrom
add-python-freethreading-support
Aug 18, 2026
Merged

Add python freethreading support#307
tschoonj merged 6 commits into
masterfrom
add-python-freethreading-support

Conversation

@tschoonj

Copy link
Copy Markdown
Owner

No description provided.

tschoonj and others added 6 commits August 18, 2026 16:16
Only request the free-threading build flags when the target interpreter
is an actual free-threaded (no-GIL) build (Py_GIL_DISABLED), and only
when the tools are new enough:

- swig -nogil (swig >= 4.4.0)
- Cython freethreading_compatible=True directive (Cython >= 3.1.0)

Warn and fall back gracefully (GIL re-enabled at import) when the tools
are too old. Remove the legacy swig -py3 flag entirely, as it has been
deprecated and a no-op since swig 4.1.0.

Applied consistently across both build systems (autotools and meson).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
test-freethreading.py imports _xraylib (swig) and xraylib_np (cython)
in fresh subprocesses and inspects sys._is_gil_enabled():

- on a free-threaded (no-GIL) build the GIL starts disabled and is only
  re-enabled when a module that has NOT declared free-threading support
  is imported, so the test asserts the GIL stays disabled -> confirming
  the modules were built with -nogil / freethreading_compatible=True
- on a regular build it asserts the opposite (the GIL is active)

A subprocess per module is required because re-enabling the GIL is a
permanent, process-wide side effect that would otherwise mask later
imports. Registered in both build systems.

Also deduplicate the free-threaded detection in configure.ac into a
single guarded XRL_CHECK_PYTHON_FREETHREADED macro.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Python bindings now declare themselves free-threading (no-GIL)
compatible via Py_MOD_GIL_NOT_USED, but the SWIG-wrapped crystal
functions operate on the mutable process-global Crystal_arr, whose
accesses were previously serialized only by the GIL. Under a
free-threaded interpreter that serialization is gone, leaving a genuine
data race (e.g. concurrent Crystal_AddCrystal / Crystal_ReadFile /
Crystal_GetCrystal calls).

Serialize the shared-global paths with a minimal internal mutex:

- New non-installed header src/xraylib-aux-private.h provides an xrl_lock
  abstraction: SRWLOCK on _WIN32 (native MinGW/MSYS2, kernel32-only, no
  libwinpthread-1.dll dependency) and pthread_mutex_t elsewhere (Linux,
  macOS, Cygwin). Both are statically initializable.
- xrl_lock_acquire/xrl_lock_release wrappers in xraylib-aux.c (hidden
  visibility, not exported).
- The four crystal functions touching Crystal_arr are split into static
  *_impl bodies wrapped by thin public functions that take the lock only
  when c_array == NULL (the shared global); caller-owned arrays remain
  lock-free, preserving the documented contract and the public API.

Build wiring adds no new redistributable dependency:

- autotools: vendored m4/ax_pthread.m4; configure.ac host-gates
  AC_CHECK_DECL(AcquireSRWLockExclusive) on mingw and AX_PTHREAD
  elsewhere; PTHREAD_CFLAGS/LIBS flow into libxrl and the prdata tool.
- meson: dependency('threads') off-Windows, cc.has_function check for
  AcquireSRWLockExclusive on Windows.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a C threaded test (tests/) and a Python threading test (python/tests/)
that hammer the process-global crystal array from multiple threads,
exercising the internal lock that makes the free-threading support truthful.
Both are wired into the meson and autotools build systems.

Add a support-gated ThreadSanitizer CI job that builds the whole library
with -Db_sanitize=thread and runs the crystal tests under TSan.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@tschoonj
tschoonj merged commit 0862368 into master Aug 18, 2026
44 checks passed
@tschoonj
tschoonj deleted the add-python-freethreading-support branch August 18, 2026 15:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant