Skip to main content

Module threads

Module threads 

Source
Expand description

Threading support (§57, §93, §85 Phase 1).

Thread-local state, concurrent parsing, concurrent transformation, shared immutable dictionaries, callback isolation.

§UPSTREAM-PARITY

libxml2’s threading support provides:

  • xmlInitThreads() / xmlCleanupThreads() — lifecycle
  • xmlLockLibrary() / xmlUnlockLibrary() — global lock
  • Thread-local storage for error state and parser contexts

In modern libxml2 (2.12+), threading is initialized automatically by xmlInitParser. The explicit thread functions exist for backward compatibility.

In Rust, we use standard thread-safe primitives and thread_local! for thread-local storage. The global lock is a no-op since Rust’s type system prevents data races at compile time.

§Phase 1 status

Complete — all threading support is implemented.

§Upstream contract

Mirrors upstream threads.c (SRC-LIBXML2-2.15.0-THREADS-C, parity target libxml2 2.15.3 oracle): xmlInitThreads, xmlCleanupThreads, xmlLockLibrary, xmlUnlockLibrary, xmlNewMutex/xmlFreeMutex/ xmlMutexLock/xmlMutexUnlock, xmlNewRMutex/xmlRMutexLock/ xmlRMutexUnlock, xmlNewCond/xmlCondWaitSignal, and the thread-local variants.

§Conceptual behavior

Implements the legacy explicit threading API. In modern libxml2 (2.12+) initialization is lazy — xmlInitParser calls the init path automatically, and the deprecated entry points exist for backward compatibility. Rust primitives (thread_local!, parking_lot, atomics) provide the same guarantees without upstream platform dispatch (HAVE_POSIX_THREADS / HAVE_WIN32_THREADS).

§Ownership & safety invariants

Mutex/rmutex/cond handles are heap objects owned by the caller and freed with the matching free function; thread-local error/parser state is owned per thread and never shared. Rust memory-safety guarantees replace the upstream data-race discipline — the SAFETY argument is the type system, not lock discipline.

§Historical quirks & epochs

Thread support predates the thread-local globals era: globals.c threading was integrated 2001-10-12/13 (commits b847864f, d0463560, LORE-0005). R-000138: the deprecated init/cleanup entry points are genuine no-ops in modern upstream (lazy init) and the candidate matches that; xmlCheckThreadLocalStorage always passes with Rust thread-locals.

§Deliberate oddities

The global library lock is a deliberate no-op: Rust prevents data races at compile time, and upstream xmlLockLibrary itself became vestigial after the thread-local rewrite. Deprecated entry points keep their no-op bodies to match the oracle byte-for-byte (R-000138).

§Proving courts

The globals-threading differential probe (tools/abi/globals_threading_ probe.py + courts/suites/data-abi/globals-threading-probe.c) verifies handler-slot and error-global behavior byte-identical vs the oracle; the parallel lib suite (100/100 runs clean, R-000170/R-000171) and cargo test exercise the thread-local error model.

§Tempting simplifications that would break parity

Do not replace thread-locals with globals: per-thread parser error state and the exported xmlLastError mirror (R-000170) depend on the thread-local model. Do not make the deprecated entry points do real work: upstream bodies are empty and observable behavior must match.

Functions§

cleanup_threads
Clean up threading support.
free_mutex
Free a simple mutex (upstream threads.h xmlFreeMutex).
free_rmutex
Free a recursive mutex (upstream threads.h xmlFreeRMutex).
get_thread_count
Get the number of active threads (for compatibility).
init_threads
Initialize threading support.
lock_library
Lock the library (global mutex).
mutex_lock
Lock a simple mutex (upstream threads.h xmlMutexLock).
mutex_unlock
Unlock a simple mutex (upstream threads.h xmlMutexUnlock).
new_mutex
Create a simple mutex (upstream threads.h xmlNewMutex).
new_rmutex
Create a recursive mutex (upstream threads.h xmlNewRMutex).
rmutex_lock
Lock a recursive mutex (upstream threads.h xmlRMutexLock).
rmutex_unlock
Unlock a recursive mutex (upstream threads.h xmlRMutexUnlock).
threads_initialized
Check whether threading has been initialized.
unlock_library
Unlock the library.