Fix race condition: serialize Pango/Cairo calls for thread safety#125
Fix race condition: serialize Pango/Cairo calls for thread safety#125SoldierSacha wants to merge 2 commits intoManimCommunity:v0from
Conversation
The registered_fonts global set is read during text2svg rendering and written during font registration, with no synchronization. Concurrent calls can cause RuntimeError from set mutation during iteration. Additionally, Pango's default font map is shared global state accessed by all rendering calls. Wrap text2svg, MarkupUtils.text2svg, register_font, unregister_font, fc_register_font, fc_unregister_font, and list_fonts with a single module-level threading.Lock to serialize access to these shared resources. https://claude.ai/code/session_012X3a138VZEKecNvQuoyFmm
…d decorator Replace the star-import-then-shadow pattern with explicit imports for all public names, and a reusable _synchronized decorator that wraps functions with the thread-safety lock. This eliminates the try/except/else gymnastics and makes the wrapping declarative and readable. https://claude.ai/code/session_012X3a138VZEKecNvQuoyFmm
naveen521kk
left a comment
There was a problem hiding this comment.
Thanks for your contribution. I took a look around this, and it looks like a workaround solution instead of fixing the actual issue. Instead, we have to change the Cython implementation to implement locks, if required, accordingly.
Do you have a Minimal Reproducible Example where we can reproduce this issue? We need it to add it to the test suite.
No problem! I guess you could consider it a workaround solution in that sense, since the problem does technically come from the Cython. Unfortunately I don't have a minimal example. If that's necessary, I guess you can close the PR. I just wanted to bring this to attention. |
Summary
threading.Lockto serialize all calls into Pango/Cairoand font registration, fixing a race condition caused by concurrent access to
global state (the default
PangoCairoFontMap, Fontconfig config, and theshared
registered_fontsset).from .cmanimpango import *, etc.) with explicitimports and a
_synchronizeddecorator, making the public API surface clearand the thread-safety wrapping declarative.
Problem
Pango and Cairo use process-global state internally (the default font map,
Fontconfig configuration). When multiple threads call
text2svg,MarkupUtils.text2svg, or font registration functions concurrently, thisleads to corrupted state, segfaults, or incorrect rendering — particularly
in tools like Manim that render scenes in parallel.
Approach
A single
threading.Lock(_pango_lock) in__init__.pywraps everypublic function that touches Pango/Cairo or the font registry. A small
_synchronizeddecorator (usingfunctools.wraps) keeps the code DRYand preserves function metadata (
__name__,__doc__, etc.).Only
manimpango/__init__.pyis changed — no modifications to the Cythonlayer or
register_font.py.